在Pandas基本使用简单了介绍了一下Pandas的基本使用和用法,大家如果没有一点基础的同学可以先看一下那篇文章。今天我们来讲解一下Pandas的高级用法。
在讲解Pandas高级特性之前,我们先来学习一下Numpy。Numpy是高性能计算和数据分析的基础包,一种ndarray的多维数组对象并且是一个同构的数据多维容器。创建和操作一个多维数组,我们来看一下简单的代码片段。
arr = np.arange(10,dtype=np.float32)
# np.zero,np.ones,np.empty等等
如果没有指定dtype,值得注意一点的是在后面如果要通过astype类型的话,astype是需要赋值数据的,而通过切片是不需要复制数据。切片是原始数据的一个视图,是直接映射到原始数据,对视图的任何修改也是直接映射到原始数据。如果想要复制数据,可以通过copy的包复制数据。
In [17]: names = np.array(['name','bol','eric','old'])
In [18]: data = np.random.randn(4,3)
In [19]: data
Out[19]:
array([[-0.37669205, 0.0604502 , 0.45811449],
[ 1.04738375, -0.32027076, 1.57581797],
[-1.30180985, -1.34583117, 0.13331215],
[-0.43754032, -1.55706331, 0.69756061]])
In [20]: data[names=='bol']
Out[21]: array([[ 1.04738375, -0.32027076, 1.57581797]])
Python关键字中and和or在布尔数组中是无效的,如果想选取除了某个特定字段可以通过!=来选择,多个条件判断时采用&和|运算符完成。numpy.where等同于三元表达式x if condition else y的矢量化版本。
In [28]: mask = (names=='bol') | (names=='old')
In [29]: mask
Out[29]: array([False, True, False, True], dtype=bool)
In [30]: data[mask]
Out[30]:
array([[ 1.04738375, -0.32027076, 1.57581797],
[-0.43754032, -1.55706331, 0.69756061]])
Numpy的切片和花式索引完全不是一回事,很多人都混淆了概念和用法。我们先来看一下切片的用法,切片的用法和一维列表的切片也是一样的。
In [32]: data = np.arange(16).reshape(4,4)
In [33]: data
Out[33]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
In [34]: data[:2,:1]
Out[34]:
array([[0],
[4]])
In [35]: data[1:3,2:4]
Out[35]:
array([[ 6, 7],
[10, 11]])
Fancy Indexing(花式索引),利用整数数组进行索引,比如:
In [38]: data[[1,2,0,3]]
Out[38]:
array([[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[ 0, 1, 2, 3],
[12, 13, 14, 15]])
In [39]: data[[1,2,0,3]][:,[0,3,1,2]]
Out[39]:
array([[ 4, 7, 5, 6],
[ 8, 11, 9, 10],
[ 0, 3, 1, 2],
[12, 15, 13, 14]])
花式索引和切片不一样,花式索引将数据复制到新的array中。
Numpy的转置是数据重塑的一种特殊形式,它返回的是源数据的视图,可以通过transpose和T来实现,不会进行任何复制操作。
In [42]: data
Out[42]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
In [43]: data.T
Out[43]:
array([[ 0, 4, 8, 12],
[ 1, 5, 9, 13],
[ 2, 6, 10, 14],
[ 3, 7, 11, 15]])
我们先来确定numpy的唯一化的集合,例如:
In [51]: names = np.array(['name','bol','eric','old','name','bol'])
In [52]: names
Out[52]:
array(['name', 'bol', 'eric', 'old', 'name', 'bol'],
dtype='|S4')
In [53]: np.unique(names)
Out[53]:
array(['bol', 'eric', 'name', 'old'],
dtype='|S4')
In [54]: data1 = np.array([2,3,5,6,7,8,1,3,6])
In [55]: np.in1d(data1,[2,6])
Out[55]: array([ True, False, False, True, False, False, False, False, True], dtype=bool)
这里就不一一列举,很多操作可以查看API。
Pandas是基于Numpy构建的,它使得数据分析工作变得更快更简单。Pandas有两种结构Series和DataFrame,他们数据表现是索引在左边,值在右边。。
Serise既可以看成是一个一维的numpy也可以看成是一个定长的有序字典。
In [64]: a = Series([1,2,3,4])
In [65]: b = Series(np.arange(10))
In [67]: a
Out[67]:
0 1
1 2
2 3
3 4
dtype: int64
In [68]: data = {"beijing":2300,"shanghai":2200,"shandong":2221}
In [69]: ser = Series(data)
In [70]: ser
Out[70]:
beijing 2300
shandong 2221
shanghai 2200
dtype: int64
In [75]: data1={"beijing":1100,"shanghai":2100,"tianjing":2100}
In [76]: ser2 = Series(data1)
In [84]: ser+ser2
Out[84]:
beijing 3400.0
shandong NaN
shanghai 4300.0
tianjing NaN
dtype: float64
Series一个最主要的特性是能自动对齐数据。
DataFrame是一个表格型数据。
In [100]: frame
Out[100]:
b d e
ut 0 1 2
oh 3 4 5
te 6 7 8
or 9 10 11
In [102]: ser = frame.iloc[0]
In [103]: frame-ser
Out[103]:
b d e
ut 0 0 0
oh 3 3 3
te 6 6 6
or 9 9 9
In [105]: ser2 = Series(range(3),index=list('def'))
In [107]: frame+ser2
Out[107]:
b d e f
ut NaN 1.0 3.0 NaN
oh NaN 4.0 6.0 NaN
te NaN 7.0 9.0 NaN
or NaN 10.0 12.0 NaN
将函数应用到各行或各列是通过apply方法实现。
当多个数据集进行合并(merge)和连接(join)都是通过一个或者多个键连接起来,多个DataFrame的合并操作是通过pandas.merge来实现的。DataFrame的合并有多种连接方式,merge默认采用inner连接方式。还有left,right以及outer连接。外连接求取的是键的并集,组合了左连接和右连接。
In [15]: df1 = DataFrame({'key':list('bbacaab'),'data1':range(7)})
In [16]: df2 = DataFrame({'key':list('abd'),'data2':range(3)})
In [17]: pd.merge(df1,df2)====pd.merge(df1,df2,on='key')
Out[17]:
data1 key data2
0 0 b 1
1 1 b 1
2 6 b 1
3 2 a 0
4 4 a 0
5 5 a 0
In [18]: pd.merge(df1,df2,how='outer')
Out[18]:
data1 key data2
0 0.0 b 1.0
1 1.0 b 1.0
2 6.0 b 1.0
3 2.0 a 0.0
4 4.0 a 0.0
5 5.0 a 0.0
6 3.0 c NaN
7 NaN d 2.0
这是一种多对一的合并,df1中有多个被标记的数据行(a和b),而df2中key的列的每个值而仅对应一个,这时候调用merge即可,也可以通过on来指定重叠的列名。如果两个dataframe的key不一样,可以分别指定。
In [27]: df1 = DataFrame({'lkey':list('bbacaab'),'data1':range(7)})
In [28]: df2 = DataFrame({'rkey':list('abd'),'data2':range(3)})
In [29]: pd.merge(df1,df2,left_on='lkey',right_on='rkey')
Out[29]:
data1 lkey data2 rkey
0 0 b 1 b
1 1 b 1 b
2 6 b 1 b
3 2 a 0 a
4 4 a 0 a
5 5 a 0 a
如果是一种多对多的合并,比如如下格式:
In [34]: df1 = DataFrame({'key':list('bbacaab'),'data1':range(7)})
In [35]: df2 = DataFrame({'key':list('ababd'),'data2':range(5)})
In [36]: pd.merge(df1,df2,on='key',how='left')
Out[36]:
data1 key data2
0 0 b 1.0
1 0 b 3.0
2 1 b 1.0
3 1 b 3.0
4 2 a 0.0
5 2 a 2.0
6 3 c NaN
7 4 a 0.0
8 4 a 2.0
9 5 a 0.0
10 5 a 2.0
11 6 b 1.0
12 6 b 3.0
In [37]: pd.merge(df1,df2,on='key',how='right')
Out[37]:
data1 key data2
0 0.0 b 1
1 1.0 b 1
2 6.0 b 1
3 0.0 b 3
4 1.0 b 3
5 6.0 b 3
6 2.0 a 0
7 4.0 a 0
8 5.0 a 0
9 2.0 a 2
10 4.0 a 2
11 5.0 a 2
12 NaN d 4
In [38]: pd.merge(df1,df2,on='key')
Out[38]:
data1 key data2
0 0 b 1
1 0 b 3
2 1 b 1
3 1 b 3
4 6 b 1
5 6 b 3
6 2 a 0
7 2 a 2
8 4 a 0
9 4 a 2
10 5 a 0
11 5 a 2
In [39]: pd.merge(df1,df2,on='key',how='outer')
Out[39]:
data1 key data2
0 0.0 b 1.0
1 0.0 b 3.0
2 1.0 b 1.0
3 1.0 b 3.0
4 6.0 b 1.0
5 6.0 b 3.0
6 2.0 a 0.0
7 2.0 a 2.0
8 4.0 a 0.0
9 4.0 a 2.0
10 5.0 a 0.0
11 5.0 a 2.0
12 3.0 c NaN
13 NaN d 4.0
多对多产生的是行的笛卡尔积,如果要按照多个column进行合并可以通过on=[‘key1’,’key2’]
DataFrame中的连接键位于其索引中,这种情况需要传入left_index=True和right_index=True来说明连接的键,对于层次化的数据多个键合并时,按需通过left_on或者right_on=[‘key1’,’key2’]来合并。
In [57]: left1 = DataFrame({'key':list('abaabc'),'value':range(6)})
In [58]: right1 = DataFrame({'group_val':[3.5,7]},index=list('ab'))
In [59]: right1
Out[59]:
group_val
a 3.5
b 7.0
In [60]: left1
Out[60]:
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
In [61]: pd.merge(left1,right1,left_on='key',right_index=True)
Out[61]:
key value group_val
0 a 0 3.5
2 a 2 3.5
3 a 3 3.5
1 b 1 7.0
4 b 4 7.0
对于索引的合并,建议采用join的方式来进行合并。
In [73]: left1 = DataFrame({'key':list('abaabc'),'value':range(6)},index=list('abcdef'))
In [74]: right1 = DataFrame({'val':[3.5,7]},index=list('de'))
In [75]: an = DataFrame({'val':[3.5,7]},index=list('de'))
In [79]: left1.join([right1,an])
Out[79]:
key value group_val val
a a 0 3.5 NaN
b b 1 7.0 NaN
c a 2 NaN NaN
d a 3 NaN 3.5
e b 4 NaN 7.0
f c 5 NaN NaN
In [86]: s1 = Series(data=[1,2,3],index=list('abc'))
In [87]: s2 = Series([1,2],index=list('de'))
In [88]: s3 = Series([3,4],index=list('fg'))
In [89]: pd.concat([s1,s2,s3],axis=0)
Out[89]:
a 1
b 2
c 3
d 1
e 2
f 3
g 4
dtype: int64
In [90]: pd.concat([s1,s2,s3],axis=1)
Out[90]:
0 1 2
a 1.0 NaN NaN
b 2.0 NaN NaN
c 3.0 NaN NaN
d NaN 1.0 NaN
e NaN 2.0 NaN
f NaN NaN 3.0
g NaN NaN 4.0
In [96]: s4=pd.concat([s1*5,s3])
In [97]: s4
Out[97]:
a 5
b 10
c 15
f 3
g 4
dtype: int64
In [98]: pd.concat([s1,s4],axis=1,join='inner')
Out[98]:
0 1
a 1 5
b 2 10
c 3 15
In [99]: pd.concat([s1,s4],axis=1,join_axes=[['a','b','c']])
Out[99]:
0 1
a 1 5
b 2 10
c 3 15
也可以通过join方式来指定inner或者outer来获取交集和并集,你也可以通过join_axes指定其他轴上的索引。 在concat之后结果区分不开,如何让他区分开结果?可以通过keys来实现,比如:
In [104]: result = pd.concat([s1,s4],join='inner',keys=['one','two'])
Out[104]:
one a 1
b 2
c 3
two a 5
b 10
c 15
f 3
g 4
dtype: int64
In [108]: result.unstack()
Out[108]:
a b c f g
one 1.0 2.0 3.0 NaN NaN
two 5.0 10.0 15.0 3.0 4.0
In [105]: result1 = pd.concat([s1,s4],axis=1,join='inner',keys=['one','two'])
Out[105]:
one two
a 1 5
b 2 10
c 3 15
In [109]: result1.unstack()
Out[109]:
one a 1
b 2
c 3
two a 5
b 10
c 15
dtype: int64
这样可以把一个Series结构轻松的转化为DataFrame结构来处理,可以相互的转换。对于DataFrame结构也可以通过concat来合并数据。如果两个数据集的索引存在重叠怎么办?可以通过combine——frist进行打补丁。
stack:将数据的列旋转为行,默认会过滤掉缺失的数据,该运算是可逆的。 unstack:将数据的行旋转为列,操作是最内层的,传入分层级别或者名称。
In [23]: data = DataFrame(np.arange(6).reshape((2,3)),index=pd.Index(['Co','Ho'],name='state'),columns=pd.Index(['one','two','three'],name
...: ='number'))
In [24]: data
Out[24]:
number one two three
state
Co 0 1 2
Ho 3 4 5
In [25]: result = data.stack()
Out[25]:
state number
Co one 0
two 1
three 2
Ho one 3
two 4
three 5
dtype: int64
In [28]: result.unstack()
Out[28]:
number one two three
state
Co 0 1 2
Ho 3 4 5
In [30]: result.unstack('state')
Out[30]:
state Co Ho
number
one 0 3
two 1 4
three 2 5
通过stack() 将列数据转换为行,转化为了一个层次化Series。对一个多层次化的Series可以通过unstack()**转化为DataFrame结构。
In [6]: s1=Series(xrange(4),index=list('abcd'))
In [7]: s2=Series(range(4,7,1),index=list('cde'))
In [8]: pd.concat([s1,s2],keys=['one','two'])
Out[8]:
one a 0
b 1
c 2
d 3
two c 4
d 5
e 6
dtype: int64
In [10]: pd.concat([s1,s2],keys=['one','two']).unstack()
Out[10]:
a b c d e
one 0.0 1.0 2.0 3.0 NaN
two NaN NaN 4.0 5.0 6.0
In [19]: result.unstack().stack(dropna=False)
Out[19]:
one a 0.0
b 1.0
c 2.0
d 3.0
e NaN
two a NaN
b NaN
c 4.0
d 5.0
e 6.0
dtype: float64
在通过Pandas处理一些数据时,另一个比较重要的是过滤、清洗以及转换。
In [27]: data = DataFrame({'one':['a']*3+['b']*4,'two':[1,1,2,3,3,4,4]})
In [28]: data
Out[28]:
one two
0 a 1
1 a 1
2 a 2
3 b 3
4 b 3
5 b 4
6 b 4
在上面的数据中会有一些重复的数据,我们需要过滤掉。
In [34]: data.duplicated()
Out[34]:
0 False
1 True
2 False
3 False
4 True
5 False
6 True
dtype: bool
In [35]: data.drop_duplicates()
Out[35]:
one two
0 a 1
2 a 2
3 b 3
5 b 4
In [36]: data.drop_duplicates(['two'])
Out[36]:
one two
0 a 1
2 a 2
3 b 3
5 b 4
```,或者也可以指定去除重复的列。
**duplicated**返回的是各行是否重复布尔值,或者你也可以通过**drop_duplicates**方法去除重复,或者也可以指定去除重复的列。
#### 面元
所谓的面元(bin)亦称为离散化。
```python
In [52]: ages = np.random.randint(100,size=20)
In [53]: ages
Out[53]:
array([50, 99, 37, 90, 9, 33, 26, 34, 97, 75, 46, 44, 17, 23, 15, 25, 63,
8, 39, 54])
In [57]: bins = [0,18,25,35,60,100]
In [58]: cats = pd.cut(ages,bins)
In [59]: cats
Out[59]:
[(35, 60], (60, 100], (35, 60], (60, 100], (0, 18], ..., (18, 25], (60, 100], (0, 18], (35, 60], (35, 60]]
Length: 20
Categories (5, interval[int64]): [(0, 18] < (18, 25] < (25, 35] < (35, 60] < (60, 100]]
In [60]: cats.value_counts()
Out[60]:
(0, 18] 4
(18, 25] 2
(25, 35] 3
(35, 60] 6
(60, 100] 5
dtype: int64
可以有效的处理,还可以通过left/right参数来左右开关闭区间,precision设置小数位数。qcut是对样本进行分位数。
data = DataFrame(np.random.randn(1000,4))
#检查超过3或者-3的异常值
In [78]: data[(np.abs(data)>3).any(1)]
Out[78]:
0 1 2 3
46 -0.658090 -0.207434 3.525865 0.283070
67 0.599947 -3.645860 0.255475 -0.549574
289 -1.559625 0.336788 -3.333767 -1.240685
371 -1.116332 -3.018842 -0.298748 0.406954
396 -3.108915 1.117755 -0.152780 -0.340173
526 1.188742 -3.183867 1.050471 -1.042736
573 -2.214074 -3.140963 -1.509976 -0.389818
738 -0.088202 1.090038 -0.848098 -3.194414
768 0.474358 0.003349 -0.011807 3.023720
797 2.368010 0.452649 -3.481593 0.789944
966 0.164293 3.082067 -0.516982 0.251909
994 -0.843849 3.189940 0.070978 0.516982
#然后可以通过将超过三的值设置到-3到3之间
In [83]: data[(np.abs(data)>3)]=np.cos(data)*3
In [84]: data[(np.abs(data)>3).any(1)]
Out[84]:
Empty DataFrame
Columns: [0, 1, 2, 3]
Index: []
在数据挖掘或者统计学习里面,我们需要将分类变量转换为dummy matrix或者indicator matrix
In [86]: data = DataFrame({'key':list('bbaabc'),'num':range(6)})
In [87]: data
Out[87]:
key num
0 b 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
In [88]: pd.get_dummies(data['key'])
Out[88]:
a b c
0 0 1 0
1 0 1 0
2 1 0 0
3 1 0 0
4 0 1 0
5 0 0 1
In [89]: pd.get_dummies(data['num'])
Out[89]:
0 1 2 3 4 5
0 1 0 0 0 0 0
1 0 1 0 0 0 0
2 0 0 1 0 0 0
3 0 0 0 1 0 0
4 0 0 0 0 1 0
5 0 0 0 0 0 1
In [94]: values = np.random.rand(10)
In [95]: values
Out[95]:
array([ 0.47712303, 0.14542606, 0.91058923, 0.77642134, 0.92337761,
0.50655742, 0.77692242, 0.26667882, 0.94795336, 0.63819667])
In [96]: bins = [0,0.2,0.4,0.6,0.8,1.0]
In [97]: pd.get_dummies(pd.cut(values,bins))
Out[97]:
(0.0, 0.2] (0.2, 0.4] (0.4, 0.6] (0.6, 0.8] (0.8, 1.0]
0 0 0 1 0 0
1 1 0 0 0 0
2 0 0 0 0 1
3 0 0 0 1 0
4 0 0 0 0 1
5 0 0 1 0 0
6 0 0 0 1 0
7 0 1 0 0 0
8 0 0 0 0 1
9 0 0 0 1 0
1.《Python 数据分析》 2.《Python数据挖掘与分析》 3.《利用Python进行数据分析》