1 层次化索引
层次化索引(hierarchical indexing)为pandas提供了一种以低维形式处理高维数据的方法
层次化索引的简单示例:
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]]) # 一个简单的双层索引示例
data.index
data['b':'c'] # 第一层索引选择
data.loc[:, 2] # 第二层索引选择
data.unstack() # 二层索引转一层(Series会重塑为DataFrame)
data.stack() # unstack的逆运算
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"]])
frame.index.names = ["key1", "key2"] # 为每层行索引命名
frame.columns.names = ["state", "color"] # 为每层列索引命名
pd.MultiIndex.from_arrays([["Ohio", "Ohio", "Colorado"],
["Green", "Red", "Green"]],
names=["state", "color"]) # 也可以单独创建多层索引,方便复用
### 多层索引的常用方法:
frame.index.nlevels # 查看索引的层级数
frame.swaplevel("key1", "key2") # 交换两层行索引
frame.sort_index(level=1) # 索引排序,仅按照第二层行索引排序
frame.groupby(level="key2").sum() # 指定行索引层级,并完成聚合运算
frame.sum(level='color', axis=1) # 指定列索引层级,并完成聚合运算
### 普通列与行索引之间的互转
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]})
frame2 = frame.set_index(['c', 'd']) # 将普通列转化为行索引
frame2.reset_index() # 将行索引转化为普通列
2 合并数据集
pandas中的常见的三种数据合并方式:
pandas.merge
指定一列或多列进行join操作(SQL常用)pandas.concat
指定一个轴直接拼接多个DataFramecombine_first
用一个DataFrame填充另一个的缺失值
pandas.merge
简单使用示例:
df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6)})
df2 = pd.DataFrame({'key': ['a', 'b', 'a', 'b', 'd'], 'data2': range(5)})
pd.merge(df1, df2, on='key', how='left') # 以key列为键进行左关联
pd.merge(df1, df2, left_on='data1', right_on='daat2', how='inner') # 内关联
pandas.merge
其他常用技巧:
pandas.merge
可以通过参数left_index=True
或right_index=True
指定行索引作为关联键- 当两份数据存在名称重复的列时可以通过参数
suffixes
指定后缀,如suffixes=['_left','_right']
- 未指定关联键时,
pandas.merge
会自动选择所有名称重复的列作为关联键 pandas.merge
支持左(left
)、右(right
)、内(inner
)、外(outer
)关联- 当索引为多层索引时,使用索引作为关联键相当于多个列作为关联键
pandas.concat
简单使用示例:
np.concatenate([arr, arr], axis=1) # 对于numpy数值可以这么拼接
s1 = pd.Series([0, 1], index=["a", "b"], dtype="Int64")
s2 = pd.Series([2, 3, 4], index=["c", "d", "e"], dtype="Int64")
s3 = pd.Series([5, 6], index=["f", "g"], dtype="Int64")
s4 = pd.concat([s1, s3]) # 直接行拼接
pd.concat([s1, s2, s3], axis="columns") # 列拼接多个DataFrame
pd.concat([s1, s4], axis="columns", join="inner") # 指定拼接方式为inner
pd.concat([s1, s1, s3], keys=["one", "two", "three"]) # 构建层次索引,区分三种来源
pandas.concat
其他常用技巧:
- 以上示例方法适用于DataFrame,只是拼接可选择的维度更多
- DataFrame行拼接时要注意忽略(
ignore_index=True
)或重置行索引
combine_first
简单使用示例:
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
np.where(pd.isnull(a), b, a) # 直接填充缺失
# 结果 array([ 0. , 2.5, 2. , 3.5, 4.5, nan])
a.combine_first(b) # 先根据索引对齐,再填充缺失
# 结果 Series([ 0.0, 4.5, 3.5, 0.0 , 2.5, 5.00])
3 重塑和旋转
重塑多层次索引:stack
对应“列转行”,unstack
对应“行转列”
- 通过参数
level
来指定重塑第几层的索引 - 被
unstack
的行索引会转换到列索引的最底层 stack
操作默认会丢弃缺失的数据,可使用dropna=False
保留
“宽格式”与“长格式”:
- 常见的Excel表格数据都是宽格式的,每一个变量单独成一列
- 长格式常用于存储时间序列,每一行代表着一个变量的一次观测
"宽转长"的代码示例:
df = pd.DataFrame({'key': ['foo', 'bar', 'baz'],
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9]})
melted = pd.melt(df, ['key']) # “宽格式”转为“长格式”
# melted 结果展示
# 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
reshaped = melted.pivot(index="key", columns="variable", # 再转回去
values="value")
# reshaped 结果展示
# variable A B C
# key
# bar 2 5 8
# baz 3 6 9
# foo 1 4 7
pivot
等价于使用set_index
创建一个分层索引,然后调用unstack