在 Pandas数据结构详解 | 轻松玩转Pandas(1) 介绍了 Pandas 中常用的两种数据结构 Series 以及 DataFrame,这里来看下这些数据结构都有哪些常用的功能。
# 导入相关库
import numpy as np
import pandas as pd
当我们构建好了 Series 和 DataFrame 之后,我们会经常使用哪些功能呢?来跟我看看吧。引用上一章节中的场景,我们有一些用户的的信息,并将它们存储到了 DataFrame 中。 因为大多数情况下 DataFrame 比 Series 更为常用,所以这里以 DataFrame 举例说明,但实际上很多常用功能对于 Series 也适用。
index = pd.Index(data=["Tom", "Bob", "Mary", "James"], name="name")
data = {
"age": [18, 30, 25, 40],
"city": ["BeiJing", "ShangHai", "GuangZhou", "ShenZhen"],
"sex": ["male", "male", "female", "male"]
}
user_info = pd.DataFrame(data=data, index=index)
user_info
age city sex
name
Tom 18 Beijing male
Bob 29 Taiyuan female
Mary 32 Guangzhou female
Alen 31 Shenzhen male
user_info.info()
-----------------------------------
Index: 4 entries, Tom to James
Data columns (total 3 columns):
age 4 non-null int64
city 4 non-null object
sex 4 non-null object
dtypes: int64(1), object(2)
memory usage: 128.0+ bytes
user_info.head(2)
----------------------
age city sex
name
Tom 18 BeiJing male
Bob 30 ShangHai male
user_info.shape
--------------------
(4, 3)
--------------------
user_info.T
--------------------
name Tom Bob Mary James
age 18 30 25 40
city BeiJing ShangHai GuangZhou ShenZhen
sex male male female male
user_info.values
--------------------------------
array([[18, 'BeiJing', 'male'],
[30, 'ShangHai', 'male'],
[25, 'GuangZhou', 'female'],
[40, 'ShenZhen', 'male']], dtype=object)
有时候我们获取到数据之后,想要查看下数据的简单统计指标(最大值、最小值、平均值、中位数等),比如想要查看年龄的最大值,如何实现呢?
user_info.age.max()
------------------------
40
user_info.age.cumsum()
-----------------------------
name
Tom 18
Bob 48
Mary 73
James 113
Name: age, dtype: int64
可以看到,cumsum 最后的结果就是将上一次求和的结果与原始当前值求和作为当前值。这话听起来有点绕。举个例子,上面的 73 = 48 + 25。cumsum 也可以用来操作字符串类型的对象。
user_info.sex.cumsum()
-----------------------------
name
Tom male
Bob malemale
Mary malemalefemale
James malemalefemalemale
Name: sex, dtype: object
虽然说常见的各种统计值都有对应的方法,如果我想要得到多个指标的话,就需要调用多次方法,是不是显得有点麻烦呢?
user_info.describe()
------------------------
age
count 4.000000
mean 28.250000
std 9.251126
min 18.000000
25% 23.250000
50% 27.500000
75% 32.500000
max 40.000000
user_info.describe(include=["object"])
----------------------------------
city sex
count 4 4
unique 4 2
top ShangHai male
freq 1 3
上面的结果展示了非数字类型的列的一些统计指标:总数,去重后的个数、最常见的值、最常见的值的频数。
user_info.sex.value_counts()
-------------------------------
male 3
female 1
Name: sex, dtype: int64
如果想要获取某列最大值或最小值对应的索引,可以使用 idxmax 或 idxmin 方法完成。
user_info.age.idxmax()
-------------------------
'James'
有时候,我们会碰到这样的需求,想要将年龄进行离散化(分桶),直白来说就是将年龄分成几个区间,这里我们想要将年龄分成 3 个区间段。就可以使用 Pandas 的 cut 方法来完成。
pd.cut(user_info.age,3)
--------------------------
name
Tom (17.978, 25.333]
Bob (25.333, 32.667]
Mary (17.978, 25.333]
James (32.667, 40.0]
Name: age, dtype: category
Categories (3, interval[float64]): [(17.978, 25.333] < (25.333, 32.667] < (32.667, 40.0]]
可以看到, cut 自动生成了等距的离散区间,如果自己想定义也是没问题的。
pd.cut(user_info.age, [1, 18, 30, 50])
---------------------------------------
name
Tom (1, 18]
Bob (18, 30]
Mary (18, 30]
James (30, 50]
Name: age, dtype: category
Categories (3, interval[int64]): [(1, 18] < (18, 30] < (30, 50]]
pd.cut(user_info.age, [1, 18, 30, 50], labels=["childhood", "youth", "middle"])
------------------------------------
name
Tom childhood
Bob youth
Mary youth
James middle
Name: age, dtype: category
Categories (3, object): [childhood < youth < middle]
pd.qcut(user_info.age, 3)
-------------------------------
name
Tom (17.999, 25.0]
Bob (25.0, 30.0]
Mary (17.999, 25.0]
James (30.0, 40.0]
Name: age, dtype: category
Categories (3, interval[float64]): [(17.999, 25.0] < (25.0, 30.0] < (30.0, 40.0]]
在进行数据分析时,少不了进行数据排序。Pandas 支持两种排序方式:按轴(索引或列)排序和按实际值排序。
user_info.sort_index()
------------------------
age city sex
name
Bob 30 ShangHai male
James 40 ShenZhen male
Mary 25 GuangZhou female
Tom 18 BeiJing male
user_info.sort_index(axis=1, ascending=False)
---------------------------
sex city age
name
Tom male BeiJing 18
Bob male ShangHai 30
Mary female GuangZhou 25
James male ShenZhen 40
如果想要实现按照实际值来排序,例如想要按照年龄排序,如何实现呢?
user_info.sort_values(by="age")
----------------------------------
age city sex
name
Tom 18 BeiJing male
Mary 25 GuangZhou female
Bob 30 ShangHai male
James 40 ShenZhen male
有时候我们可能需要按照多个值来排序,例如:按照年龄和城市来一起排序,可以设置参数 by 为一个 list 即可。 注意:list 中每个元素的顺序会影响排序优先级的。
user_info.sort_values(by=["age", "city"])
-------------------------------------------
age city sex
name
Tom 18 BeiJing male
Mary 25 GuangZhou female
Bob 30 ShangHai male
James 40 ShenZhen male
user_info.age.nlargest(2)
----------------------------
name
James 40
Bob 30
Name: age, dtype: int64
虽说 Pandas 为我们提供了非常丰富的函数,有时候我们可能需要自己定制一些函数,并将它应用到 DataFrame 或 Series。常用到的函数有:map、apply、applymap。 map 是 Series 中特有的方法,通过它可以对 Series 中的每个元素实现转换。
user_info.age.map(lambda x: "yes" if x >= 30 else "no")
-------------------------------------
name
Tom no
Bob yes
Mary no
James yes
Name: age, dtype: object
city_map = {
"BeiJing": "north",
"ShangHai": "south",
"GuangZhou": "south",
"ShenZhen": "south"
}
# 传入一个 map
user_info.city.map(city_map)
-------------------------------
name
Tom north
Bob south
Mary south
James south
Name: city, dtype: object
# 对 Series 来说,apply 方法 与 map 方法区别不大。
user_info.age.apply(lambda x: "yes" if x >= 30 else "no")
---------------------------
name
Tom no
Bob yes
Mary no
James yes
Name: age, dtype: object
---------------------------
# 对 DataFrame 来说,apply 方法的作用对象是一行或一列数据(一个Series)
user_info.apply(lambda x: x.max(), axis=0)
---------------------------
age 40
city ShenZhen
sex male
dtype: object
user_info.applymap(lambda x: str(x).lower())
----------------------------------
age city sex
name
Tom 18 beijing male
Bob 30 shanghai male
Mary 25 guangzhou female
James 40 shenzhen male
user_info.rename(columns={"age": "Age", "city": "City", "sex": "Sex"})
-------------------------------
Age City Sex
name
Tom 18 BeiJing male
Bob 30 ShangHai male
Mary 25 GuangZhou female
James 40 ShenZhen male
user_info.rename(index={"Tom": "tom", "Bob": "bob"})
--------------------------------
age city sex
name
tom 18 BeiJing male
bob 30 ShangHai male
Mary 25 GuangZhou female
James 40 ShenZhen male
user_info.get_dtype_counts()
------------------------------
int64 1
object 2
dtype: int64
user_info["age"].astype(float)
------------------------------
name
Tom 18.0
Bob 30.0
Mary 25.0
James 40.0
Name: age, dtype: float64
有时候会涉及到将 object 类型转为其他类型,常见的有转为数字、日期、时间差,Pandas 中分别对应 to_numeric、to_datetime、to_timedelta 方法。
user_info["height"] = ["178", "168", "178", "180cm"]
user_info
---------------------------
age city sex height
name
Tom 18 BeiJing male 178
Bob 30 ShangHai male 168
Mary 25 GuangZhou female 178
James 40 ShenZhen male 180cm
现在将身高这一列转为数字,很明显,180cm 并非数字,为了强制转换,我们可以传入 errors 参数,这个参数的作用是当强转失败时的处理方式。 默认情况下,errors='raise',这意味着强转失败后直接抛出异常,设置 errors='coerce' 可以在强转失败时将有问题的元素赋值为 pd.NaT(对于datetime和timedelta)或 np.nan(数字)。设置 errors='ignore' 可以在强转失败时返回原有的数据。
pd.to_numeric(user_info.height,errors="coerce")
---------------------------
name
Tom 178.0
Bob 168.0
Mary 178.0
James NaN
Name: height, dtype: float64
--------------------------
pd.to_numeric(user_info.height, errors="ignore")
--------------------------
name
Tom 178
Bob 168
Mary 178
James 180cm
Name: height, dtype: object
本文作者为无邪 AI派 | 禹都一只猫整理,转载请注明。