Pandas进阶之数据规整化


概述

在Pandas基本使用简单了介绍了一下Pandas的基本使用和用法,大家如果没有一点基础的同学可以先看一下那篇文章。今天我们来讲解一下Pandas的高级用法。

Numpy基本用法

在讲解Pandas高级特性之前,我们先来学习一下Numpy。Numpy是高性能计算和数据分析的基础包,一种ndarray的多维数组对象并且是一个同构的数据多维容器。创建和操作一个多维数组,我们来看一下简单的代码片段。

arr = np.arange(10,dtype=np.float32)
# np.zero,np.ones,np.empty等等

如果没有指定dtype,值得注意一点的是在后面如果要通过astype类型的话,astype是需要赋值数据的,而通过切片是不需要复制数据。切片是原始数据的一个视图,是直接映射到原始数据,对视图的任何修改也是直接映射到原始数据。如果想要复制数据,可以通过copy的包复制数据。

Numpy的布尔数组

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的切片和花式索引

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转置和轴转换

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的唯一化表示

我们先来确定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)

  • unique(x) 计算数组中的唯一元素,并返回结果。
  • intersect1d(x,y)计算数组x和y中的公共元素,并返回有序结果。
  • union1d(x,y)计算x和y的并集,并返回结果。

这里就不一一列举,很多操作可以查看API。

Pandas的高级用法

Pandas是基于Numpy构建的,它使得数据分析工作变得更快更简单。Pandas有两种结构Series和DataFrame,他们数据表现是索引在左边,值在右边。

Pandas的Serise结构

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一个最主要的特性是能自动对齐数据。

Pandas的DataFrame的数据规整化

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方法实现

DataFrame的列(columns)合并

当多个数据集进行合并(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的索引合并

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

DataFrame的轴向连接

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进行打补丁。

DataFrame的重塑和轴向旋转

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是对样本进行分位数。

异常值检测

检查超过3或者-3的异常值

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进行数据分析》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏mukekeheart的iOS之旅

iOS学习——属性引用self.xx与_xx的区别

 在iOS开发过程中,我们用@proprety声明一个属性后,在代码中我们可以用self.xx与_xx来获取到这个属性。但是一直有一个疑惑,那就是这两个之间有...

42416
来自专栏数说戏聊

00.数据结构关于浮点数运算的越界问题1.数据结构2.Pandas的两种常用数据结构3.Series系列4.DataFrame数据框

类似一维数组(ndarray)的对象,由一组数据(各种NumPy数据类型)以及与之相关的数据标签(索引)组成,用于存储一行或一列数据。

1021
来自专栏GopherCoder

『Go 内置库第一季:strconv』

日常编写代码的过程中,字符串和数值型、布尔类型之间的转换算是很频繁了。所以有必要研究下内置的 strconv 库。

973
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础-day07-代码题-自定义数据类型;ArrayList集合

Java基础-day07-代码题-自定义数据类型&ArrayList集合 1.饭店结账程序. 定义菜品类,属性为名称,价格,数量. 集合中添加若干菜品对象. 遍...

3304
来自专栏一个会写诗的程序员的博客

函数式编程与面向对象编程[1]: Lambda表达式 函数柯里化 高阶函数函数式编程与面向对象编程[1]: Lambda表达式 函数柯里化 高阶函数.md

For example, in Lisp the 'square' function can be expressed as a lambda expressi...

772
来自专栏函数式编程语言及工具

Scalaz(12)- Monad:再述述flatMap,顺便了解MonadPlus

  在前面的几篇讨论里我们初步对FP有了些少了解:FP嘛,不就是F[A]吗?也是,FP就是在F[]壳子(context)内对程序的状态进行更改,也就是在F壳子(...

1997
来自专栏Brian

数据分析利器Pandas基本功能

---- 概述 pandas是基于Numpy构建的,让处理数据、分析数据和可视化数据都会变得更加简单,官网Pandas.正如官网所说: pandas is an...

4917
来自专栏salesforce零基础学习

salesforce零基础学习(七十八)线性表链形结构简单实现

前两篇内容为栈和队列的顺序结构的实现,栈和队列都是特殊的线性表,线性表除了有顺序结构以外,还有线性结构。 一.线性表的链形结构--链表 使用顺序存储结构好处为实...

2420
来自专栏GreenLeaves

Jquery遍历数组之$.inArray()方法介绍

$.inArray()函数用于在数组中搜索指定的值,并返回其索引值。如果数组中不存在该值,则返回-1; $.inArray(value,array)    --...

2328
来自专栏北京马哥教育

Python练手题,敢来挑战吗?

这到题用到了字符串的所有字母大写和所有字母小写和字符串拼接,复制,用到的函数有 json 将列表中的内容按照指定字符连接成一个字符串,

1100

扫码关注云+社区

领取腾讯云代金券