利用python进行数据分析

利用python进行数据分析(其四)

数据规整:聚合、合并和重塑

在许多应用中,数据可能分散在许多文件或数据库中,存储的形式将不利用分析,因此可以使用聚合、合并、重塑数据的方法来对数据进行规整。

1.层次化索引

层次化索引是pandas的一项重要功能,可以在一个轴上拥有多个(两个以上)索引级别,因此能以低维度形式处理高纬度数据。举例来说明:

In [9]: data = pd.Series(np.random.randn(9),
...: index=[['a', 'a', 'a', 'b', 'b', 'c', '
c', 'd', 'd'],
...: [1, 2, 3, 1, 3, 1, 2, 2, 3]])
In [10]: data
Out[10]:
a 1 -0.204708
2 0.478943
3 -0.519439
b 1 -0.555730
3 1.965781
c 1 1.393406
2 0.092908
d 2 0.281746
3 0.769023
dtype: float64

可以看到经过Series操作的数据,可以直接使用上面的标签

In [11]: data.index
Out[11]:
MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],
labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 2, 0
, 1, 1, 2]])

同时对于一个层次化索引的对象,可以使用所谓的部分索引,来选取数据子集:

In [12]: data['b']
Out[12]:
1 -0.555730
3 1.965781
dtype: float64
In [13]: data['b':'c']
Out[13]:
b 1 -0.555730
3 1.965781
c 1 1.393406
2 0.092908
dtype: float64
In [14]: data.loc[['b', 'd']]
Out[14]:
b 1 -0.555730
3 1.965781
d 2 0.281746
3 0.769023
dtype: float64
重排与分级排序

根据实际需求,可能需要重新调整某条轴上个级别的顺序,或根据指定级别上的值对数据进行排序,而swaplevel接受两个级别编号或名称,并返回一个互换级别的新对象:

In [24]: frame.swaplevel('key1', 'key2')
Out[24]:
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11

而sort_index则根据单个级别中的值对数据需进行排序。

In [25]: frame.sort
_
index(level=1)
Out[25]:
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
b 1 6 7 8
a 2 3 4 5
b 2 9 10 11
In [26]: frame.swaplevel(0, 1).sort
_
index(level=0)
Out[26]:
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
b 6 7 8
2 a 3 4 5
b 9 10 11
根据级别汇总统计

许多对DataFrame和Series的描述和汇总统计都有一个level选项,用于指定在某条轴上求和的级别。

In [27]: frame.sum(level='key2')
Out[27]:
state Ohio Colorado
color Green Red Green
key2
1 6 8 10
2 12 14 16
In [28]: frame.sum(level='color', axis=1)
Out[28]:
color Green Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10
使用DataFrame的列进行索引

DataFrame的set_index函数会将其中一个或者多个列转换成行索引,并创建一个新的DataFrame

In [31]: frame2 = frame.set_index(['c', 'd'])
In [32]: frame2
Out[32]:
a b
c d
one 0 0 7
1 1 6
2 2 5
two 0 3 4
1 4 3
2 5 2
3 6 1

而reset_index的功能与set_index相反,层次化索引的级别会被转移到列里面。

In [34]: frame2.reset
_
index()
Out[34]:
c d a b
0 one 0 0 7
1 one 1 1 6
2 one 2 2 5
3 two 0 3 4
4 two 1 4 3
5 two 2 5 2
6 two 3 6 1

2.合并数据集

pandas对象中的数据可以通过一些方式进行合并:
1)pandas.merge可根据一个或多个键将不同的DataFrame中的行连接起来
2)pandas.cancat可以演这一条轴将多个对象堆叠到一起
3)conbine_first可以将重复数据拼接在一起,用一个对象中的值填充另一个对象的缺失值

数据库风格的DataFrame合并

数据集的合并或链接运算是通过一个或多个键将行连接起来的,而pandas的merge函数时对数据应用这些算法的主要切入点

In [35]: df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a'
, 'b'],
....: 'data1': range(7)})
In [36]: df2 = pd.DataFrame({'key': ['a', 'b', 'd'],
....: 'data2': range(3)})
In [37]: df1
Out[37]:
data1 key
0 0 b
1 1 b
2 2 a
3 3 c
4 4 a
5 5 a
6 6 b
In [38]: df2
Out[38]:
data2 key
0 0 a
1 1 b
2 2 d

调用merge得到:

In [39]: pd.merge(df1, df2)
Out[39]:
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 [41]: df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', '
a', 'b'],
....: 'data1': range(7)})
In [42]: df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'],
....: 'data2': range(3)})
In [43]: pd.merge(df3, df4, left
_
on='lkey', right
_
on='rkey')
Out[43]:
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

同时对这些选项进行了总结
在这里插入图片描述
对于合并运算需要考虑的一个问题是对重复列名的处理,使用merge的suffixes选项,可以指定附加到左右两个DateFrame对象的重复列名的字符串

In [54]: pd.merge(left, right, on='key1')
Out[54]:
key1 key2
_
x lval key2
_y rval
0 foo one 1 one 4
1 foo one 1 one 5
2 foo two 2 one 4
3 foo two 2 one 5
4 bar one 3 one 6
5 bar one 3 two 7
In [55]: pd.merge(left, right, on='key1', suffixes=('_
left', '_
r
ight'))
Out[55]:
key1 key2
_
left lval key2
_
right rval
0 foo one 1 one 4
1 foo one 1 one 5
2 foo two 2 one 4
3 foo two 2 one 5
4 bar one 3 one 6
5 bar one 3 two 7

merge的参数查看下表
在这里插入图片描述在这里插入图片描述

索引上的合并

当DataFrame的连接键位于其索引中时,可以传入left_index=True或right_index=True(或两个都传)来说明索引应该被用作连接键:

In [56]: left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b',
'c'],
....: 'value': range(6)})
In [57]: right1 = pd.DataFrame({'group_
val': [3.5, 7]}, index=['
a', 'b'])
In [58]: left1
Out[58]:
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
In [59]: right1
Out[59]:
group_
val
a 3.5
b 7.0
In [60]: pd.merge(left1, right1, left
_
on='key', right
_
index=True
)
Out[60]:
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

由于默认的merge方法是求取连接键的交集,因此可以通过外连接的方式得到它们的合集:

In [61]: pd.merge(left1, right1, left_on='key', right_index=True, how='outer')
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
5 c 5 NaN
轴向连接

另外一种数据合并运算也被称为连接、绑定或堆叠,NumPy的concatenation函数可以用NumPy数组来做

In [79]: arr = np.arange(12).reshape((3, 4))
In [80]: arr
Out[80]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [81]: np.concatenate([arr, arr], axis=1)
Out[81]:
array([[ 0, 1, 2, 3, 0, 1, 2, 3],
[ 4, 5, 6, 7, 4, 5, 6, 7],
[ 8, 9, 10, 11, 8, 9, 10, 11]])

pandas的concat函数提供一种可靠方式:

In [82]: s1 = pd.Series([0, 1], index=['a', 'b'])
In [83]: s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e'])
In [84]: s3 = pd.Series([5, 6], index=['f', 'g'])
In [85]: pd.concat([s1, s2, s3])
Out[85]:
a 0
b 1
c 2
d 3
e 4
f 5
g 6
dtype: int64

同时列举一些参数列表
在这里插入图片描述

合并重叠数据

还有一种该数据组合问题可以NumPy的where函数,他表示一种等价于面向数组的if-else:

In [108]: a = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan],
.....: index=['f', 'e', 'd', 'c', 'b', 'a'])
In [109]: b = pd.Series(np.arange(len(a), dtype=np.float64),
.....: index=['f', 'e', 'd', 'c', 'b', 'a'])
In [110]: b[-1] = np.nan
In [111]: a
Out[111]:
f NaN
e 2.5
d NaN
c 3.5
b 4.5
a NaN
dtype: float64
In [112]: b
Out[112]:
f 0.0
e 1.0
d 2.0
c 3.0
b 4.0
a NaN
dtype: float64
In [113]: np.where(pd.isnull(a), b, a)
Out[113]: array([ 0. , 2.5, 2. , 3.5, 4.5, nan])

3.重塑和轴向旋转

用于重塑排列表格型数据的基础运算被称作重塑或轴向运算。

重塑层次化索引

层次化索引为DataFrame数据的重排任务提供一种更具有良好一致性的方式,主要功能有二:
其一,stack:将数据的列“旋转”为行;
其二,unstack:将数据的行“旋转”为列。

In [120]: data = pd.DataFrame(np.arange(6).reshape((2, 3)),
.....: index=pd.Index(['Ohio','Colorado']
, name='state'),
.....: columns=pd.Index(['one', 'two', 't
hree'],
.....: name='number'))
In [121]: data
Out[121]:
number one two three
state
Ohio 0 1 2
Colorado 3 4 5
In [122]: result = data.stack()
In [123]: result
Out[123]:
state number
Ohio one 0
two 1
three 2
Colorado one 3
two 4
three 5
dtype: int64
In [124]: result.unstack()
Out[124]:
number one two three
state
Ohio 0 1 2
Colorado 3 4 5
将“长格式”旋转为“宽格式”

多个时间序列数据通常是以所谓的“长格式”或“堆叠格式”存储在数据库和CSV中的。

In [139]: data = pd.read
_
csv('examples/macrodata.csv')
In [140]: data.head()
Out[140]:
year quarter realgdp realcons realinv realgovt reald
pi cpi \
0 1959.0 1.0 2710.349 1707.4 286.898 470.045 1886
.9 28.98
1 1959.0 2.0 2778.801 1733.7 310.859 481.301 1919
.7 29.15
2 1959.0 3.0 2775.488 1751.8 289.226 491.260 1916
.4 29.35
3 1959.0 4.0 2785.204 1753.7 299.356 484.052 1931
.3 29.37
4 1960.0 1.0 2847.699 1770.5 331.722 462.199 1955
.5 29.54
m1 tbilrate unemp pop infl realint
0 139.7 2.82 5.8 177.146 0.00 0.00
1 141.7 3.08 5.1 177.830 2.34 0.74
2 140.5 3.82 5.3 178.657 2.74 1.09
3 140.0 4.33 5.6 179.386 0.27 4.06
4 139.6 3.50 5.2 180.007 2.31 1.19
In [141]: periods = pd.PeriodIndex(year=data.year, quarter=data.
quarter,
.....: name='date')
In [142]: columns = pd.Index(['realgdp', 'infl', 'unemp'], name=
'item')
In [143]: data = data.reindex(columns=columns)
In [144]: data.index = periods.to
_
timestamp('D', 'end')
In [145]: ldata = data.stack().reset
_
index().rename(columns={0:
'value'})

以上就是多个时间序列的长格式,表中的每行代表一次观察。关系型数据库中的数据通常采用此类方法进行存储,因为随着表中数据的添加,item列中的值的种类能够增加。使用DataFrame,可以将item值分别形成一列,date列中的时间戳用作索引,其中DataFrame的pivot方法可以实现这个转换。

In [147]: pivoted = ldata.pivot('date', 'item', 'value')
In [148]: pivoted
Out[148]:
item infl realgdp unemp
date
1959-03-31 0.00 2710.349 5.8
1959-06-30 2.34 2778.801 5.1
1959-09-30 2.74 2775.488 5.3
1959-12-31 0.27 2785.204 5.6
1960-03-31 2.31 2847.699 5.2
1960-06-30 0.14 2834.390 5.2
1960-09-30 2.70 2839.022 5.6
1960-12-31 1.21 2802.616 6.3
1961-03-31 -0.40 2819.264 6.8
1961-06-30 1.47 2872.005 7.0
... ... ... ...
2007-06-30 2.75 13203.977 4.5
2007-09-30 3.45 13321.109 4.7
2007-12-31 6.38 13391.249 4.8
2008-03-31 2.82 13366.865 4.9
2008-06-30 8.53 13415.266 5.4
2008-09-30 -3.16 13324.600 6.0
2008-12-31 -8.79 13141.920 6.9
2009-03-31 0.94 12925.410 8.1
2009-06-30 3.37 12901.504 9.2
2009-09-30 3.56 12990.341 9.6
[203 rows x 3 columns]
In [149]: ldata['value2'] = np.random.randn(len(ldata))
In [150]: ldata[:10]
Out[150]:
date item value value2
0 1959-03-31 realgdp 2710.349 0.523772
1 1959-03-31 infl 0.000 0.000940
2 1959-03-31 unemp 5.800 1.343810
3 1959-06-30 realgdp 2778.801 -0.713544
4 1959-06-30 infl 2.340 -0.831154
5 1959-06-30 unemp 5.100 -2.370232
6 1959-09-30 realgdp 2775.488 -1.860761
7 1959-09-30 infl 2.740 -0.860757
8 1959-09-30 unemp 5.300 0.560145
9 1959-12-31 realgdp 2785.204 -1.265934
In [151]: pivoted = ldata.pivot('date', 'item')
In [152]: pivoted[:5]
Out[152]:
value value2
item infl realgdp unemp infl realgdp unemp
date
1959-03-31 0.00 2710.349 5.8 0.000940 0.523772 1.343810
1959-06-30 2.34 2778.801 5.1 -0.831154 -0.713544 -2.370232
1959-09-30 2.74 2775.488 5.3 -0.860757 -1.860761 0.560145
1959-12-31 0.27 2785.204 5.6 0.119827 -1.265934 -1.063512
1960-03-31 2.31 2847.699 5.2 -2.359419 0.332883 -0.199543
In [153]: pivoted['value'][:5]
Out[153]:
item infl realgdp unemp
date
1959-03-31 0.00 2710.349 5.8
1959-06-30 2.34 2778.801 5.1
1959-09-30 2.74 2775.488 5.3
1959-12-31 0.27 2785.204 5.6
1960-03-31 2.31 2847.699 5.2
将“宽格式”旋转成“长格式”

旋转DataFrame的逆运算是pandas.melt,他不是将一列转换成多个新的DataFrame,而是合并多个列成为一个可以生成一个二笔输入长的DataFrame。

In [157]: df = pd.DataFrame({'key': ['foo', 'bar', 'baz'],
.....: 'A': [1, 2, 3],
.....: 'B': [4, 5, 6],
.....: 'C': [7, 8, 9]})
In [158]: df
Out[158]:
A B C key
0 1 4 7 foo
1 2 5 8 bar
2 3 6 9 baz
In [159]: melted = pd.melt(df, ['key'])
In [160]: melted
Out[160]:
key variable value
0 foo A 1
1 bar A 2
2 baz A 3
3 foo B 4
4 bar B 5
5 baz B 6
6 foo C 7
7 bar C 8
8 baz C 9
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值