8.1 分层索引
分层索引允许在一个轴向上拥有多个(两个或两个以上)索引层级
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]]) """输出 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 """
-
各种索引方式
# 以MultiIndex作为索引的Series的美化视图 data.index """ MultiIndex([('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 3), ('c', 1), ('c', 2), ('d', 2), ('d', 3)], ) """ # 分层索引 data['b'] data['b':'c'] data.loc[['b', 'd']] """ b 1 -0.555730 3 1.965781 d 2 0.281746 3 0.769023 dtype: float64 """ # 在“内部”层级中进行选择 data.loc[:, 2] """ a 0.478943 c 0.092908 d 0.281746 dtype: float64 """
DataFrame分层索引
-
unstack重新排列
data.unstack() # 将数据在DataFrame中重新排列 """ 1 2 3 a -0.204708 0.478943 -0.519439 b -0.555730 NaN 1.965781 c 1.393406 0.092908 NaN d NaN 0.281746 0.769023 """ data.unstack().stack() # unstack反操作 # 输出结果为原来模样
-
在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']])
分层索引名称
-
分层的层级可以有名称(字符串或Python对象)
frame.index.names = ['key1', 'key2'] frame.columns.names = ['state', 'color'] frame['Ohio']
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a3G3tbSH-1648984382595)(C:/Users/TSY/Desktop/无标题.png?lastModify=1648949532)]
-
MultiIndex对象可以使用其自身的构造函数创建并复用
pd.MultiIndex.from_arrays([['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']], names=['state', 'color']) """ MultiIndex([( 'Ohio', 'Green'), ( 'Ohio', 'Red'), ('Colorado', 'Green')], names=['state', 'color']) """
重排序和层级排序
重新排列轴上的层级顺序
按照特定层级的值对数据进行排序
-
swaplevel接收两个层级序号或层级名称,返回进行层级变更的新对象(但是数据是不变的)
frame.swaplevel('key1', 'key2')
-
sort_index只能在单一层级上进行排序,在层级变换时,可以按照层级进行字典排序
frame.sort_index(level=1) frame.swaplevel(0, 1).sort_index(level=0)
按照字典最外层开始排序数据选择效果更好,调用sort_index(level=0)或sort_index可以实现
按层级进行汇总统计
-
在描述性和汇总性统计中使用level选项实现在特定轴上进行聚合
# level要被弃用,使用group代替 frame.sum(level='key2') # frame.groupby(level='key2').sum() frame.sum(level='color', axis=1) # frame.groupby(level='color',axis=1).sum()
使用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函数和reset_index函数
frame2 = frame.set_index(['c', 'd']) frame2 # set_index函数会生成一个新的DataFrame,新的DataFrame使用一个或多个列作为索引 # 默认这些列会从DataFrame中移除 frame.set_index(['c', 'd'], drop=False) # reset_index是set_index的反操作,分层索引的索引层级会被移动到列中 frame2.reset_index()
8.2 联合与合并数据集
pandas数据联合方式
- pandas.merge根据一个或多个键将行进行连接,数据库的连接操作
- pandas.concat使对象在轴向上进行黏合或“堆叠”
- combine_first实例方法允许将重叠的数据拼接在一起,以使用一个对象中的值填充另一个对象中的缺失值
数据库风格的DataFrame连接
-
pandas.merge函数:将各种join操作运用在数据上
df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)}) df2 = pd.DataFrame({'key': ['a', 'b', 'd'], 'data2': range(3)}) print(df1) """ key data1 0 b 0 1 b 1 2 a 2 3 c 3 4 a 4 5 a 5 6 b 6 """ print(df2) """ key data2 0 a 0 1 b 1 2 d 2 """
-
使用merge进行多对一连接
-
简单示例
# merge会自动将重叠列名作为连接的键 pd.merge(df1, df2) pd.merge(df1, df2, on='key') # 显示指定键 """ key data1 data2 0 b 0 1 1 b 1 1 2 b 6 1 3 a 2 0 4 a 4 0 5 a 5 0 """
-
merge默认内连接,只出现表的交集;有可选项’left’、‘right’和’outer’(外连接是键的并集)
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(df3) print(df4) # 指定列名 pd.merge(df3, df4, left_on='lkey', right_on='rkey') # 内连接 pd.merge(df1, df2, how='outer') # 外连接
-
how参数的不同连接类型
-
-
使用merge进行多对多连接
-
多对多连接是行的笛卡尔积
-
使用多个键进行合并时,传入一个列名的列表
pd.merge(left, right, on=['key1', 'key2'], how='outer')
-
当你在进行列-列连接时,传递的DataFrame索引对象会被丢弃
-
重叠列名
-
手动重命名轴标签
-
merge的suffixes后缀选项:在左右两边有重叠列名时指定需要添加的字符串
pd.merge(left, right, on='key1', suffixes=('_left', '_right'))
-
-
merge函数参数
根据索引合并
-
合并的键是它的索引,可以传递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']) left1 right1 # 默认:连键相交 pd.merge(left1, right1, left_on='key',right_index=True) """ 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 """ # 使用外键进行合并 pd.merge(left1, right1, left_on='key', right_index=True, how='outer') """ 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 """
-
多层索引数据:隐式的多键合并
# 必须以列表的方式指明合并所需多个列(请注意使用how='outer’处理重复的索引值) # 在多层索引数据的情况下,在索引上连接是一个隐式的多键合并 pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True) pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True, how='outer') # 使用两边的索引进行合并 pd.merge(left2, right2, how='outer', left_index=True, right_index=True)
-
DataFrame的join方法:用于按照索引合并,也可用于合并多个索引相同或相似但没有重叠列的DataFrame对象
left2.join(right2, how='outer')
-
join方法进行左连接,完全保留左边DataFrame的行索引;支持在连接上传递索引
left1.koin(right1,one='key')
-
索引-索引,向join方法传入DataFrame列表
# concat方法更为通用 left2.join([right2, another], how='outer')
-
沿轴向连接
-
NumPy的concatenate函数在NumPy数组上实现拼接、绑定或堆叠
arr = np.arange(12).reshape((3, 4)) arr np.concatenate([arr, arr], axis=1) """ 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函数
-
假设存在三个索引不存在重叠的Series
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连接 ,默认沿着axis=0的轴向生效的 pd.concat([s1, s2, s3]) # 传递axis=1,返回的结果则是一个DataFrame(axis=1时是列) pd.concat([s1, s2, s3], axis=1)
-
有重叠轴
s4 = pd.concat([s1, s3]) pd.concat([s1, s4], axis=1) pd.concat([s1, s4], axis=1, join='inner') # 标签f和g消失 s4 """s4 a 0 b 1 f 5 g 6 dtype: int64 """
-
在连接轴上建立多层索引,使用参数keys来实现:区分连接前的各部分
result = pd.concat([s1, s1, s3], keys=['one', 'two', 'three']) result """ one a 0 b 1 two a 0 b 1 three f 5 g 6 dtype: int64 """
-
沿着轴向axis=1连接Series的时候,keys则成为DataFrame的列头
pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three'])
-
Series扩展到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']) pd.concat([df1, df2], axis=1, keys=['level1', 'level2'])
-
如果传递字典,字典的键会用于keys选项
pd.concat({'level1': df1, 'level2': df2}, axis=1)
-
使用names参数生成轴层级
pd.concat([df1, df2], axis=1, keys=['level1', 'level2'],names=['upper', 'lower'])
-
行索引中不包含任何相关数据的DataFrame,传入
ignore_index = True
-
-
-
concat函数的参数(join_axes好像已经弃用)
联合重叠数据
展示几种数据有重叠部分的情况
-
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 print(a) print(b) np.where(pd.isnull(a), b, a)
-
Series的combine_first方法,类似于pandas常见的数据对齐逻辑的轴向操作;针对DataFrame逐列做相同的操作。
b.combine_first(a)
8.3 重塑和透视
重排列表格型数据的操作被称为重塑或透视
使用多层索引进行重塑
两个基础操作
- stack(堆叠):该操作会“旋转”或将列中的数据透视到行
- unstack(拆堆):该操作会将行中的数据透视到列
例子说明
-
效果演示
data = pd.DataFrame(np.arange(6).reshape((2, 3)), index=pd.Index(['Ohio', 'Colorado'], name='state'), columns=pd.Index(['one', 'two', 'three'], name='number')) """ number one two three state Ohio 0 1 2 Colorado 3 4 5 """ # 用stack方法会将列透视到行,产生一个新的Series result = data.stack() result """ state number Ohio one 0 two 1 three 2 Colorado one 3 two 4 three 5 dtype: int32 """ # 使用unstack方法将数据重排列后放入一个DataFrame中 result.unstack() # 还原
-
默认最内层是已拆堆的,可以传入层级序号或名称来拆分一个不同的层级
result.unstack(0) # 传入序号来拆分不同的层级 result.unstack('state') # 传入名称来拆分不同的层级
-
拆堆可能会引入缺失值,堆叠会过滤出缺失值,两个操作可逆
-
在DataFrame中拆堆时,被拆堆的层级会变为结果中最低的层级
-
在调用stack方法时,我们可以指明需要堆叠的轴向名称
df.unstack('state').stack('side')
将“长”透视为“宽”
在数据库和CSV中存储多时间序列的方式就是所谓的长格式或堆叠格式
-
使用PeriodIndex将数据处理后形成Idata
多时间序列的长格式,或具有两个或更多个键的数据(键date和item)
-
使用DataFrame的pivot方法将数据处理为按date列时间戳进行索引且每个不同的item独立为一列
# 前两个值是分别用作行和列索引的列 # 然后是可选的数值列以填充DataFrame pivoted = ldata.pivot('date', 'item', 'value') pivoted
-
同时重塑两个数值列
ldata['value2'] = np.random.randn(len(ldata)) ldata[:10]
遗漏最后一个参数,你会得到一个含有多层列的DataFrame
pivoted = ldata.pivot('date', 'item') pivoted[:5]
-
pivot方法等价于使用set_index创建分层索引,然后调用unstack
unstacked = ldata.set_index(['date','item']).unstack('item') unstacked[:7]
将“宽”透视为“长”
DataFrame的pivot方法的反操作:pandas.melt,将多列合并成一列,产生一个新的DataFrame
-
数据
-
'key’列可以作为分组指标,其他列均为数据值
melted = pd.melt(df, ['key'])
-
使用pivot方法可以重回原来布局
reshaped = melted.pivot('key', 'variable', 'value') # pivot的结果根据作为行标签的列生成了索引 # 使用reset_index来将数据回移一列 reshaped.reset_index()
-
可以指定列的子集作为值列,也可以无须任何分组指标
# 指定列的子集作为值列 pd.melt(df, id_vars=['key'], value_vars=['A', 'B']) # 无须任何分组指标直接使用 pd.melt(df, value_vars=['A', 'B', 'C']) pd.melt(df, value_vars=['key', 'A', 'B'])