合并pandas DataFrames时如何保留列MultiIndex值
Posted
技术标签:
【中文标题】合并pandas DataFrames时如何保留列MultiIndex值【英文标题】:How to keep column MultiIndex values when merging pandas DataFrames 【发布时间】:2018-01-29 19:13:36 【问题描述】:我有两个 pandas DataFrame,如下:
df1 = pd.DataFrame(('Q1', 'SubQ1'):[1, 2, 3], ('Q1', 'SubQ2'):[1, 2, 3], ('Q2', 'SubQ1'):[1, 2, 3])
df1['ID'] = ['a', 'b', 'c']
df2 = pd.DataFrame('item_id': ['a', 'b', 'c'], 'url':['a.com', 'blah.com', 'company.com'])
df1
:
Q1 Q2 ID
SubQ1 SubQ2 SubQ1
0 1 1 1 a
1 2 2 2 b
2 3 3 3 c
df2
:
item_id url
0 a a.com
1 b blah.com
2 c company.com
请注意,df1
的某些列具有分层索引(例如 ('Q1', 'SubQ1')
),而某些列仅具有普通索引(例如 ID
)。
我想在ID
和item_id
字段上合并这两个数据框。使用:
result = pd.merge(df1, df2, left_on='ID', right_on='item_id')
给予:
(Q1, SubQ1) (Q1, SubQ2) (Q2, SubQ1) (ID, ) item_id url
0 1 1 1 a a a.com
1 2 2 2 b b blah.com
2 3 3 3 c c company.com
如您所见,合并本身工作正常,但 MultiIndex 已丢失并恢复为元组。我尝试使用 pd.MultiIndex.from_tuples
重新创建 MultiIndex,如下所示:
result.columns = pd.MultiIndex.from_tuples(result)
但这会导致item_id
和url
列出现问题,只取其名称的前两个字符:
Q1 Q2 ID i u
SubQ1 SubQ2 SubQ1 t r
0 1 1 1 a a a.com
1 2 2 2 b b blah.com
2 3 3 3 c c company.com
将df2
中的列转换为单元素元组(即('item_id',)
而不仅仅是'item_id'
)没有区别。
如何合并这两个 DataFrame 并正确保留 MultiIndex?或者,我怎样才能获取合并的结果并返回具有适当 MultiIndex 的列,而不会弄乱 item_id
和 url
列的名称?
【问题讨论】:
df1.assign(u=df1.ID.map(df2.set_index('item_id')['url']))
适合你吗?
它适用于这个例子,但在实际情况下,我在 df2
中有多个列,我想在连接中引入 - 所以我必须多次执行此操作才能获得每个专栏,我觉得不太理想。
【参考方案1】:
如果你不能打败他们,就加入他们。 (合并前让两个DataFrame的索引层数相同):
import pandas as pd
df1 = pd.DataFrame(('Q1', 'SubQ1'):[1, 2, 3], ('Q1', 'SubQ2'):[1, 2, 3], ('Q2', 'SubQ1'):[1, 2, 3])
df1['ID'] = ['a', 'b', 'c']
df2 = pd.DataFrame('item_id': ['a', 'b', 'c'], 'url':['a.com', 'blah.com', 'company.com'])
df2.columns = pd.MultiIndex.from_product([df2.columns, ['']])
result = pd.merge(df1, df2, left_on='ID', right_on='item_id')
print(result)
产量
Q1 Q2 ID item_id url
SubQ1 SubQ2 SubQ1
0 1 1 1 a a a.com
1 2 2 2 b b blah.com
2 3 3 3 c c company.com
这也避免了UserWarning
:
pandas/core/reshape/merge.py:551: UserWarning: 不同层级之间的合并会产生意想不到的结果(左边2层,右边1层)
【讨论】:
【参考方案2】:ID
的列不是“非分层的”。它由('ID', )
表示。但是,pandas
允许您仅引用第一级列,其方式看起来像是在引用单级列结构。这意味着这应该适用于df1['ID']
以及df1[('ID',)]
以及df1.loc[:, ('ID',)]
。但如果碰巧***'ID'
在第二级有更多与之关联的列,df1['ID']
将返回一个数据框。我对这个解决方案感觉更舒服,它看起来很像 @JohnGalt 在 cmets 中的回答。
df1.assign(u=df1[('ID', '')].map(df2.set_index('item_id').url))
Q1 Q2 ID u
SubQ1 SubQ2 SubQ1
0 1 1 1 a a.com
1 2 2 2 b blah.com
2 3 3 3 c company.com
将单级列数据框连接到多级列数据框很困难。我必须人为地添加另一个级别。
def rnm(d):
d = d.copy()
d.columns = [d.columns, [''] * len(d.columns)]
return d
df1.join(rnm(df2.set_index('item_id')), on=('ID',))
Q1 Q2 ID url
SubQ1 SubQ2 SubQ1
0 1 1 1 a a.com
1 2 2 2 b blah.com
2 3 3 3 c company.com
【讨论】:
【参考方案3】:这个解决方案更加灵活,因为您不必在连接之前插入列级别,您可以使用它来连接任意数量的级别:
import pandas as pd
df1 = pd.DataFrame(('A', 'b'): [1, 2], ('A', 'c'): [3, 4])
df2 = pd.DataFrame('Zaa': [1, 2])
df3 = pd.DataFrame(('Maaa', 'k', 'l'): [1, 2])
df = pd.concat([df1, df2, df3], axis=1)
cols = [col if isinstance(col, tuple) else (col, ) for col in df.columns]
df.columns = pd.MultiIndex.from_tuples(cols)
【讨论】:
以上是关于合并pandas DataFrames时如何保留列MultiIndex值的主要内容,如果未能解决你的问题,请参考以下文章
如何加入 Pandas Dataframes 并多次保留左列?
如何在Python Pandas中将MultiIndex Dataframes与权重合并?
Pandas:如何通过保留第一个数据框的信息来合并列上的两个数据框?
如何计算自特定列中发生事件以来经过的时间 - Pandas DataFrames
使用 List Comprehension (Pandas) 从 DataFrames 列表中删除 DataFrames 列