Python-pandas知识梳理

Pandas是基于NumPy的一个开源 Python 库,它被广泛用于快速分析数据,以及数据清洗和准备等工作。它的名字来源是由“ Panel data”(面板数据,一个计量经济学名词)两个单词拼成的。简单地说,你可以把 Pandas 看作是 Python 版的 Excel。

一文读懂Pandas数据分析 - 图1

我喜欢 Pandas 的原因之一,是因为它很酷,它能很好地处理来自一大堆各种不同来源的数据,比如 Excel 表格、CSV 文件、SQL 数据库,甚至还能处理存储在网页上的数据。

话不多说,让我们开始吧!

安装 Pandas

如果你已经安装了 Anaconda,你可以很方便地在终端或者命令提示符里输入命令安装 Pandas

  1. conda install pandas

如果你还没安装 Anaconda,你也可以用 Python 自带的包管理工具 pip 来安装:

  1. pip3 install pandas

Pandas 数据结构

Series 是一种一维数组,和 NumPy 里的数组很相似。事实上,Series 基本上就是基于 NumPy 的数组对象来的。和 NumPy 的数组不同,Series 能为数据自定义标签,也就是索引(index),然后通过索引来访问数组中的数据。

  1. import pandas as pd
  2. import numpy as np

创建一个 Series 的基本语法如下:

  1. my_series = pd.Series(data,index)

上面的 data 参数可以是任意数据对象,比如字典、列表甚至是 NumPy 数组,而 index 参数则是对 data 的索引值,类似字典的 key。

下面这个例子里,将创建一个 Series 对象,并用字符串对数字列表进行索引:

  1. countries=['USA','Nigeria','France','Ghana']
  2. my_data=[100,200,300,400]
  3. pd.Series(countries,my_data)
  1. 100 USA
  2. 200 Nigeria
  3. 300 France
  4. 400 Ghana
  5. dtype: object

注意:请记住, index 参数是可省略的,你可以选择不输入这个参数。如果不带 index 参数,Pandas 会自动用默认 index 进行索引,类似数组,索引值是 [0, …, len(data) - 1] ,如下所示:

从 NumPy 数组对象创建 Series:

  1. np_arr=np.array(my_data)
  1. pd.Series(np_arr)
  1. 0 100
  2. 1 200
  3. 2 300
  4. 3 400
  5. dtype: int64

从 Python 字典对象创建 Series:

  1. my_dict={'a':50,'b':60,'c':70,'d':80}
  1. pd.Series(my_dict)
  1. a 50
  2. b 60
  3. c 70
  4. d 80
  5. dtype: int64

如上图的中所示,如果你从一个 Python 字典对象创建 Series,Pandas 会自动把字典的键值设置成 Series 的 index,并将对应的 values 放在和索引对应的 data 里。

和 NumPy 数组不同,Pandas 的 Series 能存放各种不同类型的对象。

从 Series 里获取数据

访问 Series 里的数据的方式,和 Python 字典基本一样:

  1. series1=pd.Series([1,2,3,4],['London','HongKong','Lagos','Mumbai'])
  2. series1['London']
  1. 1

对 Series 进行算术运算操作

对 Series 的算术运算都是基于 index 进行的。我们可以用加减乘除(+ - * /)这样的运算符对两个 Series 进行运算,Pandas 将会根据索引 index,对响应的数据进行计算,结果将会以浮点数的形式存储,以避免丢失精度。

  1. series1=pd.Series([1,2,3,4],['London','HongKong','Lagos','Mumbai'])
  2. series2=pd.Series([1,3,6,4],['London','Accra','Lagon','Delhi'])
  1. series1-series2
  1. Accra NaN
  2. Delhi NaN
  3. HongKong NaN
  4. Lagon NaN
  5. Lagos NaN
  6. London 0.0
  7. Mumbai NaN
  8. dtype: float64
  1. series1+series2
  1. Accra NaN
  2. Delhi NaN
  3. HongKong NaN
  4. Lagon NaN
  5. Lagos NaN
  6. London 2.0
  7. Mumbai NaN
  8. dtype: float64
  1. series1*series2
  1. Accra NaN
  2. Delhi NaN
  3. HongKong NaN
  4. Lagon NaN
  5. Lagos NaN
  6. London 1.0
  7. Mumbai NaN
  8. dtype: float64

如上,如果 Pandas 在两个 Series 里找不到相同的 index,对应的位置就返回一个空值 NaN。

DataFrames

Pandas 的 DataFrame(数据表)是一种 2 维数据结构,数据以表格的形式存储,分成若干行和列。通过 DataFrame,你能很方便地处理数据。常见的操作比如选取、替换行或列的数据,还能重组数据表、修改索引、多重筛选等。

构建一个 DataFrame 对象的基本语法如下:

举个例子,我们可以创建一个 5 行 4 列的 DataFrame,并填上随机数据:

看,上面表中的每一列基本上就是一个 Series ,它们都用了同一个 index。因此,我们基本上可以把 DataFrame 理解成一组采用同样索引的 Series 的集合。

下面这个例子里,我们将用许多 Series 来构建一个DataFrame:

  1. df={'Name':pd.Series(['John','Aaron','Todd'],index=['a','b','c']),
  2. 'age':pd.Series(['39','34','32','33'],index=['a','b','c','d']),
  3. 'Nationality':pd.Series(['US',"China","US"],index=['a','b','c'])
  4. }
  5. pd.DataFrame(df)
Name age Nationality
a John 39 US
b Aaron 34 China
c Todd 32 US
d NaN 33 NaN

以及用一个字典来创建 DataFrame

  1. data={'name':['George','ann','ting','charles','phil'],
  2. 'age':[40,24,31,21,23],
  3. 'year':[2012,2012,2013,2014,2014]
  4. }
  5. my_df=pd.DataFrame(data,index=['Lagos','Dubai','Mumbai','Accra','Yuma'])
  6. my_df
name age year
Lagos George 40 2012
Dubai ann 24 2012
Mumbai ting 31 2013
Accra charles 21 2014
Yuma phil 23 2014

从DataFrame中获取数据

  1. my_df['name']
  1. Lagos George
  2. Dubai ann
  3. Mumbai ting
  4. Accra charles
  5. Yuma phil
  6. Name: name, dtype: object

因为我们只获取一列,所以返回的就是一个 Series。可以用 type() 函数确认返回值的类型:

  1. type(my_df['name'])
  1. pandas.core.series.Series

如果获取多个列,那返回的就是一个 DataFrame 类型:

  1. my_df[['name','year']]
name year
Lagos George 2012
Dubai ann 2012
Mumbai ting 2013
Accra charles 2014
Yuma phil 2014

创建一个列的时候,你需要先定义这个列的数据和索引。举个栗子,比如这个 DataFrame:

  1. df={'Name':pd.Series(['John','Aaron','Todd'],index=['a','b','c']),
  2. 'age':pd.Series(['39','34','32','33'],index=['a','b','c','d']),
  3. 'Nationality':pd.Series(['US',"China","US"],index=['a','b','c'])
  4. }
  5. pd.DataFrame(df)
Name age Nationality
a John 39 US
b Aaron 34 China
c Todd 32 US
d NaN 33 NaN

增加数据列有两种办法:可以从头开始定义一个 pd.Series,再把它放到表中,也可以利用现有的列来产生需要的新列。比如下面两种操作:

定义一个 Series ,并放入 ‘Year’ 列中:

  1. df['year']=pd.Series(['2016','2017','2018','2015'],['a','b','c','d'])
  2. pd.DataFrame(df)
Name age Nationality year
a John 39 US 2016
b Aaron 34 China 2017
c Todd 32 US 2018
d NaN 33 NaN 2015

从现有的列创建新列:

  1. df['Birth_year']=df['year']+df['age']
  2. df=pd.DataFrame(df)
  3. df
Name age Nationality year Birth_year
a John 39 US 2016 201639
b Aaron 34 China 2017 201734
c Todd 32 US 2018 201832
d NaN 33 NaN 2015 201533

从 DataFrame 里删除行/列

想要删除某一行或一列,可以用 .drop() 函数。在使用这个函数的时候,你需要先指定具体的删除方向,axis=0 对应的是行 row,而 axis=1 对应的是列 column 。

删除 ‘Birth_year’ 列

  1. df.drop('Birth_year',axis=1)
Name age Nationality year
a John 39 US 2016
b Aaron 34 China 2017
c Todd 32 US 2018
d NaN 33 NaN 2015

删除 ‘d’ 行:

  1. df.drop('d',axis=0)
Name age Nationality year Birth_year
a John 39 US 2016 201639
b Aaron 34 China 2017 201734
c Todd 32 US 2018 201832

指定位置增加行列

  1. df
  2. A B C D
  3. 0 1 3 3 4
  4. 1 5 6 7 8
  5. 2 1 1 1 1
  6. 3 2 3 2 3
  7. 4 7 8 9 10
  8. df.insert(0,'E',[11,12,13,14,15]) #插入一列
  9. df
  10. E A B C D
  11. 0 11 1 3 3 4
  12. 1 12 5 6 7 8
  13. 2 13 1 1 1 1
  14. 3 14 2 3 2 3
  15. 4 15 7 8 9 10
  16. df
  17. E A B C D
  18. 0 11 1 3 3 4
  19. 1 12 5 6 7 8
  20. 2 13 1 1 1 1
  21. 3 14 2 3 2 3
  22. 4 15 7 8 9 10
  23. df.insert(1,'调换',df.pop('A')) #改变某一列的位置。如:先删除A列,然后在原表data中第1列插入被删掉的列。
  24. df
  25. E 调换 B C D
  26. 0 11 1 3 3 4
  27. 1 12 5 6 7 8
  28. 2 13 1 1 1 1
  29. 3 14 2 3 2 3
  30. 4 15 7 8 9 10
  31. #df字典方式添加一行,append,忽略索引
  32. a b c d
  33. 0 1 3 3 4
  34. 1 5 6 7 8
  35. row={'a':9,'b':10,'c':11,'d':12}
  36. df.append(row,ignore_index=True)
  37. a b c d
  38. 0 1 3 3 4
  39. 1 5 6 7 8
  40. 2 9 10 11 12
  41. #用loc指定位置添加一行
  42. df.loc[2]=[9,10,11,12]
  43. df
  44. a b c d
  45. 0 1 3 3 4
  46. 1 5 6 7 8
  47. 2 9 10 11 12

请务必记住,除非用户明确指定,否则在调用 .drop() 的时候,Pandas 并不会真的永久性地删除这行/列。这主要是为了防止用户误操作丢失数据。

你可以通过调用 df 来确认数据的完整性。如果你确定要永久性删除某一行/列,你需要加上 inplace=True 参数,比如:

  1. df.drop('d',axis=0,inplace=True)
  1. df
Name age Nationality year Birth_year
a John 39 US 2016 201639
b Aaron 34 China 2017 201734
c Todd 32 US 2018 201832

获取 DataFrame 中的一行或多行数据

要获取某一行,你需要用 .loc[] 来按索引(标签名)引用这一行,或者用 .iloc[],按这行在表中的位置(行数)来引用。

  1. df.loc['a']
  1. Name John
  2. age 39
  3. Nationality US
  4. year 2016
  5. Birth_year 201639
  6. Name: a, dtype: object

同时你可以用 .loc[] 来指定具体的行列范围,并生成一个子数据表,就像在NumPy里做的一样。比如,提取 ‘c’ 行中 ‘Name’ 列的内容,
可以如下操作:

  1. df.iloc[0]
  1. Name John
  2. age 39
  3. Nationality US
  4. year 2016
  5. Birth_year 201639
  6. Name: a, dtype: object
  1. df.iloc[[0,1]]
Name age Nationality year Birth_year
a John 39 US 2016 201639
b Aaron 34 China 2017 201734
  1. df.loc['b','Name']
  1. 'Aaron'
  1. df.loc[['b','c'],['Name','Year']]
Name Year
b Aaron NaN
c Todd NaN

条件筛选

用中括号 [] 的方式,除了直接指定选中某些列外,还能接收一个条件语句,然后筛选出符合条件的行/列。比如,我们希望在下面这个表格中筛选出 ‘W’>0 的行:

  1. df=pd.DataFrame(np.random.randn(5,4),['A','B','C','D','E'],['W','X','Y','Z'])
  2. df[df['W']>0]
W X Y Z
A 0.507655 0.945965 -0.072447 1.112854
B 2.618248 -1.634475 0.945621 0.211625
C 1.274228 -0.348917 0.768581 0.746289
D 0.802278 1.236282 -1.399972 -0.023978
E 0.240023 0.479150 -0.569359 0.082668

如果要进一步筛选,只看 ‘X’ 列中 ‘W’>0 的数据:

上面那行相当于下面这样的几个操作连在一起:

一文读懂Pandas数据分析 - 图2

你可以用逻辑运算符 &(与)和 |(或)来链接多个条件语句,以便一次应用多个筛选条件到当前的 DataFrame 上。举个栗子,你可以用下面的方法筛选出同时满足 ‘W’>0 和’X’>1 的行:

  1. df[(df['W']>0) & (df['X']>1)]
W X Y Z
D 0.802278 1.236282 -1.399972 -0.023978

重置 DataFrame 的索引

如果你觉得当前 DataFrame 的索引有问题,你可以用 .reset_index() 简单地把整个表的索引都重置掉。这个方法将把目标 DataFrame 的索引保存在一个叫 index 的列中,而把表格的索引变成默认的从零开始的数字,也就是 [0, …, len(data) - 1] 。比如下面这样:

  1. df.reset_index()
index W X Y Z
0 A 0.507655 0.945965 -0.072447 1.112854
1 B 2.618248 -1.634475 0.945621 0.211625
2 C 1.274228 -0.348917 0.768581 0.746289
3 D 0.802278 1.236282 -1.399972 -0.023978
4 E 0.240023 0.479150 -0.569359 0.082668

和删除操作差不多,.reset_index() 并不会永久改变你表格的索引,除非你调用的时候明确传入了 inplace 参数,比如:.reset_index(inplace=True)

设置 DataFrame 的索引值

类似地,我们还可以用 .set_index() 方法,将 DataFrame 里的某一列作为索引来用。比如,我们在这个表里新建一个名为 “ID” 的列:

  1. df['ID']=['df1','df2','df3','df4','df5']
  2. df
W X Y Z ID
A 0.507655 0.945965 -0.072447 1.112854 df1
B 2.618248 -1.634475 0.945621 0.211625 df2
C 1.274228 -0.348917 0.768581 0.746289 df3
D 0.802278 1.236282 -1.399972 -0.023978 df4
E 0.240023 0.479150 -0.569359 0.082668 df5

然后把它设置成索引:

  1. df.set_index('ID')
W X Y Z
ID
df1 0.507655 0.945965 -0.072447 1.112854
df2 2.618248 -1.634475 0.945621 0.211625
df3 1.274228 -0.348917 0.768581 0.746289
df4 0.802278 1.236282 -1.399972 -0.023978
df5 0.240023 0.479150 -0.569359 0.082668

注意,不像 .reset_index() 会保留一个备份,然后才用默认的索引值代替原索引,.set_index() 将会完全覆盖原来的索引值。

多级索引(MultiIndex)以及命名索引的不同等级

多级索引其实就是一个由元组(Tuple)组成的数组,每一个元组都是独一无二的。你可以从一个包含许多数组的列表中创建多级索引(调用 MultiIndex.from_arrays ),也可以用一个包含许多元组的数组(调用 MultiIndex.from_tuples )或者是用一对可迭代对象的集合(比如两个列表,互相两两配对)来构建(调用MultiIndex.from_product )。

下面这个例子,我们从元组中创建多级索引:

  1. outside=['0 Levle','0 Levle','0 Levle','A Levle','A Levle','A Levle']
  2. inside=[21,22,23,21,22,23]
  3. my_index=list(zip(outside,inside))

最后这个 list(zip()) 的嵌套函数,把上面两个列表合并成了一个每个元素都是元组的列表。这时 my_index 的内容是这样的:[(‘O Level’, 21), (‘O Level’, 22), (‘O Level’, 23), (‘A Level’, 21), (‘A Level’, 22), (‘A Level’, 23)]

接下来,我们调用 .MultiIndex.from_tuples(my_index) 生成一个多级索引对象,然后将这个多级索引对象转成一个 DataFrame:

  1. my_index=pd.MultiIndex.from_tuples(my_index)
  2. my_index
  1. MultiIndex(levels=[['0 Levle', 'A Levle'], [21, 22, 23]],
  2. codes=[[0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2]])
  1. df=pd.DataFrame(np.random.randn(6,2),index=my_index,columns=['A','B'])
  2. df
A B
0 Levle 21 -0.239474 0.840062
22 -0.375724 -1.630837
23 0.608979 -0.489202
A Levle 21 -1.196954 -0.068834
22 0.564024 0.007361
23 1.220147 -0.472613

要获取多级索引中的数据,还是用到 .loc[] 。比如,先获取 ‘O Level’ 下的数据:

  1. df.loc['0 Levle']
A B
21 -0.239474 0.840062
22 -0.375724 -1.630837
23 0.608979 -0.489202

然后再用一次 .loc[],获取下一层 21 里的数据:

  1. df.loc['0 Levle'].loc[21]
  1. A -0.239474
  2. B 0.840062
  3. Name: 21, dtype: float64

如上所示,df 这个 DataFrame 的头两个索引列没有名字,看起来不太易懂。我们可以用 .index.names 给它们加上名字:

  1. df.index.names=['Levels','Num']
  2. df
A B
Levels Num
0 Levle 21 -0.239474 0.840062
22 -0.375724 -1.630837
23 0.608979 -0.489202
A Levle 21 -1.196954 -0.068834
22 0.564024 0.007361
23 1.220147 -0.472613

交叉选择行和列中的数据

我们可以用 .xs() 方法轻松获取到多级索引中某些特定级别的数据。比如,我们需要找到所有 Levels 中,Num = 22 的行:

  1. df.xs(22,level="Num")
A B
Levels
0 Levle -0.375724 -1.630837
A Levle 0.564024 0.007361

清洗数据

删除或填充空值

在许多情况下,如果你用 Pandas 来读取大量数据,往往会发现原始数据中会存在不完整的地方。在 DataFrame 中缺少数据的位置, Pandas 会自动填入一个空值,比如 NaN或 Null 。因此,我们可以选择用 .dropna() 来丢弃这些自动填充的值,或是用.fillna() 来自动给这些空值填充数据。

比如这个例子:

  1. dt={'A':[1,np.nan,3],'B':[2,np.nan,np.nan],'c':[4,5,6]}
  2. dt=pd.DataFrame(dt)
  3. dt
A B c
0 1.0 2.0 4
1 NaN NaN 5
2 3.0 NaN 6

当你使用 .dropna() 方法时,就是告诉 Pandas 删除掉存在一个或多个空值的行(或者列)。删除列用的是 .dropna(axis=0) ,删除行用的是 .dropna(axis=1) 。

请注意,如果你没有指定 axis 参数,默认是删除行。

删除行

  1. dt.dropna()
A B c
0 1.0 2.0 4

删除列:

  1. dt.dropna(axis=1)
c
0 4
1 5
2 6

类似的,如果你使用 .fillna() 方法,Pandas 将对这个 DataFrame 里所有的空值位置填上你指定的默认值。比如,将表中所有 NaN 替换成 20 :

  1. dt.fillna('20')
A B c
0 1 2 4
1 20 20 5
2 3 20 6

当然,这有的时候打击范围太大了。于是我们可以选择只对某些特定的行或者列进行填充。比如只对 ‘A’ 列进行操作,在空值处填入该列的平均值:

dt.fillna(dt['A'].mean())

如上所示,’A’ 列的平均值是 2.0,所以第二行的空值被填上了 2.0。

同理,.dropna() 和 .fillna() 并不会永久性改变你的数据,除非你传入了inplace=True 参数。

分组统计

Pandas 的分组统计功能可以按某一列的内容对数据行进行分组,并对其应用统计函数,比如求和,平均数,中位数,标准差等等…

举例来说,用 .groupby() 方法,我们可以对下面这数据表按 ‘Company’ 列进行分组,并用 .mean() 求每组的平均值:

首先,初始化一个DataFrame, 然后,调用 .groupby() 方法,并继续用 .mean() 求平均值:

  1. d={'company':['google','google','oracle','oracle','twitter','twitter'],
  2. 'person':['sam','charlie','amy','vanessa','carl','sarah'],
  3. 'sales':[200,120,340,124,243,350]
  4. }
  5. df=pd.DataFrame(d)
  6. df
company person sales
0 google sam 200
1 google charlie 120
2 oracle amy 340
3 oracle vanessa 124
4 twitter carl 243
5 twitter sarah 350
  1. df.groupby('company').mean()
sales
company
google 160.0
oracle 232.0
twitter 296.5

上面的结果中,Sales 列就变成每个公司的分组平均数了。

计数

用 .count() 方法,能对 DataFrame 中的某个元素出现的次数进行计数。

用一个月整理的Pandas的教程!最全面的教程没有之一!先收藏吧!

  1. df.groupby('company').count()
person sales
company
google 2 2
oracle 2 2
twitter 2 2

数据描述

Pandas 的 .describe() 方法将对 DataFrame 里的数据进行分析,并一次性生成多个描述性的统计指标,方便用户对数据有一个直观上的认识。

生成的指标,从左到右分别是:计数、平均数、标准差、最小值、25% 50% 75% 位置的值、最大值。

  1. df.groupby('company').describe()
sales
count mean std min 25% 50% 75% max
company
google 2.0 160.0 56.568542 120.0 140.00 160.0 180.00 200.0
oracle 2.0 232.0 152.735065 124.0 178.00 232.0 286.00 340.0
twitter 2.0 296.5 75.660426 243.0 269.75 296.5 323.25 350.0

如果你不喜欢这个排版,你可以用 .transpose() 方法获得一个竖排的格式:

  1. df.groupby('company').describe().transpose()
company google oracle twitter
sales count 2.000000 2.000000 2.000000
mean 160.000000 232.000000 296.500000
std 56.568542 152.735065 75.660426
min 120.000000 124.000000 243.000000
25% 140.000000 178.000000 269.750000
50% 160.000000 232.000000 296.500000
75% 180.000000 286.000000 323.250000
max 200.000000 340.000000 350.000000

如果你只想看 Google 的数据,还能这样:

  1. df.groupby('company').describe().transpose()['google']
  1. sales count 2.000000
  2. mean 160.000000
  3. std 56.568542
  4. min 120.000000
  5. 25% 140.000000
  6. 50% 160.000000
  7. 75% 180.000000
  8. max 200.000000
  9. Name: google, dtype: float64

堆叠(Concat)

堆叠基本上就是简单地把多个 DataFrame 堆在一起,拼成一个更大的 DataFrame。当你进行堆叠的时候,请务必注意你数据表的索引和列的延伸方向,堆叠的方向要和它一致。

比如,有这样3个 DataFrame:df1,df2,df3

我们用 pd.concat() 将它堆叠成一个大的表:

  1. df1=pd.DataFrame({'A':['A0','A1','A2','A3'],
  2. "B":['B0','B1','B2','B3'],
  3. "C":['C0','C1','C2','C3'],
  4. "D":['D0','D1','D2','D3']})
  5. df2=pd.DataFrame({'A':['A4','A5','A6','A7'],
  6. "B":['B4','B5','B6','B7'],
  7. "C":['C4','C5','C6','C7'],
  8. "D":['D4','D5','D6','D7']},index=[4,5,6,7])
  9. df3=pd.DataFrame({'A':['A8','A9','A10','A11'],
  10. "B":['B8','B9','B10','B11'],
  11. "C":['C8','C9','C10','C11'],
  12. "D":['D8','D9','D10','D11']},index=[8,9,10,11])
  1. pd.concat([df1,df2,df3])
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11

因为我们没有指定堆叠的方向,Pandas 默认按行的方向堆叠,把每个表的索引按顺序叠加。

如果你想要按列的方向堆叠,那你需要传入 axis=1 参数:

  1. pd.concat([df1,df2,df3],axis=1)
A B C D A B C D A B C D
0 A0 B0 C0 D0 NaN NaN NaN NaN NaN NaN NaN NaN
1 A1 B1 C1 D1 NaN NaN NaN NaN NaN NaN NaN NaN
2 A2 B2 C2 D2 NaN NaN NaN NaN NaN NaN NaN NaN
3 A3 B3 C3 D3 NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN A4 B4 C4 D4 NaN NaN NaN NaN
5 NaN NaN NaN NaN A5 B5 C5 D5 NaN NaN NaN NaN
6 NaN NaN NaN NaN A6 B6 C6 D6 NaN NaN NaN NaN
7 NaN NaN NaN NaN A7 B7 C7 D7 NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN A8 B8 C8 D8
9 NaN NaN NaN NaN NaN NaN NaN NaN A9 B9 C9 D9
10 NaN NaN NaN NaN NaN NaN NaN NaN A10 B10 C10 D10
11 NaN NaN NaN NaN NaN NaN NaN NaN A11 B11 C11 D11

注意,这里出现了一大堆空值。因为我们用来堆叠的3个 DataFrame 里,有许多索引是没有对应数据的。因此,当你使用 pd.concat() 的时候,一定要注意堆叠方向的坐标轴(行或列)含有所需的所有数据。

归并(Merge)

使用 pd.merge() 函数,能将多个 DataFrame 归并在一起,它的合并方式类似合并 SQL 数据表的方式。

归并操作的基本语法是 pd.merge(left, right, how=’inner’, on=’Key’) 。其中 left 参数代表放在左侧的 DataFrame,而 right 参数代表放在右边的 DataFrame;how=’inner’ 指的是当左右两个 DataFrame 中存在不重合的 Key 时,取结果的方式:inner 代表交集;Outer 代表并集。最后,on=’Key’ 代表需要合并的键值所在的列,最后整个表格会以该列为准进行归并。

对于两个都含有 key 列的 DataFrame,我们可以这样归并:

  1. left=pd.DataFrame({'key':['k0','k1','k2','k3'],
  2. 'A':['A0','A1','A2','A3'],
  3. 'B':['B0','B1','B2','B3']
  4. })
  5. right=pd.DataFrame({'key':['k0','k1','k2','k3'],
  6. 'C':['C0','C1','C2','C3'],
  7. 'D':['D0','D1','D2','D3']
  8. })
  9. pd.merge(left,right,how="inner",on='key')
key A B C D
0 k0 A0 B0 C0 D0
1 k1 A1 B1 C1 D1
2 k2 A2 B2 C2 D2
3 k3 A3 B3 C3 D3

同时,我们可以传入多个 on 参数,这样就能按多个键值进行归并:

  1. left=pd.DataFrame({'key':['k0','k1','k2','k3'],
  2. 'key2':['k0','k1','k0','k1'],
  3. 'A':['A0','A1','A2','A3'],
  4. 'B':['B0','B1','B2','B3']
  5. })
  6. right=pd.DataFrame({'key':['k0','k1','k2','k3'],
  7. 'key2':['k0','k0','k0','k0'],
  8. 'C':['C0','C1','C2','C3'],
  9. 'D':['D0','D1','D2','D3']
  10. })
  11. pd.merge(left,right,on=['key','key2'])
key key2 A B C D
0 k0 k0 A0 B0 C0 D0
1 k2 k0 A2 B2 C2 D2

连接(Join)

如果你要把两个表连在一起,然而它们之间没有太多共同的列,那么你可以试试 .join() 方法。和 .merge() 不同,连接采用索引作为公共的键,而不是某一列。

  1. left=pd.DataFrame({'A':['A0','A1','A2'],
  2. 'B':['B0','B1','B2']
  3. },
  4. index=['k0','k1','k2']
  5. )
  6. right=pd.DataFrame({'C':['C0','C1','C2'],
  7. 'D':['D0','D1','D2']
  8. },
  9. index=['k0','k1','k2']
  10. )
  11. left.join(right)
A B C D
k0 A0 B0 C0 D0
k1 A1 B1 C1 D1
k2 A2 B2 C2 D2
  1. left.join(right,how="outer")
A B C D
k0 A0 B0 C0 D0
k1 A1 B1 C1 D1
k2 A2 B2 C2 D2

同样,inner 代表交集,Outer 代表并集。

数值处理

查找不重复的值

不重复的值,在一个 DataFrame 里往往是独一无二,与众不同的。找到不重复的值,在数据分析中有助于避免样本偏差。在 Pandas 里,主要用到 3 种方法:

首先是 .unique() 方法。比如在下面这个 DataFrame 里,查找 col2 列中所有不重复的值:

  1. df=pd.DataFrame({'col1':[1,2,3,4],'col2':[444,555,666,444],'col3':['abc','def','ghl','xyz']})
  2. df.head()
col1 col2 col3
0 1 444 abc
1 2 555 def
2 3 666 ghl
3 4 444 xyz

除了列出所有不重复的值,我们还能用 .nunique() 方法,获取所有不重复值的个数:

  1. df['col2'].unique()
  1. array([444, 555, 666])

除了列出所有不重复的值,我们还能用 .nunique() 方法,获取所有不重复值的个数:

  1. df['col2'].nunique()
  1. 3

此外,还可以用 .value_counts() 同时获得所有值和对应值的计数:

  1. df['col2'].value_counts()
  1. 444 2
  2. 555 1
  3. 666 1
  4. Name: col2, dtype: int64

apply() 方法

.apply()方法,可以对 DataFrame 中的数据应用自定义函数,进行数据处理。比如,我们先定义一个 square() 函数,然后对表中的 col1 列应用这个函数:

  1. def square(x):
  2. return x*x
  3. df['col1'].apply(square)
  1. 0 1
  2. 1 4
  3. 2 9
  4. 3 16
  5. Name: col1, dtype: int64

在上面这个例子中,这个函数被应用到这一列里的每一个元素上。同样,我们也可以调用任意的内置函数。比如对 col3 列取长度 len :

  1. df['col3'].apply(len)
  1. 0 3
  2. 1 3
  3. 2 3
  4. 3 3
  5. Name: col3, dtype: int64

有的时候,你定义了一个函数,而它其实只会被用到一次。那么,我们可以用 lambda 表达式来代替函数定义,简化代码。比如,我们可以用这样的 lambda 表达式代替上面 In[47] 里的函数定义:

  1. df['col1'].apply(lambda x: x*x)
  1. 0 1
  2. 1 4
  3. 2 9
  4. 3 16
  5. Name: col1, dtype: int64
  1. df['col1'] = df['col1'].apply(lambda x: x*x)

获取 DataFrame 的属性

DataFrame 的属性包括列和索引的名字。假如你不确定表中的某个列名是否含有空格之类的字符,你可以通过 .columns 来获取属性值,以查看具体的列名。

  1. df.columns
  1. Index(['col1', 'col2', 'col3'], dtype='object')
  1. df.index
  1. RangeIndex(start=0, stop=4, step=1)

排序

如果想要将整个表按某一列的值进行排序,可以用 .sort_values() :

  1. df.sort_values('col2')
col1 col2 col3
0 1 444 abc
3 4 444 xyz
1 2 555 def
2 3 666 ghl

如上所示,表格变成按 col2 列的值从小到大排序。要注意的是,表格的索引 index 还是对应着排序前的行,并没有因为排序而丢失原来的索引数据。

查找空值

假如你有一个很大的数据集,你可以用 Pandas 的 .isnull() 方法,方便快捷地发现表中的空值:

  1. df.isnull()
col1 col2 col3
0 False False False
1 False False False
2 False False False
3 False False False

这返回的是一个新的 DataFrame,里面用布尔值(True/False)表示原 DataFrame 中对应位置的数据是否是空值。

数据透视表

在使用 Excel 的时候,你或许已经试过数据透视表的功能了。数据透视表是一种汇总统计表,它展现了原表格中数据的汇总统计结果。Pandas 的数据透视表能自动帮你对数据进行分组、切片、筛选、排序、计数、求和或取平均值,并将结果直观地显示出来。比如,这里有个关于动物的统计表:

  1. data=pd.DataFrame({
  2. 'A':['Dog','Dog','Dog','Goat','Goat','Goat'],
  3. 'B':['Brown','Brown',"Black","Black","Brown","Brown"],
  4. 'C':['x','y','x','y','x','y'],
  5. 'D':[1,3,2,5,4,1]
  6. })
  7. data
A B C D
0 Dog Brown x 1
1 Dog Brown y 3
2 Dog Black x 2
3 Goat Black y 5
4 Goat Brown x 4
5 Goat Brown y 1

Pandas 数据透视表的语法是 .pivot_table(data, values='', index=[''], columns=['']) ,其中 values 代表我们需要汇总统计的数据点所在的列,index 表示按该列进行分组索引,而 columns 则表示最后结果将按该列的数据进行分列。你可以在 Pandas 的官方文档 中找到更多数据透视表的详细用法和例子。

于是,我们按上面的语法,给这个动物统计表创建一个数据透视表:

  1. pd.pivot_table(data,values='D',index=['A','B'],columns='C')
C x y
A B
Dog Black 2.0 NaN
Brown 1.0 3.0
Goat Black NaN 5.0
Brown 4.0 1.0

或者也可以直接调用 df 对象的方法:

  1. data.pivot_table(values='D',index=['A','B'],columns='C')
C x y
A B
Dog Black 2.0 NaN
Brown 1.0 3.0
Goat Black NaN 5.0
Brown 4.0 1.0

导入导出数据

采用类似 pd.read_ 这样的方法,你可以用 Pandas 读取各种不同格式的数据文件,包括 Excel 表格、CSV 文件、SQL 数据库,甚至 HTML 文件等。

读取 CSV 文件

简单地说,只要用 pd.read_csv() 就能将 CSV 文件里的数据转换成 DataFrame 对象:

一文读懂Pandas数据分析 - 图3

指定编码格式和分隔符,分隔符默认是用逗号

  1. df= pd.read_csv('example.csv', encoding='gbk', sep=',')

写入 CSV 文件

将 DataFrame 对象存入 .csv 文件的方法是 .to_csv(),例如,我们先创建一个 DataFrame 对象:

一文读懂Pandas数据分析 - 图4

然后我们将这个 DataFrame 对象存成 ‘New_dataframe’ 文件,Pandas 会自动在磁盘上创建这个文件。

一文读懂Pandas数据分析 - 图5

这里传入 index=False 参数是因为不希望 Pandas 把索引列的 0~5 也存到文件中。

为了确保数据已经保存好了,你可以试试用 pd.read_csv(‘New_dataframe’) ,把这个文件的内容读取出来看看。

读取 Excel 表格文件

Excel 文件是一个不错的数据来源。使用 pd.read_excel() 方法,我们能将 Excel 表格中的数据导入 Pandas 中。请注意,Pandas 只能导入表格文件中的数据,其他对象,例如宏、图形和公式等都不会被导入。如果文件中存在有此类对象,可能会导致 pd.read_excel() 方法执行失败。

举个例子,假设我们有一个 Excel 表格 ‘excel_output.xlsx’,然后读取它的数据:

一文读懂Pandas数据分析 - 图6

请注意,每个 Excel 表格文件都含有一个或多个工作表,传入 sheet_name=’Sheet1’ 这样的参数,就表示只读取 ‘excel_output.xlsx’ 中的 Sheet1 工作表中的内容。

写入 Excel 表格文件

跟写入 CSV 文件类似,我们可以将一个 DataFrame 对象存成 .xlsx 文件,语法是 .to_excel() :

一文读懂Pandas数据分析 - 图7

和前面类似,把数据存到 ‘excel_output.xlsx’ 文件中:

一文读懂Pandas数据分析 - 图8

读取 HTML 文件中的数据

为了读取 HTML 文件,你需要安装 htmllib5,lxml 以及 BeautifulSoup4 库,在终端或者命令提示符运行以下命令来安装:

一文读懂Pandas数据分析 - 图9

举个例子,我们用让 Pandas 读取这个页面的数据: https://en.wikipedia.org/wiki/Udacity 。由于一个页面上含有多个不同的表格,我们需要通过下标 [0, …, len(tables) - 1] 访问数组中的不同元素。

下面的这个例子,我们显示的是页面中的第 2 个表格:

一文读懂Pandas数据分析 - 图10

结语

恭喜!读到这里,说明你已经看完了这个教程!

如果你已经学完了本文,我想你应该已经拥有足够的知识,可以好好调教 Pandas,做好分析之前的数据准备工作啦。接下来,你需要的是练习,练习,再练习!