Pandas 简明教程(二):读取文件、DataFrame常用属性/方法/条件过滤/聚合/分组
一、读取文件Pandas的主业是数据分析。因此,从外部文件读/写数据是Pandas的重要功能。Pandas提供了多种API函数用于支持多种类型数据(如CSV、Excel、SQL等)的读写,其中常用的函数如下表所示。文件类型读取函数写入函数xls/xlsxread_excelto_excelCSVread_csvto_csvSQLread_sqlto_sqlJSONread_jsonto_jsonH
一、读取文件
Pandas
的主业是数据分析。因此,从外部文件读/写数据是Pandas
的重要功能。Pandas
提供了多种API函数用于支持多种类型数据(如CSV、Excel、SQL等)的读写,其中常用的函数如下表所示。
文件类型 | 读取函数 | 写入函数 |
---|---|---|
xls/xlsx | read_excel | to_excel |
CSV | read_csv | to_csv |
SQL | read_sql | to_sql |
JSON | read_json | to_json |
HTML | read_html | to_html |
HDF5 | read_hdf | to_hdf |
pickle | read_pickle | to_pickle |
Pandas
可以将读取到的表格型数据转换为DataFrame
数据,然后通过操作DataFrame
进行数据分析、数据预处理及行列操作。
我们以CSV
文件为例讨论一下Pandas
是如何处理文件的,其他类型文件的操作也是类似的。
假设数据源为Salaries.csv
,下面先利用Pandas
的read_csv()
方法读取数据。
In [1]: import pandas as pd
In [2]: data =pd.read_csv('Salaries.csv')
In [3]: data
Out[3]:
rank discipline phd service sex salary
0 Prof B 56 49 Male 186960
1 Prof A 12 6 Male 93000
2 Prof A 23 20 Male 110515
3 Prof A 40 31 Male 131205
4 Prof B 20 18 Male 104800
.. ... ... ... ... ... ...
73 Prof B 18 10 Female 105450
74 AssocProf B 19 6 Female 104542
75 Prof B 17 17 Female 124312
76 Prof A 28 14 Female 109954
77 Prof A 23 15 Female 109646
[78 rows x 6 columns]
为了适应各种应用场景,read_csv()
方法还配置了大量参数,这里仅说明部分常用的参数,更多内容可参考Pandas
官网。
filepath_or_buffer
:指定要读取的数据源,可以是网络链接地址URL,也可以是本地文件。sep
:指定分隔符,如果不指定参数,默认将英文逗号作为数据字段间的分隔符号。delimiter
:定界符,备选分隔符(如果指定该参数,则前面的sep
参数失效),支持使用正则表达式来匹配某些不标准的CSV
文件。Delimiter
可视为sep
的别名。header
:指定行数作为列名(相当于表格的表头,用来说明每个列的字段含义),如果文件中没有列名,则默认为0
(即设置首行作为列名,真正的数据在0
行之后)。如果没有表头,则起始数据就是正式的待分析数据,此时这个参数应该设置为None
。index_col
:指定某个列(比如ID、日期等)作为行索引。如果这个参数被设置为包含多个列的列表,则表示设定多个行索引。如果不设置,Pandas
会启用一个0~n-1
(n
为数据行数)范围内的数字作为列索引。converters
:用一个字典数据类型指明将某些列转换为指定数据类型。在字典中,key
用于指定特定的列,value
用于指定特定的数据类型。parse_dates
:指定是否对某些列的字符串启用日期解析,它是布尔类型的,默认为False
,即字符串被原样加载,该列的数据类型就是Object
(相当于Python内置的字符串数据str
)。如果设置为True
,则这一列的字符串(如果是合法字符串的话)会被解析为日期类型。
二、DataFrame
中的常用属性
DataFrame
常用属性的名称及描述如下表所示。
属性名称 | 说明 |
---|---|
index | 行索引 |
index.name | 行索引名称 |
columns | 列索引 |
columns.name | 列索引名称 |
values | 存储DataFrame 数值的numpy 数组 |
axes | 行索引和列索引 |
ndim | 维度 |
shape | 形状,元组 |
size | 元素个数 |
dtypes | 列的数据类型 |
T | DataFrame 行列转置 |
In [4]: data.dtypes
Out[4]:
rank object
discipline object
phd int64
service int64
sex object
salary int64
dtype: object
In [5]: data['salary'].dtype
Out[5]: dtype('int64')
In [6]: data.shape
Out[6]: (78, 6)
In [7]: data.ndim
Out[7]: 2
In [8]: data.columns
Out[8]: Index(['rank', 'discipline', 'phd', 'service', 'sex', 'salary'], dtype
'object')
In [9]: data.axes
Out[9]:
[RangeIndex(start=0, stop=78, step=1),
Index(['rank', 'discipline', 'phd', 'service', 'sex', 'salary'], dtype='object
)]
In [10]: data.values
Out[10]:
array([['Prof', 'B', 56, 49, 'Male', 186960],
['Prof', 'A', 12, 6, 'Male', 93000],
['Prof', 'A', 23, 20, 'Male', 110515],
['Prof', 'A', 40, 31, 'Male', 131205],
['Prof', 'B', 20, 18, 'Male', 104800],
...
['Prof', 'A', 28, 14, 'Female', 109954],
['Prof', 'A', 23, 15, 'Female', 109646]], dtype=object)
这里有两点值得注意:
首先,在Pandas
中,所谓的object
类型在本质上就是Python中的字符串类型,其主要用途就是存储文本类型的数据。
另外,如果想查看多列(≥2
)数据类型,用的属性是dtypes
,而查询单列数据类型时用的属性是dtype
,因为DataFrame
通常是由多列数据构成的,而单列数据就构成一个Series
,所以前者是复数形式,而后者是单数形式。
三、DataFrame
中的常用方法
DataFrame
中的常用方法如下表所示。
方法 | 说明 |
---|---|
head([n])/tail([n]) | 返回前/后n 行记录。 |
describe() | 返回所有数值列的统计信息。 |
max()/min() | 返回所有数值列的最大值/最小值。 |
mean()/median() | 返回所有数值列的均值/中位数。 |
std() | 返回所有数值列的标准差。 |
sample([n]) | 从DataFrame 中随机抽取n 个样本。 |
dropna() | 将数据集合中所有含有缺失值的记录删除。 |
count() | 对符合条件的记录计数。 |
value_counts() | 查看某列中有多少个不同值。 |
groupby() | 按给定条件进行分组。 |
head()
方法可以显示文件的前若干条记录,默认值为5
,如果需要修改显示行数,需要显示指定参数值。
In [11]: data.head()
Out[11]:
rank discipline phd service sex salary
0 Prof B 56 49 Male 186960
1 Prof A 12 6 Male 93000
2 Prof A 23 20 Male 110515
3 Prof A 40 31 Male 131205
4 Prof B 20 18 Male 104800
In [12]: data.head(2)
Out[12]:
rank discipline phd service sex salary
0 Prof B 56 49 Male 186960
1 Prof A 12 6 Male 93000
类似地,如果显示DataFrame
的最后5
行记录,则可以使用tail()
方法,该方法的参数默认值也为5
。
类似于NumPy
,在Pandas
中,describe()
方法常用于生成描述性的统计数据。对于数值型的数据,统计结果包括计数、平均值、标准差、最小值、最大值及百分位数。默认情况下,百分位数包括25%
分位数、50%
分位数(即中位数)和75%
分位数。
由于Pandas
的一列数据就是一个Series
对象,因此,对于单独的列可以使用Series
对象的一些统计方法。
value_counts()
是一种查看DataFrame
中某列有多少个不同类别(不限于两个类别)的快捷方法,并可计算出每个不同类别在该列中有多少次重复出现,实际上就是分类计数。
In [13]: data.sex.value_counts()
Out[13]:
Female 39
Male 39
Name: sex, dtype: int64
value_counts()
还支持计数大小的排序,这时需要启用该方法中的参数ascending
,这是一个布尔类型参数,设置为True
时表示升序,设置为False
时表示降序。
In [14]: data.discipline.value_counts(ascending=True)
Out[14]:
A 36
B 42
Name: discipline, dtype: int64
有时候,我们可能需要得到各个分类的占比,而非具体的计数值,这时可以使用value_counts()
方法。不要忘记启用另外一个参数normalize
,并将这个布尔类型参数设置为True
。
In [15]: data.discipline.value_counts(ascending=True,normalize=True)
Out[15]:
A 0.461538
B 0.538462
Name: discipline, dtype: float64
四、DataFrame
的条件过滤
如同Series
一样,我们也可以利用布尔索引来提取DataFrame
的子集,从而过滤部分不符合我们要求的数据。比如说,我们想要提取年收入大于130000
美元的人员。
In [16]: data[data.salary>=130000]
Out[16]:
rank discipline phd service sex salary
0 Prof B 56 49 Male 186960
3 Prof A 40 31 Male 131205
11 Prof B 23 23 Male 134778
13 Prof B 35 33 Male 162200
14 Prof B 25 19 Male 153750
15 Prof B 17 3 Male 150480
19 Prof A 29 27 Male 150500
26 Prof A 38 19 Male 148750
27 Prof A 45 43 Male 155865
31 Prof B 22 21 Male 155750
36 Prof B 45 45 Male 146856
40 Prof A 39 36 Female 137000
44 Prof B 23 19 Female 151768
45 Prof B 25 25 Female 140096
58 Prof B 36 26 Female 144651
72 Prof B 24 15 Female 161101
df.salary >=13000
返回的结果,实际上是一个由False/Tru
e构成的布尔矩阵。
不断通过.
操作访问DataFrame
或Series
的方法或属性,便可以接续细化以上结果。例如,统计年收入大于130000美元的女性。
In [17]: data[data.salary>=130000][data.sex=='Female']
Out[17]:
rank discipline phd service sex salary
40 Prof A 39 36 Female 137000
44 Prof B 23 19 Female 151768
45 Prof B 25 25 Female 140096
58 Prof B 36 26 Female 144651
72 Prof B 24 15 Female 161101
从上面返回的结果可以看出,这仍然是一个DataFrame
对象。更进一步,如果想返回年收入大于130000美元的女性的平均薪资。
In [18]: data[data.salary>=130000][data.sex=='Female'].salary.mean()
Out[18]: 146923.2
五、DataFrame
的排序操作
我们可以根据某一列或某几列对整个DataFrame
中的数据进行排序。默认的排序方式是升序。
比如可以对数据源Salaries.csv
中的数据,按照薪资的升序进行排序。
In [19]: data.sort_values(by='salary').head()
Out[19]:
rank discipline phd service sex salary
9 Prof A 51 51 Male 57800
54 AssocProf A 25 22 Female 62884
66 AsstProf A 7 6 Female 63100
71 AssocProf B 12 9 Female 71065
57 AsstProf A 3 1 Female 72500
返回结果就是一个DataFrame
对象,在排序过程中还可以利用sort_values()
方法中的by
参数接受一个用列表表达的多个排序指标(key
),sort_values()
将按照参数by
中的不同指标依次进行排序。随后的参数ascending
也可以接收一个由布尔值构成的列表,一一对应前面参数by
指定的排序指标,是升序(True
)还是降序(False
)。
例如,按service
的升序和salary
的降序来排序。
In [20]: data.sort_values(by=['service','salary'],ascending=[True,False]).head()
Out[20]:
rank discipline phd service sex salary
52 Prof A 12 0 Female 105000
17 AsstProf B 4 0 Male 92000
12 AsstProf B 1 0 Male 88000
23 AsstProf A 2 0 Male 85000
43 AsstProf B 5 0 Female 77000
组合排序的规则如下:先按service
来排序(升序),这是主排序;如果按service
排序,大家的排名还是不分先后,那么就启用第二个关键字salary
排序,它是按降序来排序的。
六、聚合和分组
对数据集进行分组并对各组应用一个函数(聚合或分组)是数据分析工作的重要环节。数据集就绪后,就要计算分组统计或生成透视表。
6.1 聚合
聚合(Aggregation
)和分组其实是紧密相连的。不过在Pandas
中,聚合更侧重于描述将多个数据按照某种规则(即特定函数)聚合在一起,变成一个标量(即单个数值)的数据转换过程。它与张量的“约减”(reduction
)有相通之处。
聚合的流程大致是这样的:先根据一个或多个“键”(通常对应列索引)拆分Pandas
对象(Series
或DataFrame
等);然后根据分组信息对每个数据块应用某个函数,这些函数多为统计意义上的函数,包括但不限于最小值(min
)、最大值(max
)、平均值(mean
)、中位数(median
)、众数(mode
)、计数(count
)、去重计数(nunique
)、求和(sum
)、标准差(std
)、var
(方差)、偏度(skew
)、峰度(kurt
)及用户自定义函数。
我们可以通过Pandas
提供的agg()
方法来实施聚合操作。agg()
方法仅仅是聚合操作的“壳”,其中的各个参数(即各类操作的函数名)才是实施具体操作的“瓤”。通过设置参数,可以将一个函数作用在一个或多个列上。
给agg()
方法的参数赋值是有讲究的。如果这些函数名是官方提供的,如mean
、median
等,则以字符串的形式出现(即用双引号或单引号将其括起来)。
例如,如果我们想统计前面提到的数据集合中的薪资(salary
)的最小值、最大值、均值及中位数,利用聚合函数,同时设置多个统计参数,便可“一气呵成”完成工作。
In [21]: data.agg('min')
Out[21]:
rank AssocProf
discipline A
phd 1
service 0
sex Female
salary 57800
dtype: object
In [22]: data.agg(['min','max','mean','median'])
Out[22]:
rank discipline phd service sex salary
min AssocProf A 1.000000 0.000000 Female 57800.000000
max Prof B 56.000000 51.000000 Male 186960.000000
mean NaN NaN 19.705128 15.051282 NaN 108023.782051
median NaN NaN 18.500000 14.500000 NaN 104671.000000
如果这些聚合函数来自第三方(如Numpy
)或是自定义的,则直接给出该函数的名称(不能利用引号将函数引起来),不需要加引号。
In [23]: data.agg(['min','max',np.mean,'median'])
Out[23]:
rank discipline phd service sex salary
min AssocProf A 1.000000 0.000000 Female 57800.000000
max Prof B 56.000000 51.000000 Male 186960.000000
mean NaN NaN 19.705128 15.051282 NaN 108023.782051
median NaN NaN 18.500000 14.500000 NaN 104671.000000
agg()
方法的参数可以针对不同的列给出不同的统计,这时,agg()
方法内的参数是一个字典对象。字典中是以key:value
方式来指定统计方式的,其中key
表示不同的列,value
表示统计指标(如果不止一个统计指标,可以用列表将多个指标括起来),不同的key
都是以字符串形式表征的。
比如说,如果想统计薪资(salary
)这一列的最大值和最小值,而对服务年限(service
)这一列统计它的均值和标准差,就可以如下操作。
In [24]: data.agg({'salary':['min','max'],'service':['mean','std']})
Out[24]:
salary service
max 186960.0 NaN
mean NaN 15.051282
min 57800.0 NaN
std NaN 12.139768
6.2 分组
Pandas
提供了一个灵活高效的分组方法——groupby()
。通过这个方法,我们能以一种很自然的方式,对每个分组进行数据统计、分析和转换。分组统计的指标包括计数、平均值、标准差,如果标准化的统计不能满足我们的需求,还可以自定义个性化的统计函数。
groupby()
的核心操作分三步走:分割-应用-合并(split-apply-combine
)。操作的第一步,就是根据一个或多个key将数据分割为若干个组,每个组包含若干行数据。分组之后,如果不加以操作,意义并不大,因此我们通常会对分组的结果应用某个特定的函数,产生一组新的值。然后再将每组产生的值合并到一起,形成一个新的数据集合。
假设,我们想对前面打开的数据集用职称(rank)作为key
进行数据分割,就可以用如下代码来实现。
In [25]: data.groupby(['rank'])
Out[25]: <`Pandas`.core.groupby.generic.`DataFrame`GroupBy object at 0x000002C4AF5E7C50>
查看上面的结果会发现,这个分组操作可能并非我愿,因为并没有输出分组信息,而是输出一堆我们看不懂的东西。事实上,groupby()
方法仅返回一个DataFrame
GroupBy
对象,而这个对象实际上还没有进行任何计算,只是生成了一系列含有分组键[‘rank’]的中间数据而已。
如果想让这个DataFrame
GroupBy
对象真正发挥作用,还需要将特定方法应用在这个对象上,这些方法包括但不限于mean()
、count()
、median()
等。
In [26]: data.groupby(['rank']).mean()
Out[26]:
phd service salary
rank
AssocProf 15.076923 11.307692 91786.230769
AsstProf 5.052632 2.210526 81362.789474
Prof 27.065217 21.413043 123624.804348
In [27]: data.groupby(['rank']).count()
Out[27]:
discipline phd service sex salary
rank
AssocProf 13 13 13 13 13
AsstProf 19 19 19 19 19
Prof 46 46 46 46 46
In [28]: data.groupby(['rank']).median()
Out[28]:
phd service salary
rank
AssocProf 13.0 9.0 103613.0
AsstProf 4.0 2.0 78500.0
Prof 24.5 19.0 123321.5
In [29]: data.groupby(['rank']).describe()
Out[29]:
phd ... salary
count mean std min 25% ... min 25% 50% 75% max
rank ...
AssocProf 13.0 15.076923 5.589597 9.0 12.00 ... 62884.0 74830.0 103613.0 104542.00 119800.0
AsstProf 19.0 5.052632 2.738079 1.0 3.50 ... 63100.0 74096.0 78500.0 91150.00 97032.0
Prof 46.0 27.065217 10.185834 12.0 19.25 ... 57800.0 105112.5 123321.5 143512.25 186960.0
[3 rows x 24 columns]
从上面的输出可以看到,一旦根据关键字分组之后,对分组数据实施统计操作,会作用在所有能适用的列上。事实上,我们也可以仅对分组后的部分列进行统计操作。
以下代码的功能,就是对分组后的数据的salary这一列实施求均值操作。
In [30]: data.groupby('rank')['salary'].mean()
Out[30]:
rank
AssocProf 91786.230769
AsstProf 81362.789474
Prof 123624.804348
Name: salary, dtype: float64
In [31]: data.groupby('rank')[['salary']].mean()
Out[31]:
salary
rank
AssocProf 91786.230769
AsstProf 81362.789474
Prof 123624.804348
有一个细节值得注意:如果我们用双层方括号将特定的列(通常用于多个列)括起来,则返回的结果是一个DataFrame
对象。反之,如果我们用单层方括号将指定列括起来,这时输出的结果是一个Series
对象。
实际上,分组和聚合通常会结合在一起使用。比如说,通过rank
分组之后,我们想求得salary
和service
这两列的均值、标准差。
In [32]: data.groupby('rank')[['salary','service']].agg('mean','std')
Out[32]:
salary service
rank
AssocProf 91786.230769 11.307692
AsstProf 81362.789474 2.210526
Prof 123624.804348 21.413043
七、数据预处理
我们想处理的数据是完整且有意义的,但现实可能是“非常骨感”的,可能会存在数据缺失、数据格式不统一或数据不准确的情况。倘若数据不对(如格式不统一、不准确、有缺失等),那么在其基础上的一切分析都是徒劳。因此,数据清洗通常是数据分析的第一步,也是最烦琐且耗时的一步。对这些“脏”的数据,自然不能简单地“一扔了之”,因为它们依然包括很多有价值的信息,所以适当的处理这些“脏”数据,变废为宝,便非常有意义。
庆幸的是,Pandas
提供了强大的数据清洗功能,通过必要的处理,最后还是可以得到可用的数据。Pandas
提供了很多好用的数据预处理方法,针对DataFrame
,常用的方法见下表。
下面我们以泰坦尼克幸存者数据为例演示预处理功能。
泰坦尼克号事件留下了许多“弥足珍贵”的数据记录,由于该数据集中的记录不完整,存在缺失值、异常值等,因此也成了很典型的练习数据分析的数据集。
7.1 数据“鸟瞰”
对数据处理前,我们需要对数据一个简单的认识。
可以通过head()
方法、shape
属性、info()
方法预览数据,了解数据表的大小、字段的名称及数据格式等。
In [29]:ti=pd.read_csv('./titanic/train.csv')
In [30]: ti.head()
Out[31]:
PassengerId Survived Pclass ... Fare Cabin Embarked
0 1 0 3 ... 7.2500 NaN S
1 2 1 1 ... 71.2833 C85 C
2 3 1 3 ... 7.9250 NaN S
3 4 1 1 ... 53.1000 C123 S
4 5 0 3 ... 8.0500 NaN S
[5 rows x 12 columns]
In [32]: ti.shape
Out[32]: (891, 12)
In [33]: ti.info()
<class '`Pandas`.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
我们还可以通过describe()
方法获取该数据集的摘要信息。
In [34]: ti.describe()
Out[34]:
PassengerId Survived Pclass Age SibSp Parch Fare
count 891.000000 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208
std 257.353842 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429
min 1.000000 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400
50% 446.000000 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200
75% 668.500000 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200
7.2 缺失值的填充
从前面的分析可知,年龄(Age
)、是否住在独立房间(Cabin
)、登船港口(Embarked
)里面有缺失数据。很多机器学习算法要求传入的特征中不能有空值,所以需要对缺失值进行填充。
In [35]: ti.isnull().sum()
Out[35]:
PassengerId 0
Survived 0
Pclass 0
Name 0
Sex 0
Age 177
SibSp 0
Parch 0
Ticket 0
Fare 0
Cabin 687
Embarked 2
dtype: int64
需要注意的是,在Python中,是可以对布尔值实施加法操作的,True
被当作1
,而False
被当作0
,所以可以对isnull()
的结果实施求和操作。
对缺失值实施填充需要用到fillna()
方法,其原型如下。
fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None)
其中,参数value
指明有缺失值时该填充什么值,默认值为None
,相当于不设置填充值。
以用method()
方法来指导填充行为。如果某一行或某一列不全为缺失值,那说明它总会找到合法的有效值。而这个有效值就用来填充空位。这时需要设置填充策略,如果method='backfill'
或method='bfill'
,则表示在填充时会按照指定的轴方向,向回(back)找到上一个合法有效值,然后把这个有效值填充到当前空缺处。反之,如果method='ffill'
或method='pad'
,则表明按照指定的轴方向,向前(front)找到一个有效值来填充。
参数axis
表示的是填充缺失值所沿的轴方向。取值为0
或'index'
时,表示按行填充,取值为1
或'columns'
时,表示按列填充。
如果我们希望在原始DataFrame
中(而非DataFrame
的副本中)填充数据,则需要把参数inplace
设置为True
。设置为False
时,Pandas
会创建一个副本,填充的结果对原有的数据集没有任何影响。这时,我们需要用一个新DataFrame
对象来接收fillna()
方法的执行结果。
缺失值的填充策略有很多。除了在fillna()
方法中利用method()
方法来指导填充,我们还可以自定义一些填充策略。比如,对于数值型空缺,我们可以使用众数、均值、中位数填充。
对于具备时间序列特征的空缺可以使用插值(interpolation)方式来填充。插值是一种离散函数逼近的重要方法,它可通过拟合函数在有限个点处的取值状况,估算出函数在其他点(缺失值)处的近似值。如果是分类数据(即标签)缺失,一种填充策略就是用最常见的类别来填充空缺处,这类似于众数填充。当然,如果在特征参数很完备的情况下,还可以用模型来预测缺失值,然后填充。
In [36]: ti['Embarked'].isnull().sum()
Out[36]: 2
In [38]: ti['Embarked'].fillna(ti['Embarked'].mode()[0],inplace=True)
In [39]: ti['Embarked'].isnull().sum()
Out[39]: 0
ti['Embarked']
返回的是一个Series
对象,它相当于DataFrame
中的一列,然后求这个Series
对象的众数,这里用到了mode()
方法。需要注意的是,通过前面的介绍可知,一个数据集中的众数可能不止一个,为了稳妥起见,mode()
方法返回的是一个列表,以便存储多个并列的众数。对于一个列表而言,我们想取这个列表中的第一个元素,就可以用下标[0]
获得。
我们对另外一个有缺失值的列Age
进行填充,这次我们选择了均值填充。或许你会问,为什么不用众数填充呢?用众数填充也是可以的,这取决于你对数据处理的偏好,并无好坏之分。
In [41]: ti['Age'].isnull().sum()
Out[41]: 177
In [42]: ti['Age'].fillna(ti['Age'].mean(),inplace=True)
In [43]: ti['Age'].isnull().sum()
Out[43]: 0
参考资料
《Python极简讲义:一本书入门数据分析与机器学习》
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)