1. 安装
首先,需要先安装numpy和pandas环境,参考:https://pandas.pydata.org/
。以下语句检查并确认安装成功。
import numpy as np
import pandas as pd
pd.__version__
pd?
2. Pandas对象
Pandas 有三种基本数据结构:Series、DataFrame 和 Index。
2.1. Series对象
Pandas 的 Series 对象是一个带索引数据构成的一维数组。Series 对象将一组数据和一组索引绑定在一起,我们可以通过 values 属性和 index 属性获取数据。values 属性返回的结果与 NumPy 数组类似;index 属性返回的结果是一个类型为 pd.Index 的类数组对象。
可以像访问Numpy那样来访问Series(序号也是从0开始计数的)。
In [1]: import numpy as py
In [2]: import pandas as pd
In [3]: data = pd.Series([4.57,92,783.23,134,5.6])
In [4]: data
Out[4]:
0 4.57
1 92.00
2 783.23
3 134.00
4 5.60
dtype: float64
In [5]: data.values
Out[5]: array([ 4.57, 92. , 783.23, 134. , 5.6 ])
In [6]: data.index
Out[6]: RangeIndex(start=0, stop=5, step=1)
In [7]: data[2:]
Out[7]:
2 783.23
3 134.00
4 5.60
dtype: float64
In [8]:
Pandas 的 Series 对象比Numpy更加灵活、通用。
两者的主要区别是:NumPy 数组通过隐式定义的整数索引获取数值,而 Pandas 的 Series 对象用一种显式定义的索引与数值关联。也就是说,Numpy的索引是系统自分配的无法更改,但是Series对象是可以手工指定的。
In [9]: ds1 = pd.Series([2,4,6,8], index=['f','i','b','a'])
In [10]: ds1
Out[10]:
f 2
i 4
b 6
a 8
dtype: int64
In [11]: ds1['b']
Out[11]: 6
In [12]: ds2 = pd.Series([1.4,1.8,2.2,2.6],index=[4,7,3,1])
In [13]: ds2
Out[13]:
4 1.4
7 1.8
3 2.2
1 2.6
dtype: float64
Series是特殊的字典,Series 对象其实是一种将类型键映射到一组类型值的数据结构,Pandas Series 的类型信息使得它在某些操作上比 Python 的字典更高效。用字典创建 Series 对象时,其索引默认按照顺序排列。
In [14]: city_code = {'Beijing':'010','Tianjin':'022','Guangzhou':'020',
'Dalian':'0411','Shanghai':'021','Changchun':'0431'}
In [15]: city_se = pd.Series(city_code)
In [16]: city_se
Out[16]:
Beijing 010
Changchun 0431
Dalian 0411
Guangzhou 020
Shanghai 021
Tianjin 022
dtype: object
In [17]: city_se['Dalian']
Out[17]: '0411'
In [18]: city_se['Beijing':'Guangzhou']
Out[18]:
Beijing 010
Changchun 0431
Dalian 0411
Guangzhou 020
dtype: object
2.2. DataFrame对象
DataFrame类似于RDBMS中的Table。DataFrame就可以看作是一种既有灵活的行索引,又有灵活列名的二维数组。
DataFrame有2个常用属性,分别是index 属性和columns 属性。前者可以获取索引标签(行标签);后者是是存放列标签的Index 对象。DataFrame 是特殊的字典,一列映射一个Series 的数据。
DataFrame可以通过以下几种方式来创建:(1)通过单个 Series 对象创建。(2)通过字典列表创建。(3)通过 Series 对象字典创建。(4)通过NumPy 二维数组创建。(5)通过 NumPy 结构化数组创建。
In [3]: order_count = {'nanjing':201614, 'shanghai':266105, 'hangzhou':21477,
'zhengzhou':11275 , 'beijing':2271}
In [4]: price = {'nanjing':201614, 'shanghai':266105, 'hangzhou':21477,
'zhengzhou':11275 , 'beijing':2271}
In [5]: order_count_se = pd.Series(order_count)
In [6]: price_se = pd.Series(price)
In [7]: df1 = pd.DataFrame({'order_cnt': order_count_se , 'price':price_se })
In [8]: df1.index
Out[8]: Index([u'beijing', u'hangzhou', u'nanjing', u'shanghai',
u'zhengzhou'], dtype='object')
In [9]: df1.columns
Out[9]: Index([u'order_cnt', u'price'], dtype='object')
In [10]: df1
Out[10]:
order_cnt price
beijing 2271 2271
hangzhou 21477 21477
nanjing 201614 201614
shanghai 266105 266105
zhengzhou 11275 11275
In [11]: df2 = pd.DataFrame(order_count_se, columns = ['order_count'])
In [12]: df2
Out[12]:
order_count
beijing 2271
hangzhou 21477
nanjing 201614
shanghai 266105
zhengzhou 11275
In [13]: df3 = pd.DataFrame([ {'a' : i , 'b' : 3*i} for i in range(4) ])
In [14]: df3
Out[14]:
a b
0 0 0
1 1 3
2 2 6
3 3 9
In [15]: df4 = pd.DataFrame(np.random.rand(3,2),
columns=['A','B'],index=['a','b','c'])
In [16]: df4
Out[16]:
A B
a 0.830527 0.925459
b 0.210633 0.806638
c 0.604675 0.222498
2.3. Index对象
可以将Index视为一个不可变数组或有序集合。当作为不可变数组时,一般数组的访问方式(例如切片等)对Index适用,与数组的最大区别是Index对象不可更改。当作为集合时,Index也可以做交集、并集等常规操作。
In [21]: ind1 = pd.Index([1,2,3,5,18,27])
In [22]: ind2 = pd.Index([2,3,7,18,56,345])
In [23]: ind1[3]
Out[23]: 5
In [24]: ind1[::2]
Out[24]: Int64Index([1, 3, 18], dtype='int64')
In [25]: ind1[2] = 8
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
----> 1 ind1[2] = 8
/Users/natty/anaconda2/lib/python2.7/site-packages/pandas/core/indexes/base.pyc
in __setitem__(self, key, value)
2063
2064 def __setitem__(self, key, value):
-> 2065 raise TypeError("Index does not support mutable operations")
2066
2067 def __getitem__(self, key):
TypeError: Index does not support mutable operations
In [26]: ind1 & ind2
Out[26]: Int64Index([2, 3, 18], dtype='int64')
In [27]: ind1 | ind2
Out[27]: Int64Index([1, 2, 3, 5, 7, 18, 27, 56, 345], dtype='int64')
In [28]: ind1 ^ ind2
Out[28]: Int64Index([1, 5, 7, 27, 56, 345], dtype='int64')
3. 数据取值和访问
3.1. Series数值访问
Series的访问既可以作为字典,也可以作为一维数组。数据访问的方法,可以参考Numpy的访问方式,这里不赘述。
In [32]: list(order_count_se.items())
Out[32]:
[('beijing', 2271),
('hangzhou', 21477),
('nanjing', 201614),
('shanghai', 266105),
('zhengzhou', 11275)]
In [33]: order_count_se.keys()
Out[33]: Index([u'beijing', u'hangzhou', u'nanjing', u'shanghai',
u'zhengzhou'], dtype='object')
In [36]: 'shanghai' in order_count_se # 验证key是否在Series中
Out[36]: True
In [37]: order_count_se['tianjin'] = 5690 #可以增加键值对方式修改Series
In [38]: order_count_se
Out[38]:
beijing 2271
hangzhou 21477
nanjing 201614
shanghai 266105
zhengzhou 11275
tianjin 5690
dtype: int64
3.2. 隐式索引和显式索引
如果Series的显式索引是整数,那么在访问时,很容易混淆。例如下边的例子:
In [3]: se_001 = pd.Series(['e','a','z','x','f','c','d'] , index = [1,3,5,4,2,7,6])
In [4]: se_001
Out[4]:
1 e
3 a
5 z
4 x
2 f
7 c
6 d
dtype: object
In [5]: se_001[5]
Out[5]: 'z'
In [6]: se_001[2:4]
Out[6]:
5 z
4 x
dtype: object
从上边的例子总结得出,python的默认规则是:在单个访问时,使用的显式索引,而在切片时,使用的是隐式索引,很容易混淆!python提供了loc、iloc和ix三种索引器。
loc表示:表示取值和切片都是显式的。iloc 属性,表示取值和切片都是隐式索引。ix是loc和iloc的混合形式,应用于dataFrame(使用例子在3.3节)。
In [7]: se_001.loc[5]
Out[7]: 'z'
In [8]: se_001.loc[2:4]
Out[8]: Series([], dtype: object)
In [14]: se_001.iloc[5]
Out[14]: 'c'
In [15]: se_001.iloc[2:4]
Out[15]:
5 z
4 x
dtype: object
3.3. DataFrame读取
dataframe可以通过对列名进行字典形式(dictionary-style)的取值获取数据。可以把 DataFrame 看成是一个增强版的二维数组,用 values 属性按行查看数组数据。ix 索引器对于整数索引的处理和之前在 Series 对象中介绍的一样,都容易让人混淆。
In [9]: df1
Out[9]:
order_cnt price
beijing 2271 6984
hangzhou 21477 103019
nanjing 201614 490291034
shanghai 266105 786594932
zhengzhou 11275 93329
In [10]: df1['price']
Out[10]:
beijing 6984
hangzhou 103019
nanjing 490291034
shanghai 786594932
zhengzhou 93329
Name: price, dtype: int64
In [11]: df1['price_per_or'] = df1['price']/df1['order_cnt']
In [12]: df1
Out[12]:
order_cnt price price_per_or
beijing 2271 6984 3.075297
hangzhou 21477 103019 4.796713
nanjing 201614 490291034 2431.830299
shanghai 266105 786594932 2955.956979
zhengzhou 11275 93329 8.277517
In [13]: df1.values
Out[13]:
array([[2.27100000e+03, 6.98400000e+03, 3.07529723e+00],
[2.14770000e+04, 1.03019000e+05, 4.79671276e+00],
[2.01614000e+05, 4.90291034e+08, 2.43183030e+03],
[2.66105000e+05, 7.86594932e+08, 2.95595698e+03],
[1.12750000e+04, 9.33290000e+04, 8.27751663e+00]])
In [14]: df1.T
Out[14]:
beijing hangzhou nanjing shanghai zhengzhou
order_cnt 2271.000000 21477.000000 2.016140e+05 2.661050e+05 11275.000000
price 6984.000000 103019.000000 4.902910e+08 7.865949e+08 93329.000000
price_per_or 3.075297 4.796713 2.431830e+03 2.955957e+03 8.277517
In [15]: df1.values[0]
Out[15]: array([2.27100000e+03, 6.98400000e+03, 3.07529723e+00])
In [16]: df1.iloc[0:2,1:4]
Out[16]:
price price_per_or
beijing 6984 3.075297
hangzhou 103019 4.796713
In [17]: df1.ix[0:4,'p':'z']
/Users/natty/anaconda2/bin/ipython:1: DeprecationWarning:
.ix is deprecated. Please use
.loc for label based indexing or
.iloc for positional indexing
See the documentation here:
http://pandas.pydata.org/pandas-docs/stable/indexing.html#ix-indexer-is-deprecated
#!/Users/natty/anaconda2/bin/python
Out[17]:
price price_per_or
beijing 6984 3.075297
hangzhou 103019 4.796713
nanjing 490291034 2431.830299
shanghai 786594932 2955.956979
In [18]: df1['beijing':'Shanghai'] #该方式对行进行索引
Out[18]:
order_cnt price price_per_or
beijing 2271 6984 3.075297
hangzhou 21477 103019 4.796713
nanjing 201614 490291034 2431.830299
shanghai 266105 786594932 2955.956979
In [19]: df1['order_cnt':'price_per_or']
Out[19]:
Empty DataFrame
Columns: [order_cnt, price, price_per_or]
Index: []
In [20]: df1[1:3]
Out[20]:
order_cnt price price_per_or
hangzhou 21477 103019 4.796713
nanjing 201614 490291034 2431.830299
4. Pandas数值运算
4.1 索引对齐
对于一元运算(像函数与三角函数),这些通用函数将在输出结果中保留索引和列标签(很简单,所有元素做相应运算并返回);而对于二元运算(如加法和乘法),Pandas 在传递通用函数时会自动对齐索引进行计算。
当在两个 Series 或 DataFrame 对象上进行二元计算时,Pandas 会在计算过程中对齐两个对象的索引。如果想给缺失数值指定一个默认值,需要使用add来替代+,并指定fill_value:
In [21]: se_at_01 = pd.Series([7,6,9,12],index=[2,7,2,5])
In [22]: se_at_01
Out[22]:
2 7
7 6
2 9
5 12
dtype: int64
In [23]: se_at_02 = pd.Series([13],index=[2])
In [24]: se_at_02
Out[24]:
2 13
dtype: int64
In [25]: se_at_01 + se_at_02
Out[25]:
2 20.0
2 22.0
5 NaN
7 NaN
dtype: float64
In [26]: se_at_01.add(se_at_02,fill_value=-99)
Out[26]:
2 20.0
2 22.0
5 -87.0
7 -93.0
dtype: float64
4.2 dataframe对齐
两个对象的行列索引可以是不同顺序的,结果的索引会自动按顺序排列。
In [34]: df_sa_001 = pd.DataFrame(rng.randint(0,10,(2,2)),
columns=['C','D'],index=[1,2])
In [35]: df_sa_001
Out[35]:
C D
1 8 4
2 7 1
In [37]: df_sa_002 = pd.DataFrame(rng.randint(0,10,(3,3)),
columns=['D','C','A'],index=[3,1,2])
In [38]: df_sa_002
Out[38]:
D C A
3 1 1 1
1 2 9 4
2 6 2 0
In [39]: df_sa_001 + df_sa_002
Out[39]:
A C D
1 NaN 17.0 6.0
2 NaN 9.0 7.0
3 NaN NaN NaN
4.3 dataframe与Series计算
DataFrame 和 Series 的运算规则,与NumPy 中二维数组与一维数组的运算规则是一样的。需要使用广播原则,那么默认地,会按行计算。如果想要按列运算,需要使用参数axis = 0 。
In [42]: df_sb_001 =pd.DataFrame(rng.randint(20,size=(3,4)),columns=list('QUIK'))
In [43]: df_sb_001
Out[43]:
Q U I K
0 19 7 17 5
1 12 9 11 10
2 1 16 7 4
In [49]: se_sb_002 = pd.Series(rng.randint(20,size=(3)),index =list('QUI'))
In [52]: se_sb_002
Out[52]:
Q 11
U 10
I 2
dtype: int64
In [50]: df_sb_001 - se_sb_002
Out[50]:
I K Q U
0 15.0 NaN 8.0 -3.0
1 9.0 NaN 1.0 -1.0
2 5.0 NaN -10.0 6.0
In [55]: df_sb_001 - df_sb_001.iloc[0] #按行计算
Out[55]:
Q U I K
0 0 0 0 0
1 -7 2 -6 5
2 -18 9 -10 -1
In [60]: df_sb_001.subtract(df_sb_001['Q'],axis=0) #按列计算
Out[60]:
Q U I K
0 0 -12 -2 -14
1 0 -3 -1 -2
2 0 15 6 3
注意:DataFrame访问行可以使用loc,但是访问列,只能是df['col']这种形式了。
5. 缺失值
缺失值有三种形式:null、NaN 或 NA。
处理缺失值,一般有两种方法:一种方法是通过一个覆盖全局的掩码表示缺失值,另一种方法是用一个标签值(sentinel value)表示缺失值。
掩码是利用一个跟原来一样大小的矩阵,用0或者1表示某个元素缺失。标签值是利用一个特殊字符例如NaN表示缺失。
Pandas 选择用标签方法表示缺失值,包括两种 Python 原有的缺失值:浮点数据类型(包括整型)的 NaN 值,以及 Python的 None对象。
NaN(全称 Not a Number,不是一个数字)
In [69]: vals_sc_001 = np.array([51,14,None,78])
In [70]: vals_sc_001
Out[70]: array([51, 14, None, 78], dtype=object)
In [71]: vals_sc_001.sum()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
----> 1 vals_sc_001.sum()
/Users/natty/anaconda2/lib/python2.7/site-packages/numpy/core/_methods.pyc
in _sum(a, axis, dtype, out, keepdims)
30
31 def _sum(a, axis=None, dtype=None, out=None, keepdims=False):
---> 32 return umr_sum(a, axis, dtype, out, keepdims)
33
34 def _prod(a, axis=None, dtype=None, out=None, keepdims=False):
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
In [72]: vals_sc_002 = np.array([51,14,np.nan,78])
In [73]: vals_sc_002
Out[73]: array([51., 14., nan, 78.])
In [74]: vals_sc_002.sum()
Out[74]: nan
In [75]: vals_sc_002.dtype
Out[75]: dtype('float64')
使用None时,表示一个空的python对象,所以numpy的dtype=object,因为是对象所以在进行大批量计算时,效率会比标量低。使用np.nan时表示标量,效率会高很多。
任何数与np.nan的计算都只会得到np.nan。
对于缺失值,pandas提供了几个有用的API方法,分别是:isnull(),notnull(),dropna(),fillna()。其中,对于dataframe,dropna()方法默认会将包含NaN的整行都drop掉,如果想按照整列drop,增加axis=1参数。
In [78]: df_sc_001 = pd.DataFrame(np.array([[1,43,np.nan,9],
[2,np.nan,0,1],[np.nan,np.nan,3,1]]),columns = list('fast'))
In [79]: df_sc_001
Out[79]:
f a s t
0 1.0 43.0 NaN 9.0
1 2.0 NaN 0.0 1.0
2 NaN NaN 3.0 1.0
In [80]: df_sc_001.isnull()
Out[80]:
f a s t
0 False False True False
1 False True False False
2 True True False False
In [81]: df_sc_001.notnull()
Out[81]:
f a s t
0 True True False True
1 True False True True
2 False False True True
In [82]: df_sc_001.fillna(-999)
Out[82]:
f a s t
0 1.0 43.0 -999.0 9.0
1 2.0 -999.0 0.0 1.0
2 -999.0 -999.0 3.0 1.0
In [83]: df_sc_001.dropna()
Out[83]:
Empty DataFrame
Columns: [f, a, s, t]
Index: []
In [84]: df_sc_001.dropna(axis=0)
Out[84]:
Empty DataFrame
Columns: [f, a, s, t]
Index: []
In [85]: df_sc_001.dropna(axis=1)
Out[85]:
t
0 9.0
1 1.0
2 1.0
6. 层级索引
pandas的MultiIndex提供了多级索引的功能,用元组表示是多级索引的基础。
6.1. 多级索引Series
下面例子,使用元组索引生成Series。筛选2019的索引,非常繁琐。
In [87]: idx_sd_001 = [('beijing',2018),('beijing',2019),('shanghai',2018),
('shanghai',2019),('tianjin',2018),('tianjin',2019),('suzhou',2018),
('suzhou',2019)]
In [92]: se_sd_001 = pd.Series([61,62,68,69,35,39,42,45], index = idx_sd_001)
In [93]: se_sd_001
Out[93]:
(beijing, 2018) 61
(beijing, 2019) 62
(shanghai, 2018) 68
(shanghai, 2019) 69
(tianjin, 2018) 35
(tianjin, 2019) 39
(suzhou, 2018) 42
(suzhou, 2019) 45
dtype: int64
In [95]: se_sd_001[[i for i in se_sd_001.index if i[1] == 2019]]
Out[95]:
(beijing, 2019) 62
(shanghai, 2019) 69
(tianjin, 2019) 39
(suzhou, 2019) 45
dtype: int64
Pandas 的 MultiIndex 类型提供多种实现方法,下边例子使用元组表示实现。
unstack() 方法可以快速将一个多级索引的 Series 转化为普通索引的DataFrame。stack() 方法实现相反的效果。
In [96]: idx_sd_002 = pd.MultiIndex.from_tuples(idx_sd_001)
In [97]: idx_sd_002
Out[97]:
MultiIndex(levels=[[u'beijing', u'shanghai', u'suzhou', u'tianjin'], [2018, 2019]],
labels=[[0, 0, 1, 1, 3, 3, 2, 2], [0, 1, 0, 1, 0, 1, 0, 1]])
In [98]: se_sd_002 = se_sd_001.reindex(idx_sd_002)
In [99]: se_sd_002
Out[99]:
beijing 2018 61
2019 62
shanghai 2018 68
2019 69
tianjin 2018 35
2019 39
suzhou 2018 42
2019 45
dtype: int64
In [100]: se_sd_002[:,2019]
Out[100]:
beijing 62
shanghai 69
tianjin 39
suzhou 45
dtype: int64
In [101]: df_sd_001 = se_sd_002.unstack()
In [102]: df_sd_001
Out[102]:
2018 2019
beijing 61 62
shanghai 68 69
suzhou 42 45
tianjin 35 39
In [103]: se_sd_003 = df_sd_001.stack()
In [104]: se_sd_003
Out[104]:
beijing 2018 61
2019 62
shanghai 2018 68
2019 69
suzhou 2018 42
2019 45
tianjin 2018 35
2019 39
dtype: int64
6.2. 多级索引创建方法
总结一下,创建多级索引的方法包括:
(1)通过一个有不同等级的若干简单数组组成的列表来构建 MultiIndex:pd.MultiIndex.from_arrays。
(2) 多个索引值的元组构成的列表创建 MultiIndex:pd.MultiIndex.from_tuples。
(3)用两个索引的笛卡尔积创建MultiIndex:pd.MultiIndex.from_product。
(4)直接提供 levels和labels创建 MultiIndex(lablels是指每个级别的整数指定每个位置):
In [106]: idx_sd_003 = pd.MultiIndex.from_arrays([['a','a','a','b','b'],
[0,1,2,0,1]])
In [107]: idx_sd_003
Out[107]:
MultiIndex(levels=[[u'a', u'b'], [0, 1, 2]],
labels=[[0, 0, 0, 1, 1], [0, 1, 2, 0, 1]])
In [109]: idx_sd_004 = pd.MultiIndex.from_product([['a','b'],[1,2]])
In [110]: idx_sd_004
Out[110]:
MultiIndex(levels=[[u'a', u'b'], [1, 2]],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
In [112]: idx_sd_005 = pd.MultiIndex.from_tuples([('a',0),('a',1),('a',2),('b',0),
('b',1)])
In [113]: idx_sd_005
Out[113]:
MultiIndex(levels=[[u'a', u'b'], [0, 1, 2]],
labels=[[0, 0, 0, 1, 1], [0, 1, 2, 0, 1]])
In [114]: idx_sd_006 = pd.MultiIndex(levels=[['c','f','z'],[1,6,7,12]],
labels=[[0,0,1,1,2,2],[1,3,0,2,1,2]])
In [119]: idx_sd_006.values
Out[119]:
array([('c', 6), ('c', 12), ('f', 1), ('f', 7), ('z', 6), ('z', 7)],
dtype=object)
In [120]: idx_sd_006.names = ['rank','denk'] #设置多级索引的等级名称
In [126]: df_sd_002 = pd.DataFrame(np.random.randint(6,size=(6)),
index = idx_sd_006,columns=['order_cnt'])
In [127]: df_sd_002
Out[127]:
order_cnt
rank denk
c 6 4
12 5
f 1 1
7 4
z 6 1
7 3
6.3. 多级列索引
上边的例子中,不管是Series还是DataFrame都是按照行来进行多级索引,其实,也可以按列索引,而且非常简单,下边是一个例子(几个学生在2018和2019两次考试的不同科目成绩):
In [130]: idx_sd_007 = pd.MultiIndex.from_product([[2018,2019],
[1,2]],names=['year','time'])
In [134]: idx_sd_008 = pd.MultiIndex.from_product([['Alice','Judy','Bob'],
['Chinese','English']],names = ['name','subject'])
In [137]: df_sd_003=pd.DataFrame(np.random.randint(50,101,
size=(4,6)),index=idx_sd_007,columns=idx_sd_008)
In [138]: df_sd_003
Out[138]:
name Alice Judy Bob
subject Chinese English Chinese English Chinese English
year time
2018 1 94 69 62 85 62 60
2 97 97 100 88 63 84
2019 1 81 85 74 79 68 86
2 90 81 61 91 74 77
In [139]: df_sd_003['Alice']
Out[139]:
subject Chinese English
year time
2018 1 94 69
2 97 97
2019 1 81 85
2 90 81
6.4. 多级索引的取值与切片
需要对多级索引做显示切片操作时,可以使用pd.IndexSlice对象来切,不同级别的维度,拿逗号分割,例如下边例子中的df_sd_003.loc[idx_sd[2018,:],idx_sd['Alice',:]]。其他切片和取值操作与Numpy很类似。
In [140]: se_sd_003 #示例Series
Out[140]:
beijing 2018 61
2019 62
shanghai 2018 68
2019 69
suzhou 2018 42
2019 45
tianjin 2018 35
2019 39
dtype: int64
In [141]: se_sd_003['suzhou',2019]
Out[141]: 45
In [142]: se_sd_003['suzhou']
Out[142]:
2018 42
2019 45
dtype: int64
In [143]: se_sd_003['shanghai':'tianjin']
Out[143]:
shanghai 2018 68
2019 69
suzhou 2018 42
2019 45
tianjin 2018 35
2019 39
dtype: int64
In [144]: se_sd_003[:,2018]
Out[144]:
beijing 61
shanghai 68
suzhou 42
tianjin 35
dtype: int64
In [145]: se_sd_003[se_sd_003>60]
Out[145]:
beijing 2018 61
2019 62
shanghai 2018 68
2019 69
dtype: int64
In [146]: se_sd_003[['tianjin','suzhou']]
Out[146]:
suzhou 2018 42
2019 45
tianjin 2018 35
2019 39
dtype: int64
In [147]: df_sd_003 #示例DataFrame
Out[147]:
name Alice Judy Bob
subject Chinese English Chinese English Chinese English
year time
2018 1 94 69 62 85 62 60
2 97 97 100 88 63 84
2019 1 81 85 74 79 68 86
2 90 81 61 91 74 77
In [149]: df_sd_003['Judy','Chinese']
Out[149]:
year time
2018 1 62
2 100
2019 1 74
2 61
Name: (Judy, Chinese), dtype: int64
In [151]: df_sd_003.iloc[:2,:2] #行列维度序号隐式索引
Out[151]:
name Alice
subject Chinese English
year time
2018 1 94 69
2 97 97
In [152]: df_sd_003.loc[:,('Alice','English')]
Out[152]:
year time
2018 1 69
2 97
2019 1 85
2 81
Name: (Alice, English), dtype: int64
In [156]: idx_sd = pd.IndexSlice
In [160]: df_sd_003.loc[idx_sd[2018,:],idx_sd['Alice',:]]
Out[160]:
name Alice
subject Chinese English
year time
2018 1 94 69
2 97 97
6.5. 多级索引行列转换
如果 MultiIndex 不是有序的索引,那么大多数切片操作都会失败。
如果Series或者DataFrame的索引是未排序的,可以简单地通过sort_index方法来快速排序。
层级数据维度转换的另一种方法是行列标签转换,可以通过reset_index 方法实现
In [162]: se_sf_001 = pd.Series(np.random.randint(9,size=(9)),
index=pd.MultiIndex.from_product([['c','a','b'],[4,1,3]]))
In [163]: se_sf_001
Out[163]:
c 4 0
1 6
3 7
a 4 8
1 0
3 3
b 4 3
1 3
3 6
dtype: int64
In [165]: se_sf_001['a':'b'] #因为无序,切片报错
In [169]: se_sf_002 = se_sf_001.sort_index()
In [170]: se_sf_002
Out[170]:
a 1 0
3 3
4 8
b 1 3
3 6
4 3
c 1 6
3 7
4 0
dtype: int64
In [171]: se_sf_002['a':'b']
Out[171]:
a 1 0
3 3
4 8
b 1 3
3 6
4 3
dtype: int64
In [172]: se_sf_002.unstack(level=0) #按照第一级维度unstack成dataframe
Out[172]:
a b c
1 0 3 6
3 3 6 7
4 8 3 0
In [173]: se_sf_002.unstack(level=1) #按照第二级维度unstack成dataframe
Out[173]:
1 3 4
a 0 3 8
b 3 6 3
c 6 7 0
7. 合并数据集(concat和append操作)
通过pd.concat()实现pandas对象合并,pd.cancat的所有参数(下面列举的是这些参数的默认值):
pd.concat(objs, axis=0, join='outer', join_axes=None,
ignore_index=False,keys=None, levels=None, names=None,
verify_integrity=False,copy=True)
pd.concat() 可以简单地合并一维的 Series 或 DataFrame 对象,与
np.concatenate() 合并数组一样。
DataFrame 的合并默认都是逐行进行的(axis=0);pd.concat在合并时会保留索引,即使索引是重复的!如果设置 verify_integrity=True,那么生成重复索引时,会触发异常!有时索引无关紧要,那么合并时就可以忽略它们,可以通过设置 ignore_index 参数来实现。默认的合并方式是对所有输入列进行并集合并(join='outer'),当然也可以用 join='inner' 实现对输入列的交集合并。下面是一个实现合并的例子:
def make_df(str_d, ind):
data = {c:[str(c) + str(i) for i in ind] for c in str_d}
df = pd.DataFrame(data,index=ind)
return df
ser_1 = pd.Series(list('ZERA'), index =[1,2,3,4])
ser_2 = pd.Series(list('FORD'), index =[9,10,12,14])
ser_con_1 = pd.concat([ser_1,ser_2])
ser_con_1
df_1 = make_df('AB',[1,2])
df_2 = make_df('CD',[3,4])
#DataFrame 的合并默认都是逐行进行的(axis=0)
df_con_1 = pd.concat([df_1,df_2],sort=False)
df_3 = make_df('AB', [0, 1])
df_4 = make_df('CD', [0, 1])
#axis=1修改成按列merge
df_con_2 = pd.concat([df_3,df_4],axis=1,sort=False) #按列来合并
#verify_integrity=True会验证索引重复,所以会报错。
#df_con_3 = pd.concat([df_3,df_4],verify_integrity=True,sort=False)
#会忽略,merge的pd的索引,生成新索引。
df_con_4 = pd.concat([df_3,df_4],ignore_index=True,sort=False)
df_con_5 = pd.concat([df_3,df_4], keys=['x','y'], sort=False) #增加多级索引
df_5 = make_df('EFG',[2,3,5])
df_6 = make_df('FGH',[1,4,6])
# 默认: join ='outer'
df_con_6 = pd.concat([df_5,df_6],sort=False,join ='outer')
# join ='inner',按列找交集。
df_con_7 = pd.concat([df_5,df_6],sort=False,join ='inner')
#另一种合并方式是直接确定结果使用的列名,设置 join_axes 参数,里面是索引对象构成的列表
df_con_8 = pd.concat([df_5,df_6],sort=False,join_axes =[df_5.columns[0:2]])
df_con_8
8. 合并数据集(合并与连接)
Pandas 的基本特性之一就是高性能的内存式数据连接(join)与合并(merge)操作。
8.1 直接数据合并
pd.merge() 实现的功能基于关系代数(relational algebra)的一部分。 pd.merge() 函数实现了三种数据连接的类型:一对一、多对一和多对多。pd.merge()会自动识别2个dataframe共有的列,并以这个列进行关联。
df1 = pd.DataFrame({'employee': ['Bob', 'Jake', 'Lisa', 'Sue'],
'group': ['Accounting', 'Engineering', 'Engineering', 'HR']})
df2 = pd.DataFrame({'employee': ['Lisa', 'Bob', 'Jake', 'Sue'],
'hire_date': [2004, 2008, 2012, 2014]})
df3 = pd.merge(df1,df2) #一对一关联
df4 = pd.DataFrame({'group': ['Accounting', 'Engineering', 'HR'],
'supervisor': ['Carly', 'Guido', 'Steve']})
df5 = pd.merge(df3,df4) #多对一关联
df6 = pd.DataFrame({'group': ['Accounting', 'Accounting','Engineering', 'Engineering', 'HR', 'HR'],
'skills': ['math', 'spreadsheets', 'coding', 'linux','spreadsheets', 'organization']})
pd.merge(df5,df6) #多对多关联
8.2 指定合并关联键
上边的例子中,关联的两个dataframe具有相同名称的列,pandas会直接按同名列合并,由于两个输入要合并的列通常都不是同名的,因此 pd.merge() 提供了一些参数处理这个问题。
1.最简单的方法就是直接将参数 on 设置为一个列名字符串或者一个包含多列名称的列表,这个参数只能在两个 DataFrame 有共同列名的时候才可以使用。
df1 = pd.DataFrame({'employee': ['Bob', 'Jake', 'Lisa', 'Sue'],
'group': ['Accounting', 'Engineering', 'Engineering', 'HR']})
df2 = pd.DataFrame({'employee': ['Lisa', 'Bob', 'Jake', 'Sue'],
'hire_date': [2004, 2008, 2012, 2014]})
df3 = pd.merge(df1,df2,on='employee') #一对一关联
df4 = pd.DataFrame({'group': ['Accounting', 'Engineering', 'HR'],
'supervisor': ['Carly', 'Guido', 'Steve']})
df5 = pd.merge(df3,df4,on='group') #多对一关联
df6 = pd.DataFrame({'group': ['Accounting', 'Accounting','Engineering', 'Engineering', 'HR', 'HR'],
'skills': ['math', 'spreadsheets', 'coding', 'linux','spreadsheets', 'organization']})
df7 = pd.merge(df5,df6,on='group') #多对多关联
df8 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'],
'salary': [70000, 80000, 120000, 90000]})
# left_on指定左DataFrame的关联键,right_on指定右DataFrame的关联键
# drop删除掉 employee或者name这2个重复的键,需要指定按列(axis=1)drop
df9 = pd.merge(df1,df8,left_on='employee',right_on= 'name').drop('name',axis=1)
df10 = df1.set_index('employee') #修改索引
df11 = df2.set_index('employee') #修改索引
# 通过2个dataframe的索引关联(left_index=True表名左边dataframe使用索引关联)
df12 = pd.merge(df10,df11,left_index =True, right_index =True)
#当2个dataframe通过索引关联时,可以简单的使用join()来完成关联,dataframe的join()方法
df13 = df10.join(df11)
#如果想将索引与列混合使用,那么可以通过结合 left_index 与right_on,或者结合 left_on 与 right_index 来实现
df14 = pd.merge(df2, df10, left_on='employee', right_index=True)
df15 = pd.DataFrame({'name': ['Peter', 'Paul', 'Mary'],'food': ['fish', 'beans', 'bread']},columns=['name', 'food'])
df16 = pd.DataFrame({'name': ['Mary', 'Joseph'],'drink': ['wine', 'beer']},columns=['name', 'drink'])
df17 = pd.merge(df15,df16,how='inner')
df18 = pd.merge(df15,df16,how='left')
df19 = pd.merge(df15,df16,how='right')
df20 = pd.merge(df15,df16,how='outer')
df21 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'],'rank': [1, 2, 3, 4]})
df22 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'],'rank': [3, 1, 4, 2]})
#由于输出结果中有两个重复的列名,因此 pd.merge() 函数会自动为它们增加后缀 _x 或 _y
df23 = pd.merge(df21,df22,on='name')
#如果不想要默认的_x和_y,可以通过suffixes来指定不同的后缀列名
df24 = pd.merge(df21,df22,on='name', suffixes=['_L','_R'])
df24.query("rank_L == 4 | rank_R == 3")