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

import numpy as np
import pandas as pd
from numpy import nan as NA

#1 层次化索引
"""
层次化索引(hierarchical indexing)是pandas的一项重要功能,它使你能在一个轴上拥有多个(两个以上)索引级别,
抽象点说,它使你能以低维度形式处理高维度数据,
我们先来看一个简单的例子:创建一个Series,并用一个由列表或数组组成的列表作为索引
"""
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]])#两列index的长度需要是一样的
print(data)
#看到的结果是经过美化的带有MultiIndex索引的Series的格式。索引之间的“间隔”表示“直接使用上面的标签”
print(data.index)
#对于一个层次化索引的对象,可以使用所谓的部分索引,使用它选取数据子集的操作更简单
print(data["b":"c"])
#对于一个DataFrame,每条轴都可以有分层索引
frame = pd.DataFrame(np.arange(12).reshape((4, 3)),
index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
columns=[['Ohio', 'Ohio', 'Colorado'],
['Green', 'Red', 'Green']])
print(frame.index)
print(frame)
#各层都可以有名字(可以是字符串,也可以是别的Python对象)。如果指定了名称,它们就会显示在控制台输出中
frame.index.names = ['key1', 'key2']
frame.columns.names = ['state', 'color']
print(frame)

#使用DataFrame的列进行索引
#人们经常想要将DataFrame的一个或多个列当做行索引来用,或者可能希望将行索引变成DataFrame的列
frame = pd.DataFrame({'a': range(7), 'b': range(7, 0, -1),
'c': ['one', 'one', 'one', 'two', 'two',
'two', 'two'],
'd': [0, 1, 2, 0, 1, 2, 3]})
#DataFrame的set_index函数会将其一个或多个列转换为行索引,并创建一个新的DataFrame
frame2=frame.set_index(['c','d'])
print(frame2.loc['one'])
#默认情况下,那些列会从DataFrame中移除,但也可以将其保留下来
frame3=frame.set_index(['c','d'],drop=False)
print(frame3)
#reset_index的功能跟set_index刚好相反,层次化索引的级别会被转移到列里面
print(frame2.reset_index())



#合并数据集
#数据库风格的DataFrame合并
"""
数据集的合并(merge)或连接(join)运算是通过一个或多个键将行连接起来的,
这些运算是关系型数据库(基于SQL)的核心。pandas的merge函数是对数据应用这些算法的主要切入点。
"""
df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
'data1': range(7)})
df2 = pd.DataFrame({'key': ['a', 'b', 'd'],
'data2': range(3)})
#这是一种多对一的合并。df1中的数据有多个被标记为a和b的行,而df2中key列的每个值则仅对应一行。
print(pd.merge(df1, df2,on="key"))#指定按key合并
#如果两个对象的列名不同,也可以分别进行指定
df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
'data1': range(7)})
df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'],
'data2': range(3)})
print(pd.merge(df3, df4, left_on='lkey', right_on='rkey'))
"""
结果里面c和d以及与之相关的数据消失了。默认情况下,merge做的是“内连接”;
结果中的键是交集。其他方式还有"left"、"right"以及"outer"。
"""
#外连接求取的是键的并集,组合了左连接和右连接的效果:
print(pd.merge(df1, df2, how='outer'))
#要根据多个键进行合并,传入一个由列名组成的列表即可
left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'],
'key2': ['one', 'two', 'one'],
'lval': [1, 2, 3]})
right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'],
'key2': ['one', 'one', 'one', 'two'],
'rval': [4, 5, 6, 7]})
print(pd.merge(left, right, on=['key1', 'key2'], how='outer'))

#索引上的合并
#有时候,DataFrame中的连接键位于其索引中。在这种情况下,你可以传入left_index=True或right_index=True(或两个都传)以说明索引应该被用作连接键:
left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'],
'value': range(6)})
right1 = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])
print(pd.merge(left1, right1, left_on='key', right_index=True))

#轴向连接
#另一种数据合并运算也被称作连接(concatenation)、绑定(binding)或堆叠(stacking)。NumPy的concatenation函数可以用NumPy数组来做
arr = np.arange(12).reshape((3, 4))
print(arr)
print(np.concatenate([arr, arr], axis=1))#axis等于1按列拼接,等于0按行拼接

s1 = pd.Series([0, 1], index=['a', 'b'])
s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e'])
s3 = pd.Series([5, 6], index=['f', 'g'])
#对这些对象调用concat可以将值和索引粘合在一起
print(pd.concat([s1, s2, s3]))
#axis按列合并,结果变为Dataframe
print(pd.concat([s1, s2, s3], axis=1))
#这种情况下,另外的轴上没有重叠,从索引的有序并集(外连接)上就可以看出来。传入join='inner'即可得到它们的交集
s4 = pd.concat([s1, s3])
print(pd.concat([s1, s4], axis=1, join='inner'))
#沿着axis=1对Series进行合并,则keys就会成为DataFrame的列头
df1 = pd.DataFrame(np.arange(6).reshape(3, 2), index=['a', 'b', 'c'],
columns=['one', 'two'])
df2 = pd.DataFrame(5 + np.arange(4).reshape(2, 2), index=['a', 'c'],
columns=['three', 'four'])
print(pd.concat([df1, df2], axis=1, keys=['level1', 'level2']))

#合并重叠数据
#使用NumPy的where函数,它表示一种等价于面向数组的if-else
a = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan],
index=['f', 'e', 'd', 'c', 'b', 'a'])
b = pd.Series(np.arange(len(a), dtype=np.float64),
index=['f', 'e', 'd', 'c', 'b', 'a'])
b[-1] = np.nan#设置b的最后一项等于NAN
print(np.where(pd.isnull(a), b, a))#返回一个数组,如果a等于null,则填充b
#Series有一个combine_first方法,实现的也是一样的功能,还带有pandas的数据对齐
print(b[:-2].combine_first(a[2:]))
#对于DataFrame,combine_first自然也会在列上做同样的事情,因此你可以将其看做:用传递对象中的数据为调用对象的缺失数据“打补丁”
df1 = pd.DataFrame({'a': [1., np.nan, 5., np.nan],
'b': [np.nan, 2., np.nan, 6.],
'c': range(2, 18, 4)})
df2 = pd.DataFrame({'a': [5., 4., np.nan, 3., 7.],
'b': [np.nan, 3., 4., 6., 8.]})
print(df1.combine_first(df2))#用df2里的数来填充df1里等于NAN的数



#3 重塑和轴向旋转。 有许多用于重新排列表格型数据的基础运算。这些函数也称作重塑(reshape)或轴向旋转(pivot)运算。
data = pd.DataFrame(np.arange(6).reshape((2, 3)),
index=pd.Index(['Ohio','Colorado'], name='state'),
columns=pd.Index(['one', 'two', 'three'],
name='number'))
#对该数据使用stack方法即可将列转换为行,得到一个Series
result =data.stack()
print(data.stack())
#对于一个层次化索引的Series,你可以用unstack将其重排为一个DataFrame,相当于stack的反义
print(result.unstack())

#将“长格式”旋转为“宽格式”
#多个时间序列数据通常是以所谓的“长格式”(long)或“堆叠格式”(stacked)存储在数据库和CSV中的。我们先加载一些示例数据,做一些时间序列规整和数据清洗:
data = pd.read_csv('../examples/macrodata.csv')

posted @ 2022-04-17 22:59  {hunter}ZY  阅读(254)  评论(0编辑  收藏  举报