import numpy as np
import pandas as pd
data = np.random.randint(low=1, high=10, size=(3, 5))
df = pd.DataFrame(data, columns=list("abcde"), index=list("ABC"))
df
a | b | c | d | e | |
---|---|---|---|---|---|
A | 2 | 7 | 2 | 9 | 5 |
B | 5 | 7 | 9 | 2 | 5 |
C | 4 | 4 | 3 | 2 | 8 |
Guangyao Zhao
Dec 2, 2022
import numpy as np
import pandas as pd
data = np.random.randint(low=1, high=10, size=(3, 5))
df = pd.DataFrame(data, columns=list("abcde"), index=list("ABC"))
df
a | b | c | d | e | |
---|---|---|---|---|---|
A | 2 | 7 | 2 | 9 | 5 |
B | 5 | 7 | 9 | 2 | 5 |
C | 4 | 4 | 3 | 2 | 8 |
set_index()
设置新的索引:
将原数据的某一列设置为新的索引,可以看到被设置为索引后原列消失:
b | c | d | e | |
---|---|---|---|---|
a | ||||
2 | 7 | 2 | 9 | 5 |
5 | 7 | 9 | 2 | 5 |
4 | 4 | 3 | 2 | 8 |
可以替换后保持原列:
可以保持原列且保持原索引,此处可以看出 drop
针对的是列,append
针对的是索引:
reset_index()
重置索引:
如果想替换掉原索引:
rename()
用 mapper
修改索引名或列名:
数据类型
排序:
函数:
此处主要介绍数据框的基础信息和统计信息,验证下读取数据是否和原数据信息大概一致,比如行名,列名,数据量是否缺失,各列的类型数据等等。
data = np.random.randint(low=1, high=10, size=(6, 5))
df = pd.DataFrame(data, columns=list("abcde"), index=list("ABCDEF"))
df
a | b | c | d | e | |
---|---|---|---|---|---|
A | 4 | 3 | 7 | 7 | 1 |
B | 6 | 2 | 9 | 4 | 4 |
C | 5 | 7 | 8 | 9 | 6 |
D | 7 | 1 | 2 | 3 | 4 |
E | 2 | 5 | 4 | 9 | 8 |
F | 9 | 2 | 7 | 2 | 4 |
head(), tail(), sample()
头部数据:
尾部数据:
随机采样:
shape
和 numpy 一样,pandas 也内置了数据形状查找功能:
info()
Pandas 有一个很好用的功能,直接可以显示出数据框的常规信息:
<class 'pandas.core.frame.DataFrame'>
Index: 6 entries, A to F
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 a 6 non-null int64
1 b 6 non-null int64
2 c 6 non-null int64
3 d 6 non-null int64
4 e 6 non-null int64
dtypes: int64(5)
memory usage: 288.0+ bytes
describe()
Pandas 可以直接批量给出数据框的统计信息:
a | b | c | d | e | |
---|---|---|---|---|---|
count | 6.000000 | 6.000000 | 6.000000 | 6.000000 | 6.000000 |
mean | 5.500000 | 3.333333 | 6.166667 | 5.666667 | 4.500000 |
std | 2.428992 | 2.250926 | 2.639444 | 3.076795 | 2.345208 |
min | 2.000000 | 1.000000 | 2.000000 | 2.000000 | 1.000000 |
25% | 4.250000 | 2.000000 | 4.750000 | 3.250000 | 4.000000 |
50% | 5.500000 | 2.500000 | 7.000000 | 5.500000 | 4.000000 |
75% | 6.750000 | 4.500000 | 7.750000 | 8.500000 | 5.500000 |
max | 9.000000 | 7.000000 | 9.000000 | 9.000000 | 8.000000 |
corr()
在此强调一点,pandas 的重点在于列,也就是所谓的特征列,所以默认的情况和 numpy 强调数据的整体不同,pandas 更注重的是每列的情况,默认自然而然也就是以列为整体
a | b | c | d | e | |
---|---|---|---|---|---|
a | 1.000000 | -0.585279 | 0.109184 | -0.883119 | -0.368648 |
b | -0.585279 | 1.000000 | 0.258085 | 0.885598 | 0.568301 |
c | 0.109184 | 0.258085 | 1.000000 | 0.082091 | -0.242325 |
d | -0.883119 | 0.885598 | 0.082091 | 1.000000 | 0.443476 |
e | -0.368648 | 0.568301 | -0.242325 | 0.443476 | 1.000000 |
同理还有 df.max(), df.min(), df.std(), df.corr()
等常用统计函数。
idxmax()
还有一些更有用的信息,比如每列的最大值索引:
nunique()
还有个很好用的功能,查询每列的集合:
all(), any()
判断列数据是否都大于某个值,计算分为两部:
True, False
True
,则结果为 True
a | b | c | d | e | |
---|---|---|---|---|---|
A | True | False | True | True | False |
B | True | False | True | True | True |
C | True | True | True | True | True |
D | True | False | False | False | True |
E | False | True | True | True | True |
F | True | False | True | False | True |
any()
用法和 all()
一致,只是前者是只要有一个结果为 True
则为 True
。
round()
data = np.random.randn(6, 5)
df = pd.DataFrame(data, columns=list("abcde"), index=list("ABCDEF"))
df
a | b | c | d | e | |
---|---|---|---|---|---|
A | 1.403203 | -0.843999 | -0.725820 | 1.035822 | -0.205633 |
B | -0.852134 | 0.563946 | 1.369935 | 0.321659 | 1.487192 |
C | 0.473048 | 0.927135 | 1.017546 | 0.057711 | -1.454395 |
D | 0.443630 | -1.281710 | 1.386452 | -0.459800 | 0.497552 |
E | -0.366010 | -1.663643 | -1.238280 | -1.286800 | -0.898251 |
F | -0.171442 | 1.410416 | -0.834794 | -1.046389 | -1.085320 |
将整个数据框四舍五入到小数点两位:
a | b | c | d | e | |
---|---|---|---|---|---|
A | 1.40 | -0.84 | -0.73 | 1.04 | -0.21 |
B | -0.85 | 0.56 | 1.37 | 0.32 | 1.49 |
C | 0.47 | 0.93 | 1.02 | 0.06 | -1.45 |
D | 0.44 | -1.28 | 1.39 | -0.46 | 0.50 |
E | -0.37 | -1.66 | -1.24 | -1.29 | -0.90 |
F | -0.17 | 1.41 | -0.83 | -1.05 | -1.09 |
指定特定列的有效数字:
value_counts()
该函数是 Series 的专有函数,在统计某列的分布时很好用
diff()
Pandas 提供了增量计算,比如上一个数据和本数据的差值,当然了,也可以计算下一个和本数据的差值:
a | b | c | d | e | |
---|---|---|---|---|---|
A | NaN | NaN | NaN | NaN | NaN |
B | -2.255337 | 1.407945 | 2.095755 | -0.714162 | 1.692826 |
C | 1.325182 | 0.363189 | -0.352389 | -0.263948 | -2.941588 |
D | -0.029418 | -2.208844 | 0.368906 | -0.517511 | 1.951947 |
E | -0.809640 | -0.381933 | -2.624732 | -0.827001 | -1.395803 |
F | 0.194568 | 3.074059 | 0.403485 | 0.240411 | -0.187069 |
a | b | c | d | e | |
---|---|---|---|---|---|
A | 2.255337 | -1.407945 | -2.095755 | 0.714162 | -1.692826 |
B | -1.325182 | -0.363189 | 0.352389 | 0.263948 | 2.941588 |
C | 0.029418 | 2.208844 | -0.368906 | 0.517511 | -1.951947 |
D | 0.809640 | 0.381933 | 2.624732 | 0.827001 | 1.395803 |
E | -0.194568 | -3.074059 | -0.403485 | -0.240411 | 0.187069 |
F | NaN | NaN | NaN | NaN | NaN |
shift()
对数据进行移位,不做任何计算。注意,索引和列保持不变:
a | b | c | d | e | |
---|---|---|---|---|---|
A | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
B | 1.403203 | -0.843999 | -0.725820 | 1.035822 | -0.205633 |
C | -0.852134 | 0.563946 | 1.369935 | 0.321659 | 1.487192 |
D | 0.473048 | 0.927135 | 1.017546 | 0.057711 | -1.454395 |
E | 0.443630 | -1.281710 | 1.386452 | -0.459800 | 0.497552 |
F | -0.366010 | -1.663643 | -1.238280 | -1.286800 | -0.898251 |
rank()
该函数是将数据的数据大小序列替换到原数据中:
a | b | c | d | e | |
---|---|---|---|---|---|
A | 5.0 | 1.0 | 2.0 | 4.0 | 3.0 |
B | 1.0 | 3.0 | 4.0 | 2.0 | 5.0 |
C | 3.0 | 4.0 | 5.0 | 2.0 | 1.0 |
D | 3.0 | 1.0 | 5.0 | 2.0 | 4.0 |
E | 5.0 | 1.0 | 3.0 | 2.0 | 4.0 |
F | 4.0 | 5.0 | 3.0 | 2.0 | 1.0 |
以上是绝对顺序,也可以转化为分位数:
数据选择是 pandas 最重要的一部分,方式分为三种:
df.a
:取出列,推荐df['a'], df[0]
:推荐前者,不太推荐后者df.loc['a', 'c'], df.loc[0, 10]
: 轴标签,推荐df.iloc[0, 5], df.iloc[0: 3, 1: 2]
:轴索引,推荐.loc()
和 .iloc()
只相差个 i
,那是 index
的意思。
从上面可以看出,在 pands 中同样支持切片。
loc()
某列的所有行:
A 1.403203
B -0.852134
C 0.473048
D 0.443630
E -0.366010
F -0.171442
Name: a, dtype: float64
切片:
a | b | c | |
---|---|---|---|
A | 1.403203 | -0.843999 | -0.725820 |
B | -0.852134 | 0.563946 | 1.369935 |
C | 0.473048 | 0.927135 | 1.017546 |
D | 0.443630 | -1.281710 | 1.386452 |
某几列的某些行:
iloc()
第 1 列的所有行:
A 1.403203
B -0.852134
C 0.473048
D 0.443630
E -0.366010
F -0.171442
Name: a, dtype: float64
第 1 和 4 列的所有行:
a | d | |
---|---|---|
A | 1.403203 | 1.035822 |
B | -0.852134 | 0.321659 |
C | 0.473048 | 0.057711 |
D | 0.443630 | -0.459800 |
E | -0.366010 | -1.286800 |
F | -0.171442 | -1.046389 |
第 1 行的第 2 列;第 3 行的第 3 列:
数据查询是 pandas 的最重要的功能之一,Sec. 6 的内容远远达不到要求,所以就需要更复杂的逻辑条件。和 Sec. 6 不同,此处支持以下两种形式:
df[]
:不筛选列,只筛选行时使用df.loc()
:同时筛选行和列时使用()
。True
,反之标记为 False
。df[]
这种形式的筛选只能筛选出特定行。
a | b | c | d | e | |
---|---|---|---|---|---|
A | 1.403203 | -0.843999 | -0.725820 | 1.035822 | -0.205633 |
D | 0.443630 | -1.281710 | 1.386452 | -0.459800 | 0.497552 |
a | b | c | d | e | |
---|---|---|---|---|---|
B | -0.852134 | 0.563946 | 1.369935 | 0.321659 | 1.487192 |
E | -0.366010 | -1.663643 | -1.238280 | -1.286800 | -0.898251 |
F | -0.171442 | 1.410416 | -0.834794 | -1.046389 | -1.085320 |
df.loc()
这种形式不仅能筛选出特定行,还能指定特定列。
b | c | d | e | |
---|---|---|---|---|
A | -0.843999 | -0.725820 | 1.035822 | -0.205633 |
C | 0.927135 | 1.017546 | 0.057711 | -1.454395 |
D | -1.281710 | 1.386452 | -0.459800 | 0.497552 |
a | b | |
---|---|---|
A | 1.403203 | -0.843999 |
C | 0.473048 | 0.927135 |
D | 0.443630 | -1.281710 |
E | -0.366010 | -1.663643 |
query()
当逻辑非常复杂的时候,利用以上方法将会显得特别杂乱,pandas 也提供了类似 SQL 的查询语句,针对数据框的列进行查询,筛选出符合条件的行。非常推荐这种写法。
filter()
此函数支持对行名和列名进行筛选,支持模糊匹配,正则表达式:
a | b | |
---|---|---|
A | 1.403203 | -0.843999 |
B | -0.852134 | 0.563946 |
C | 0.473048 | 0.927135 |
D | 0.443630 | -1.281710 |
E | -0.366010 | -1.663643 |
F | -0.171442 | 1.410416 |
a | |
---|---|
A | 1.403203 |
B | -0.852134 |
C | 0.473048 |
D | 0.443630 |
E | -0.366010 |
F | -0.171442 |
a | |
---|---|
A | 1.403203 |
B | -0.852134 |
C | 0.473048 |
D | 0.443630 |
E | -0.366010 |
F | -0.171442 |
filter()
函数仅支持对索引和列名称进行过滤,不针对具体数据。
convert_dtypes()
在开始数据分析之前,要清楚地了解数据类型,一般也无非是整型,浮点型,字符串,时间这几种。
a | b | c | d | e | |
---|---|---|---|---|---|
A | 1.403203 | -0.843999 | -0.72582 | 1.035822 | -0.205633 |
B | -0.852134 | 0.563946 | 1.369935 | 0.321659 | 1.487192 |
C | 0.473048 | 0.927135 | 1.017546 | 0.057711 | -1.454395 |
D | 0.44363 | -1.28171 | 1.386452 | -0.4598 | 0.497552 |
E | -0.36601 | -1.663643 | -1.23828 | -1.2868 | -0.898251 |
F | -0.171442 | 1.410416 | -0.834794 | -1.046389 | -1.08532 |
to_xxx(), astype()
强制转换数据类型
df.iloc[0, 0] = np.nan # 将该元素设置为异常值
pd.to_numeric(df["a"], errors="coerce").fillna(0) # 如果存在异常值,将使用 NaN填充,然后将其转换为 0
A 0.000000
B -0.852134
C 0.473048
D 0.443630
E -0.366010
F -0.171442
Name: a, dtype: float64
a float32
b float32
c float32
d float32
e float32
dtype: object
a | b | c | d | e | |
---|---|---|---|---|---|
A | -1 | 0 | 0 | 1 | 0 |
B | 0 | 0 | 1 | 0 | 1 |
C | 0 | 0 | 1 | 0 | -1 |
D | 0 | -1 | 1 | 0 | 0 |
E | 0 | -1 | -1 | -1 | 0 |
F | 0 | 1 | 0 | -1 | -1 |
sort_index()
按行索引:
a | b | c | d | e | |
---|---|---|---|---|---|
F | 0.0 | 1 | 0 | -1 | -1 |
E | 0.0 | -1 | -1 | -1 | 0 |
D | 0.0 | -1 | 1 | 0 | 0 |
C | 0.0 | 0 | 1 | 0 | -1 |
B | 0.0 | 0 | 1 | 0 | 1 |
A | -1.0 | 0 | 0 | 1 | 0 |
按列索引:
e | d | c | b | a | |
---|---|---|---|---|---|
A | 0 | 1 | 0 | 0 | -1.0 |
B | 1 | 0 | 1 | 0 | 0.0 |
C | -1 | 0 | 1 | 0 | 0.0 |
D | 0 | 0 | 1 | -1 | 0.0 |
E | 0 | -1 | -1 | -1 | 0.0 |
F | -1 | -1 | 0 | 1 | 0.0 |
将索引设置为 0-(n-1)
,类似于 df.reset_index(drop = True)
:
a | b | c | d | e | |
---|---|---|---|---|---|
A | -1.0 | 0 | 0 | 1 | 0 |
B | 0.0 | 0 | 1 | 0 | 1 |
C | 0.0 | 0 | 1 | 0 | -1 |
D | 0.0 | -1 | 1 | 0 | 0 |
E | 0.0 | -1 | -1 | -1 | 0 |
F | 0.0 | 1 | 0 | -1 | -1 |
此处需要注意,当操作对象是索引和列而不是具体数据内容时,两者均可称之为索引,即行索引和列索引。但需要注意的是对列索引排序没有什么实际意义。
sort_values()
a | b | c | d | e | |
---|---|---|---|---|---|
0 | -1.0 | 0 | 0 | 1 | 0 |
1 | 0.0 | 0 | 1 | 0 | 1 |
2 | 0.0 | 0 | 1 | 0 | -1 |
3 | 0.0 | -1 | 1 | 0 | 0 |
4 | 0.0 | -1 | -1 | -1 | 0 |
5 | 0.0 | 1 | 0 | -1 | -1 |
为什么要有 ignore_index
选项?因为根据值排序以后,索引的顺序会显得很凌乱,如果不使用索引的信息时可以添加此选项初始化索引值。
也可多列混合排序:
a | b | c | d | e | |
---|---|---|---|---|---|
A | -1.0 | 0 | 0 | 1 | 0 |
D | 0.0 | -1 | 1 | 0 | 0 |
E | 0.0 | -1 | -1 | -1 | 0 |
B | 0.0 | 0 | 1 | 0 | 1 |
C | 0.0 | 0 | 1 | 0 | -1 |
F | 0.0 | 1 | 0 | -1 | -1 |
更进一步,按照索引和某列混合排序,比如班级里要按成绩和人名排名,其中人名是索引:
where()
满足条件的维持原值不变,不满足的赋予新的值:
mask()
该函数和 where()
相反,满足条件的赋予新值,不满足的维持不变:
原则上将,无论 numpy 还是 pandas 都是矢量化运算,但难免也要用到迭代处理。
常规方法:
A -1.0 0
B 0.0 0
C 0.0 0
D 0.0 -1
E 0.0 -1
F 0.0 1
df.iterrows()
生成一个可迭代对象,将数据框的行作为组成的 Series 数据对进行迭代。
df.itertuples()
封装程度更高,会将列名返回:
函数的目的就是为了重复利用代码,同时让整个代码结构显得更加清晰。在此主要函数有以下几种:
apply()
:应用在行或者列中,可以传递多参数。推荐map()
:应用在列中的每个元素,只能传递一个参数。推荐applymap()
:应用在整个数据框中,只能传递一个参数。推荐pipe()
:应用在整个数据框中,不太推荐还是那句话,在 pandas 中数据处理主要针对的是列,行处理使用频率不高。
apply()
可以针对某列:
也可以针对所有列:
a | b | c | d | e | |
---|---|---|---|---|---|
A | -2.0 | 0 | 0 | 2 | 0 |
B | 0.0 | 0 | 2 | 0 | 2 |
C | 0.0 | 0 | 2 | 0 | -2 |
D | 0.0 | -2 | 2 | 0 | 0 |
E | 0.0 | -2 | -2 | -2 | 0 |
F | 0.0 | 2 | 0 | -2 | -2 |
自定义函数:
# 去掉最高和最低,然后求平均值,最后添加一个 bias 项
def my_means(s, bias):
max_min_ser = pd.Series([-s.max(), -s.min()])
tmp = s.append(max_min_ser).sum() # 去掉最大值和最小值
res = tmp / (s.count() - 2)
return res + bias
df.apply(my_means, args=[0.01], axis=0)
a 0.01
b -0.24
c 0.51
d -0.24
e -0.24
dtype: float64
筛选出数型列进行运算:
map()
和 apply()
不同,map()
只能针对某列数据进行某种操作,不可以一次性对全体列,另外 map()
的局限性在于只能传递入一个参数:
applymap()
和之前的不同,此函数可以做到针对每个元素进行操作: