一、读取文件

Pandas的主业是数据分析。因此,从外部文件读/写数据是Pandas的重要功能。Pandas提供了多种API函数用于支持多种类型数据(如CSV、Excel、SQL等)的读写,其中常用的函数如下表所示。

文件类型读取函数写入函数
xls/xlsxread_excelto_excel
CSVread_csvto_csv
SQLread_sqlto_sql
JSONread_jsonto_json
HTMLread_htmlto_html
HDF5read_hdfto_hdf
pickleread_pickleto_pickle

Pandas可以将读取到的表格型数据转换为DataFrame数据,然后通过操作DataFrame进行数据分析、数据预处理及行列操作。

我们以CSV文件为例讨论一下Pandas是如何处理文件的,其他类型文件的操作也是类似的。

假设数据源为Salaries.csv,下面先利用Pandasread_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-1n为数据行数)范围内的数字作为列索引。
  • 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列的数据类型
TDataFrame行列转置
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/True构成的布尔矩阵。

不断通过.操作访问DataFrameSeries的方法或属性,便可以接续细化以上结果。例如,统计年收入大于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对象(SeriesDataFrame等);然后根据分组信息对每个数据块应用某个函数,这些函数多为统计意义上的函数,包括但不限于最小值(min)、最大值(max)、平均值(mean)、中位数(median)、众数(mode)、计数(count)、去重计数(nunique)、求和(sum)、标准差(std)、var(方差)、偏度(skew)、峰度(kurt)及用户自定义函数。
我们可以通过Pandas提供的agg()方法来实施聚合操作。agg()方法仅仅是聚合操作的“壳”,其中的各个参数(即各类操作的函数名)才是实施具体操作的“瓤”。通过设置参数,可以将一个函数作用在一个或多个列上。
agg()方法的参数赋值是有讲究的。如果这些函数名是官方提供的,如meanmedian等,则以字符串的形式出现(即用双引号或单引号将其括起来)。
例如,如果我们想统计前面提到的数据集合中的薪资(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分组之后,我们想求得salaryservice这两列的均值、标准差。

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极简讲义:一本书入门数据分析与机器学习》

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐