Pandas:如何合并两个列名不同的列?

3

我正在尝试将两个数据框连接在一起,一个在上方,一个在下方。不是并排连接。

这些数据框包含相同的数据,但是第一个数据框中可能有一个名为“ObjectType”的列,而第二个数据框中该列可能具有名为“ObjectClass”的名称。 当我执行

df_total = pandas.concat ([df0, df1])

df_total将具有两个列名,一个为"ObjectType",另一个为"ObjectClass"。在这两个列中,一半的值将是"NaN"。因此,我必须手动合并这两个列成为一个列,这非常麻烦。

我能否以某种方式将这两个列合并成一个?我希望有一个函数可以执行以下操作:

df_total = pandas.merge_many_columns(input=["ObjectType,"ObjectClass"], output=["MyObjectClasses"]

合并两列并创建新列。我研究了melt(),但它并不能真正做到这一点?也许如果我可以指定在发生冲突时会发生什么,比如说两列包含值,那么我提供一个lambda函数来说明“保留最大值”、“使用平均值”等等。


如果你来这里是想学习如何合并两个具有不同列名的数据框,你可以在这里了解更多。 - cs95
2个回答

5
我认为您可以先重命名列,以便在两个数据帧中对齐数据:
df0 = pd.DataFrame({'ObjectType':[1,2,3],
                   'B':[4,5,6],
                   'C':[7,8,9]})

#print (df0)

df1 = pd.DataFrame({'ObjectClass':[1,2,3],
                   'B':[4,5,6],
                   'C':[7,8,9]})

#print (df1)

inputs= ["ObjectType","ObjectClass"]
output= "MyObjectClasses"

#dict comprehension 
d = {x:output for x in inputs}
print (d)
{'ObjectType': 'MyObjectClasses', 'ObjectClass': 'MyObjectClasses'}

df0 = df0.rename(columns=d)
df1 = df1.rename(columns=d)
df_total = pd.concat([df0, df1], ignore_index=True)
print (df_total)
   B  C  MyObjectClasses
0  4  7                1
1  5  8                2
2  6  9                3
3  4  7                1
4  5  8                2
5  6  9                3

编辑:

更简单的方法是使用update(在原地inplace操作):

df = pd.concat([df0, df1])
df['ObjectType'].update(df['ObjectClass'])
print (df)
   B  C  ObjectClass  ObjectType
0  4  7          NaN         1.0
1  5  8          NaN         2.0
2  6  9          NaN         3.0
0  4  7          1.0         1.0
1  5  8          2.0         2.0
2  6  9          3.0         3.0

或者使用fillna,但需要删除原始列:
df = pd.concat([df0, df1])
df["ObjectType"] = df['ObjectType'].fillna(df['ObjectClass'])
df = df.drop('ObjectClass', axis=1)
print (df)
   B  C  ObjectType
0  4  7         1.0
1  5  8         2.0
2  6  9         3.0
0  4  7         1.0
1  5  8         2.0
2  6  9         3.0

df = pd.concat([df0, df1])
df["MyObjectClasses"] = df['ObjectType'].fillna(df['ObjectClass'])
df = df.drop(['ObjectType','ObjectClass'], axis=1)
print (df)
   B  C  MyObjectClasses
0  4  7              1.0
1  5  8              2.0
2  6  9              3.0
0  4  7              1.0
1  5  8              2.0
2  6  9              3.0

编辑1:

时间

df0 = pd.DataFrame({'ObjectType':[1,2,3],
                   'B':[4,5,6],
                   'C':[7,8,9]})

#print (df0)

df1 = pd.DataFrame({'ObjectClass':[1,2,3],
                   'B':[4,5,6],
                   'C':[7,8,9]})

#print (df1)
df0 = pd.concat([df0]*1000).reset_index(drop=True)
df1 = pd.concat([df1]*1000).reset_index(drop=True)

inputs= ["ObjectType","ObjectClass"]
output= "MyObjectClasses"

#dict comprehension 
d = {x:output for x in inputs}

In [241]: %timeit df_total = pd.concat([df0.rename(columns=d), df1.rename(columns=d)], ignore_index=True)
1000 loops, best of 3: 821 µs per loop

In [240]: %%timeit
     ...: df = pd.concat([df0, df1])
     ...: df['ObjectType'].update(df['ObjectClass'])
     ...: df = df.drop(['ObjectType','ObjectClass'], axis=1)
     ...: 

100 loops, best of 3: 2.18 ms per loop

In [242]: %%timeit
     ...: df = pd.concat([df0, df1])
     ...: df['MyObjectClasses'] = df['ObjectType'].combine_first(df['ObjectClass'])
     ...: df = df.drop(['ObjectType','ObjectClass'], axis=1)
     ...: 
100 loops, best of 3: 2.21 ms per loop

In [243]: %%timeit 
     ...: df = pd.concat([df0, df1])
     ...: df['MyObjectClasses'] = df['ObjectType'].fillna(df['ObjectClass'])
     ...: df = df.drop(['ObjectType','ObjectClass'], axis=1)
     ...: 
100 loops, best of 3: 2.28 ms per loop

是的,这可能有效。但是,我有很多列,我只想重命名两列。您的解决方案仅在数据框具有两列时有效吗? - Orvar Korvar
我认为这是一种通用的解决方案 - 只需要在两个数据框中使用相同的列名即可。 - jezrael
谢谢你的帮助,但我选择了“combine_first”的答案,因为它更简单。 :) - Orvar Korvar
我添加了2个解决方案,但在我看来,如果需要处理更多不同的列并且需要将input=["ObjectType,"ObjectClass"]映射到output=["MyObjectClasses"],则使用rename更好。 - jezrael
嗯,主要取决于你的需求。combine_firstfillnaupdate速度较慢(请参见编辑后的答案),而int会转换为float,因此需要最后使用astype(int)。祝你愉快! - jezrael
好的,我认为 "update()" 比 "combine_first()" 更容易,所以我改变了主意并将其用作答案。谢谢你们所有人的帮助,你们是最棒的! :) - Orvar Korvar

1

您可以使用combine_first将两个由NaN分隔的列合并为一个。

>>> import numpy as np
>>> import pandas as pd
>>>
>>> df0 = pd.DataFrame({'ObjectType':[1,2,3],
                    'B':[4,5,6],
                    'C':[7,8,9]})

>>> df1 = pd.DataFrame({'ObjectClass':[1,2,3],
                    'B':[4,5,6],
                    'C':[7,8,9]})

>>> df = pd.concat([df0, df1])
>>> df['ObjectType'] = df['ObjectType'].combine_first(df['ObjectClass'])
>>> df['ObjectType']

0    1
1    2
2    3
0    1
1    2
3    3
Name: ObjectType, dtype: float64

据我理解,此人在拼接后得到了一个由Nan填满的df,现在正在寻找一种合并两列的方法。 - greole
这正是我想要的。谢谢!也许你可以将最后一行编辑成这样?我花了15分钟才弄清楚,所以如果能加上这个就太感激了: df["ObjectType"] = df['ObjectType'].combine_first(df['ObjectClass']) - Orvar Korvar
抱歉,但我认为"update()"比"combine_first()"更符合Python的风格。我想选择两者都作为解决方案。 - Orvar Korvar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接