Skip to content

Pandas_Dataframe

一、DataFrame简介

相比Series,由多个Series组成的DataFrame,才是我们分析数据是最常打交道的数据结构。

DataFrame看起来像是一个表格,它的不同列可以是不同数据类型,而不是像NumPy二维数组那样,要求数据类型全部保持一致。

相比起Series,DataFrame每个值不止有索引,也有列名。换个角度来看,DataFrame就像是由Series组成的字典,每个Series对应一个键名,也就是列名。

二、创建DataFrame

创建DataFrame时,会自动进行索引对齐

(一)参数传入一个字典,值是Series

既然DataFrame可以看成由Series组成的字典,那么第一个创建方法就是,参数传入一个字典。键是各个Series所对应的列名。

创建好后,Jupyter Notebook会输出一个,排版好看的DataFrame表格。索引就对应了Series的索引,而列名对应我们传入的键。

参数传入一个字典,值是Series

python
import pandas as pd
s_id = pd.Series(["01", "02", "03", "04", "05"])
s_class = pd.Series(["二班", "一班", "二班", "三班", "一班"])
s_grade = pd.Series([92, 67, 70, 88, 76])

df1 = pd.DataFrame({"学号": s_id, "班级": s_class, "成绩": s_grade})
df1

运行结果

学号班级成绩
001二班92
102一班67
203二班70
304三班88
405一班76

(二)参数传入一个字典,值是列表

python
l_id = ["01", "02", "03", "04", "05"]
l_class = ["二班", "一班", "二班", "三班", "一班"]
l_grade = [92, 67, 70, 88, 76]

df2 = pd.DataFrame({"学号": s_id, "班级": s_class, "成绩": s_grade})
df2

运行结果

学号班级成绩
001二班92
102一班67
203二班70
304三班88
405一班76

Dataframe默认的索引和Series一样,都是从0开始依次递增的整数,来表示位置。但如果传入的Series有标签索引的话,DataFrame的索引也会变成相应的标签。

python
s_id = pd.Series(["01", "02", "03", "04", "05"], index=["小明", "小红", "小杰", "小丽", "小华"])
s_class = pd.Series(["二班", "一班", "二班", "三班", "一班"], index=["小明", "小红", "小杰", "小丽", "小华"])
s_grade = pd.Series([92, 67, 70, 88, 76],
                    index=["小明", "小红", "小杰", "小丽", "小华"])

df3 = pd.DataFrame({"学号": s_id, "班级": s_class, "成绩": s_grade})
df3

运行结果

学号班级成绩
小明01二班92
小红02一班67
小杰03二班70
小丽04三班88
小华05一班76

(三)参数传入一个嵌套字典

参数传入一个嵌套字典,可以一次性创建出既有标签索引,也有列名的DataFrame

最外层的键仍然对应各个列名,而值则对应每列的Series;里层字典的键对应Series的标签索引

python
df4 = pd.DataFrame({"学号": {"小明": "01", "小红": "02", "小杰": "03", "小丽": "04", "小华": "05"}, 
                    "班级": {"小明": "二班", "小红": "一班", "小杰": "二班", "小丽": "三班", "小华": "一班"}, 
                    "成绩": {"小明": 92, "小红": 67, "小杰": 70, "小丽": 88, "小华": 76}})
df4

运行结果

学号班级成绩
小明01二班92
小红02一班67
小杰03二班70
小丽04三班88
小华05一班76

三、DataFrame的常用属性

(一)index属性与columns属性

要获得DataFrame的索引,可以用index属性;要获取所有列名,可以用columns属性。

返回的索引和列名的数据类型,都是pandas库的Index类

python
df4.index

Index(['小明', '小红', '小杰', '小丽', '小华'], dtype='object')

df4.columns

Index(['学号', '班级', '成绩'], dtype='object')

(二)values属性

要获取所有的值,可以用values属性

返回的类型是NumPy数组,那所有针对NumPy数组的操作,都可以用在values属性上了

python
df4.values

array([['01', '二班', 92],
       ['02', '一班', 67],
       ['03', '二班', 70],
       ['04', '三班', 88],
       ['05', '一班', 76]], dtype=object)

(三)T属性

对DataFrame进行转置,可以用T属性,大写的T。

返回的结果会把行和列进行转置。

python
df4.T

运行结果

小明小红小杰小丽小华
学号0102030405
班级二班一班二班三班一班
成绩9267708876

获取转置后的属性

python
df5 = df4.T
print(df5.index)
print(df5.columns)
print(df5.values)

运行结果

python
Index(['学号', '班级', '成绩'], dtype='object')
Index(['小明', '小红', '小杰', '小丽', '小华'], dtype='object')
[['01' '02' '03' '04' '05']
 ['二班' '一班' '二班' '三班' '一班']
 [92 67 70 88 76]]

转置后,索引、列名、值都相应发生了变化

四、从DataFrame中提取数据

(一)提取DataFrame的列

1、提取某个列

1)在DataFrame后面跟上方括号,里面放上列名,就能把列名对应的列提取出来。

列的类型是Series,索引对应DataFrame原本的索引。

这就跟我们在Python字典后面跟上方括号,里面放上键名,就能把键对应的值提取出来是类似的

python
df4['成绩']

小明    92
小红    67
小杰    70
小丽    88
小华    76
Name: 成绩, dtype: int64
python
df4['班级']

小明    二班
小红    一班
小杰    二班
小丽    三班
小华    一班
Name: 班级, dtype: object

2)也可以通过".列名" ,来获取对应的列,因为每列Series其实也是DataFrame的属性

如果列名里面有空格或特殊符号的话,就不能通过属性名来获取了,只能通过方括号

Pandas不允许通过属性来添加/更新列

python
df4.成绩

小明    92
小红    67
小杰    70
小丽    88
小华    76
Name: 成绩, dtype: int64
python
df4.班级

小明    二班
小红    一班
小杰    二班
小丽    三班
小华    一班
Name: 班级, dtype: object

2、提取任意多列

可以在方括号里放入列表,再在列表里面传入多个列名。

这样做返回的就不是Series,而是DataFrame了

python
df4[["成绩", "班级"]]

运行结果

成绩班级
小明92二班
小红67一班
小杰70二班
小丽88三班
小华76一班

(二)提取DataFrame的行

提取列用列名,提取行就应该用索引

1、提取某个行

每行数据是以Series类型进行返回的

1)loc 按照标签索引提取行

2)iloc 按照位置索引提取行

python
df4.loc["小丽"]

学号    04
班级    三班
成绩    88
Name: 小丽, dtype: object
python
df4.iloc[3]

学号    04
班级    三班
成绩    88
Name: 小丽, dtype: object

2、提取部分行

与Series切片类似,给loc标签索引范围,或者给iloc位置索引范围,可以获得多行数据

标签索引做切片是包含结束值的

python
df4.loc["小红": "小丽"]

运行结果

学号班级成绩
小红02一班67
小杰03二班70
小丽04三班88
plain
 df4.iloc[1: 3]

运行结果

学号班级成绩
小红02一班67
小杰03二班70

3、提取任意多行

可以给loc或iloc后面的方括号里,放入一个列表,里面是想提取出的行的标签或位置索引。与之前提取任意列类似。

python
df4.loc[["小丽", "小红"]]

运行结果

学号班级成绩
小丽04三班88
小红02一班67
python
df4.iloc[[3, 1]]

运行结果

学号班级成绩
小丽04三班88
小红02一班67

(三)提取DataFrame的值

1、提取某个DataFrame的元素

可以在loc或iloc后面的方括号里,放上2个参数,第一个表示行,第二个表示列,就能提取出表格某个位置上的值

python
 df4.loc["小杰", "学号"]

'03'

df4.iloc[2, 0]

'03'

2、提取部分DataFrame

提取部分表格数据类似,只需要在loc或iloc后面的方括号里放上2个参数,第一个表示行的切片,第二个表示列的切片,就可以把表格的一部分给切出来

标签索引做切片会包含结束值

python
df4.loc["小红": "小丽", "学号": "成绩"]

运行结果

学号班级成绩
小红02一班67
小杰03二班70
小丽04三班88
python
df4.iloc[1: 3, 0: 2]

运行结果

学号班级
小红02一班
小杰03二班

3、提取部分列,同时保留所有行;提取部分行,同时保留所有列

一个省事的方法是,省略希望保留所有的切片里冒号前后的值,直接放上一个冒号,这能默认表示全部范围的索引

python
df4.loc[:, "班级": "成绩"]

运行结果

班级成绩
小明二班92
小红一班67
小杰二班70
小丽三班88
小华一班76
python
df4.iloc[0: 3, :]

运行结果

学号班级成绩
小明01二班92
小红02一班67
小杰03二班70

4、提取不相邻的行或列

通过往loc或iloc后面的方括号里放入列表,通过标签或位置指明提取哪些

python
df4.loc[["小红", "小丽"], "学号": "班级"]

运行结果

学号班级
小红02一班
小丽04三班
python
df4.iloc[[1, 3], 0: 2]

运行结果

学号班级
小红02一班
小丽04三班

五、根据条件筛选DataFrame中的行

(一)根据条件筛选行,相比于根据条件筛选列来说,是更加常见和合理的。

因为一般每一行代表一个实例,比如一个城市、一个学生,而每一列代表数据实例的属性,比如说城市的人口、学生的身高。那我们筛选符合条件的行,就相当于从已有数据里,提取符合条件的实例,比如人口在1000万以上的城市,身高在1.6米以上的学生。

(二)语法

和NumPy的数组以及Pandas的Series是很类似的,在DataFrame后面跟一个方括号,里面放上针对列的条件。列的条件包括:数据类型是Series的列和条件。返回列的两种方法:通过"["列名"]",或者通过".属性名",都可以应用在列的条件中。

(三)原理

DataFrame的列是Series类型,而Series和条件结合起来,会返回一个布尔值组成的Series,它的长度和DataFrame的行数相对应。DataFrame会用布尔值的Series进行索引,保留True所对应的索引的行。

python
df4['成绩'] > 80

小明     True
小红    False
小杰    False
小丽     True
小华    False
Name: 成绩, dtype: bool
python
df4[df4["成绩"] > 80]

运行结果

学号班级成绩
小明01二班92
小丽04三班88
python
df4[df4.成绩 > 80]

运行结果

学号班级成绩
小明01二班92
小丽04三班88

(四)结合逻辑运算

条件也可以结合逻辑运算,因为DataFrame有不同列,所以不同条件里,可以根据不同列的变量进行筛选。

python
df4[(df4.成绩 > 80) & (df4["班级"] == "三班")]

运行结果

学号班级成绩
小丽04三班88

六、head方法和tail方法

基本上,对DataFrame的操作方法,都是默认不改变原始DataFrame的,而是返回一个新的DataFrame

要操作生效的话,要么就得进行重新赋值,要么指定可选参数inplace=True

(一)head方法

1、DataFrame.head(num)会返回给我们DataFrame前num行的内容,num是可选参数,默认是前5行内容。

2、用处:当我们和实际数据打交道的时候,可能动辄几千、几万甚至几十万数据,这种时候,这个方法就很实用了。可以看一眼开头几行,快速了解数据包含的信息,以及各列里面变量的特点。

python
df4.head()

运行结果

学号班级成绩
小明01二班92
小红02一班67
小杰03二班70
小丽04三班88
小华05一班76

增加指定行数

python
df4.head(2)

运行结果

学号班级成绩
小明01二班92
小红02一班67

(二)tail方法

DataFrame.tail(num)会返回给我们DataFrame后num行的内容,num是可选参数,默认是后5行内容

python
df4.tail(2)

运行结果

学号班级成绩
小丽04三班88
小华05一班76

(三)sample方法

DataFrame.sample(num)会返回给我们DataFrame随机num行的内容,num是可选参数,默认是随机1行内容

python
df4.sample()

运行结果

学号班级成绩
小华05一班76

七、更新/增加DataFrame的一列值

更新或者增加,取决于列名是否已经存在

python
import pandas as pd
name = pd.Series(["小陈", "小李", "小王", "小张", "小赵", "小周"], index=["001", "002", "003", "004", "005", "006"])
gender = pd.Series(["女", "女", "男", "男", "女", "男"], index=["006", "005", "004", "003", "002", "001"])
height = pd.Series([172.5, 168.0, 178.2, 181.3, 161.7, 159.8], index=["001", "002", "003", "004", "005", "006"])
grade = pd.Series([89, 92, 82, 96, 93, 84], index=["001", "002", "003", "004", "005", "006"])
df1 = pd.DataFrame({"姓名": name, "性别": gender, "身高": height, "成绩": grade})
df1
姓名性别身高成绩
001小陈172.589
002小李168.092
003小王178.282
004小张181.396
005小赵161.793
006小周159.884

(一)、Series处理列值

python
dataframe['列名'] = Series

如果DataFrame有标签索引,那被赋值的Series也要有index属性,才能成功和DataFrame的索引对齐,否则所有标签无法对齐的地方,都会产生缺失值

python
df1['成绩'] = pd.Series([90, 91, 83, 95, 94, 85])
df1
姓名性别身高成绩
001小陈172.5NaN
002小李168.0NaN
003小王178.2NaN
004小张181.3NaN
005小赵161.7NaN
006小周159.8NaN
python
df1['成绩'] = pd.Series([90, 91, 83, 95, 94, 85], index=['001', '002', '003', '004', '005', '006'])
df1
姓名性别身高成绩
001小陈172.590
002小李168.091
003小王178.283
004小张181.395
005小赵161.794
006小周159.885

(二)、列表处理列值

python
dataframe['列名'] = 列表

用列表的好处是不需要指明标签,会自动按顺序对齐,列表的长度和DataFrame本身的行数温和就可以

python
df1['成绩'] = [90, 91, 83, 95, 94, 85]
df1
姓名性别身高成绩
001小陈172.590
002小李168.091
003小王178.283
004小张181.395
005小赵161.794
006小周159.885
python
# 增加DataFrame的一列值
df1["班级"] = ["一班", "三班", "二班", "三班", "一班", "二班"]
df1
姓名性别身高成绩班级
001小陈172.590一班
002小李168.091三班
003小王178.283二班
004小张181.395三班
005小赵161.794一班
006小周159.885二班

八、更新/增加DataFrame的一行值

更新或者增加,取决于列名是否已经存在

既然可以通过loc或iloc提取出一行数据,那就可以以同样的方式更新那行

(一)、Series处理行值

python
dataframe.loc/iloc['索引'] = Series

需要把Series的标签与列名进行对应,否则会产生缺失值

python
df1.loc["005"] = pd.Series(["小赵", "女", 162.7, 95, "一班"],
                           index=["姓名", "性别", "身高", 
                                  "成绩", "班级"])
df1
姓名性别身高成绩班级
001小陈172.590一班
002小李168.091三班
003小王178.283二班
004小张181.395三班
005小赵162.795一班
006小周159.885二班

(二)、列表处理行值

python
dataframe.loc/iloc['索引'] = 列表

不需要指明标签,会自动按顺序对齐

python
df1.loc["005"] = ["小赵", "女", 162.7, 95, "一班"]
df1
姓名性别身高成绩班级
001小陈172.590一班
002小李168.091三班
003小王178.283二班
004小张181.395三班
005小赵162.795一班
006小周159.885二班

添加行,只能用loc。用iloc,会报错,因为给iloc里面的位置索引得是存在的

python
# 增加DataFrame的一行值
df1.loc["007"] = ["小孙", "男", 182.7, 71, "一班"]
df1
姓名性别身高成绩班级
001小陈172.590一班
002小李168.091三班
003小王178.283二班
004小张181.395三班
005小赵162.795一班
006小周159.885二班
007小孙182.771一班

九、删除DataFrame的行或列

用drop函数

drop函数只会返回删除后的DataFrame,但不会改变原始的DataFrame。假如让原本DataFrame的行被删除,可以把drop返回的结果赋值给原本的DataFrame,来实现更新。

(一)、删除DataFrame的行

1、删除DataFrame的单行

python
dataframe.drop('标签索引')
df1.drop('003')
姓名性别身高成绩班级
001小陈172.590一班
002小李168.091三班
004小张181.395三班
005小赵162.795一班
006小周159.885二班
007小孙182.771一班

2、删除DataFrame的任意多行

python
dataframe.drop(['标签索引1', '标签索引2'...])
df1.drop(['003', '007'])
姓名性别身高成绩班级
001小陈172.590一班
002小李168.091三班
004小张181.395三班
005小赵162.795一班
006小周159.885二班

(二)、删除DataFrame的列

1、删除DataFrame的单列

python
dataframe.drop('列名', axis=1)

传入可选参数'axis=1'

因为DataFrame是二维的,可以看成是有两个轴线,axis=0表示沿着索引纵向进行操作,axis=1,表示沿着列名横向进行操作。一般针对DataFrame的方法,默认axis为0,因为沿着索引纵向进行操作的时候,数据的变量含义和类型一般是相同的,比如都是表示身高的浮点数,所以适合进行统计操作。drop,默认axis也是0,那沿着索引纵向操作,删除的就是行,当我们指明axis为1时,是沿着列名横向进行操作,所以删除的就是列。正是因为DataFrame二维的特征,针对很多操作我们都可以指明axis到底是0还是1。

python
df1.drop('身高', axis=1)
姓名性别成绩班级
001小陈90一班
002小李91三班
003小王83二班
004小张95三班
005小赵95一班
006小周85二班
007小孙71一班

2、删除DataFrame的任意多列

python
dataframe.drop(['列名1', '列名2'...], axis=1)
df1.drop(['身高', '性别'], axis=1)
姓名成绩班级
001小陈90一班
002小李91三班
003小王83二班
004小张95三班
005小赵95一班
006小周85二班
007小孙71一班

(三)、根据条件删除行或列

  1. 可以反向操作,把不符合条件的行或列筛选出来,重新赋值给原始DataFrame
python
# 删除成绩小于75的同学的档案
df1 = df1[df1.成绩 > 75]
df1
姓名性别身高成绩班级
001小陈172.590一班
002小李168.091三班
003小王178.283二班
004小张181.395三班
005小赵162.795一班
006小周159.885二班
  1. 正向操作。由于drop函数中传入'标签索引'作为参数。所以我们先根据条件筛选出要删除的行,再用.index获取作为属性的标签索引,最后作为参数放入DataFrame的drop函数中。
plain
# 删除身高大于180的同学的档案
 df1.drop(df1[df1.身高 > 180].index, inplace=True)
 df1
plain
C:\Users\stube\AppData\Local\Temp\ipykernel_26868\3609063738.py:2: SettingWithCopyWarning: 
 A value is trying to be set on a copy of a slice from a DataFrame
 
 See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
   df1.drop(df1[df1.身高 > 180].index, inplace=True)
plain
.dataframe tbody tr th {
     vertical-align: top;
 }
 
 .dataframe thead th {
     text-align: right;
 }
姓名性别身高成绩班级
001小陈172.590一班
002小李168.091三班
003小王178.283二班
005小赵162.795一班
006小周159.885二班

十、DataFrame和DataFrame之间的运算

与Series与Series之间的运算类似。

DataFrame和DataFrame之间的运算,索引和索引、列名和列名会自动对齐。

1、使用符号运算

准备df1数据

python
df1 = pd.DataFrame({"a": {"001": 0, "003": 4, "005": 8, "007": 12},
                    "b": {"001": 1, "003": 5, "005": 9, "007": 13},
                    "c": {"001": 2, "003": 6, "005": 10, "007": 14},
                    "d": {"001": 3, "003": 7, "005": 11, "007": 15}})
df1
abcd
0010123
0034567
005891011
00712131415

准备df2数据

python
df2 = pd.DataFrame({"a": [0, 3, 6],
                    "b": [1, 4, 7],
                    "c": [2, 5, 8]})
df2
abc
0012
1345
2678

相加

python
df1 + df2
abcd
001NaNNaNNaNNaN
003NaNNaNNaNNaN
005NaNNaNNaNNaN
007NaNNaNNaNNaN
0NaNNaNNaNNaN
1NaNNaNNaNNaN
2NaNNaNNaNNaN

分析:df1与df2是有重合的列名的,a, b, c这三列是可以对齐上,而d列会全是缺失值;但除了列,行也要对齐,df1的标签是001、003、005、007,而df2的标签是0、1、2,没有一个对得上。可以看到,计算结果会保留双方全部索引和列名,所以每一个计算结果都是NaN

假如一个DataFrame没有标签,另一个DataFrame有标签,两个DataFrame之间运算是会拿标签索引和位置索引对齐,不一样则会保留全部索引

python
df2 = pd.DataFrame({"a": {"001": 0, "003": 3, "006": 6},
                    "b": {"001": 1, "003": 4, "006": 7},
                    "c": {"001": 2, "003": 5, "006": 8}})
df2
abc
001012
003345
006678
python
df1 + df2
abcd
0010.02.04.0NaN
0037.09.011.0NaN
005NaNNaNNaNNaN
006NaNNaNNaNNaN
007NaNNaNNaNNaN

分析:有一部分数据对齐成功,不全是缺失值了

2、用方法而不是符号运算

如果你希望给缺失的值一个默认值的话,可以给fill_value这个参数传一个值

python
df1.add(df2, fill_value=0)
abcd
0010.02.04.03.0
0037.09.011.07.0
0058.09.010.011.0
0066.07.08.0NaN
00712.013.014.015.0

分析:索引006、列名d的值不存在,是由于这个位置的值,在两个DataFrame中都不存在。因此没有相加操作,也不存在替换。但因为结果会保留所有索引和列名,导致那个位置会有个占位的NaN值。

python
df1.sub(df2, fill_value=0)
abcd
0010.00.00.03.0
0031.01.01.07.0
0058.09.010.011.0
006-6.0-7.0-8.0NaN
00712.013.014.015.0
python
df1.mul(df2, fill_value=0)
abcd
0010.01.04.00.0
00312.020.030.00.0
0050.00.00.00.0
0060.00.00.0NaN
0070.00.00.00.0
python
df1.div(df2, fill_value=0)
abcd
001NaN1.001.0inf
0031.3333331.251.2inf
005infinfinfinf
0060.0000000.000.0NaN
007infinfinfinf

十一、DataFrame和Series之间运算

DataFrame和Series之间运算同样会自动对齐,是用Series的索引和DataFrame的列名对齐,然后把操作运用在DataFrame的每一行上,对齐不了的就是NaN。

比如:

对齐的情况

python
s1 = pd.Series([0.1, 0.2, 0.3, 0.4, 0.5], index=["a", "b", "c", "d", "e"])
s1

运行结果

python
a    0.1
b    0.2
c    0.3
d    0.4
e    0.5
dtype: float64

不对齐的情况

python
s1 * df1

运行结果

abcde
0010.00.20.61.2NaN
0030.41.01.82.8NaN
0050.81.83.04.4NaN
0071.22.64.26.0NaN

这里s1里索引a对应的值,会与df1里a列下面的所有值进行相乘;索引b对应的值,会与df1里b列下面的所有值进行相乘。

广播机制,Series和DataFrame之间的操作也是广播机制的体现,因为广播机制值得就是不同维度数据之间的运算机制。

十二、DataFrame和单个数字之间运算

python
name = pd.Series(["小陈", "小李", "小王", "小张", "小赵", "小周"], index=["001", "002", "003", "004", "005", "006"])
gender = pd.Series(["女", "女", "男", "男", "女", "男"], index=["006", "005", "004", "003", "002", "001"])
height = pd.Series([172.5, 168.0, 178.2, 181.3, 161.7], index=["001", "002", "003", "004", "005"])
students = pd.DataFrame({"姓名": name, "性别": gender, "身高": height})
students
姓名性别身高
001小陈172.5
002小李168.0
003小王178.2
004小张181.3
005小赵161.7
006小周NaN

1、运算运用到DataFrame的每一项数据上

运算会被运用到DataFrame的每一项数据上,所以要确保操作确实能被运用到里面的所有数据类型上。因为DataFrame包含多种数据类型,同一个操作放到不同类型上可能会有不同效果,也可能会报错

python
students * 5
姓名性别身高
001小陈小陈小陈小陈小陈男男男男男862.5
002小李小李小李小李小李女女女女女840.0
003小王小王小王小王小王男男男男男891.0
004小张小张小张小张小张男男男男男906.5
005小赵小赵小赵小赵小赵女女女女女808.5
006小周小周小周小周小周女女女女女NaN

2、先提取出需要的DataFrame数据,再进行操作

也可以先提取出需要的DataFrame数据,用数据类型一致的那一部分,再拿去进行操作

python
students[['姓名', '性别']] * 5
姓名性别
001小陈小陈小陈小陈小陈男男男男男
002小李小李小李小李小李女女女女女
003小王小王小王小王小王男男男男男
004小张小张小张小张小张男男男男男
005小赵小赵小赵小赵小赵女女女女女
006小周小周小周小周小周女女女女女

十三、聚合运算

(一)、统计方法

NumPy数组和Pandas的Series的统计方法,包括max, min, sum, mean,在DataFrame中也有相同名字的方法

不同之处在于,由于DataFrame是二维的,我们可以指定是沿着索引纵向操作,还是沿着列名横向操作。

python
import pandas as pd
player1 = pd.Series([8.5, 7.9, 8.2, 7.6, 8.8, 7.4], index=["001", "002", "003", "004", "005", "006"])
player2 = pd.Series([9.0, 8.3, 8.6, 7.7, 8.9, 7.8], index=["001", "002", "003", "004", "005", "006"])
player3 = pd.Series([8.7, 8.1, 8.4, 7.9, 8.6, 7.3], index=["001", "002", "003", "004", "005", "006"])
df1 = pd.DataFrame({"选手1": player1, "选手2": player2, "选手3": player3})
df1
选手1选手2选手3
0018.59.08.7
0027.98.38.1
0038.28.68.4
0047.67.77.9
0058.88.98.6
0067.47.87.3
python
df1.mean()

选手1    8.066667
选手2    8.383333
选手3    8.166667
dtype: float64

默认沿着索引纵向操作,计算各列的统计值,因此返回结果的Series索引和列名对应

python
df1.mean(axis=1)

001    8.733333
002    8.100000
003    8.400000
004    7.733333
005    8.766667
006    7.500000
dtype: float64

如果用可选参数指定axis=1的话,就变成横向操作,计算各行的统计值,因此返回结果的Series索引和DataFrame索引对应。

(二)、describe方法

与Series的describe方法类似。用在DataFrame上,能得到各列的统计信息

如果DataFrame既有数字列也有非数字列,我们不需要吧数字列提取出来再调用这个方法,describe方法会自动忽略掉所有非数字列,只计算数字列的统计信息

如果DataFrame数据类型全都都是object,那么describe方法会展现针对object类型数据的信息

python
df1["姓名"] = ["小陈", "小李", "小王", "小张", "小赵", "小周"]
df1
选手1选手2选手3姓名
0018.59.08.7小陈
0027.98.38.1小李
0038.28.68.4小王
0047.67.77.9小张
0058.88.98.6小赵
0067.47.87.3小周
python
df1.describe()
选手1选手2选手3
count6.0000006.0000006.000000
mean8.0666678.3833338.166667
std0.5354130.5492420.520256
min7.4000007.7000007.300000
25%7.6750007.9250007.950000
50%8.0500008.4500008.250000
75%8.4250008.8250008.550000
max8.8000009.0000008.700000

十四、apply方法

与Series的apply方法类似,DataFrame中也有相同名字的方法。

参数接受一个函数,调用后把DataFrame的每列或每行的Series数据,分别作为那个函数的参数,默认对列进行操作。返回的Series里的元素,就是那个函数对原始Series里各列或各行调用后的结果。

apply方法不改变原始DataFrame,而是会返回一个新的DataFrame

python
# 写出一个函数,去掉选手最高分和最低分后,求平均分
def trim_mean(data):
    data_len = len(data)
    data_sum = data.sum()
    max_num = data.max()
    min_num = data.min()
    return (data_sum - max_num - min_num) / data_len
python
df1.apply(trim_mean)

选手1    5.366667
选手2    5.600000
选手3    5.500000
dtype: float64
python
df1.apply(trim_mean, axis=1)

001    2.900000
002    2.700000
003    2.800000
004    2.566667
005    2.933333
006    2.466667
dtype: float64

十五、applymap方法

与apply方法区别在于,传给apply的函数,会运用在每列或每行上;而传给applymap的函数,会运用在每一个元素上

applymap方法不改变原始DataFrame,而是会返回一个新的DataFrame

python
df1.applymap(lambda x: x + 5)
选手1选手2选手3
00113.514.013.7
00212.913.313.1
00313.213.613.4
00412.612.712.9
00513.813.913.6
00612.412.812.3

Released under the MIT License.