我的示例数据框每行有 4 行。从pk1到pk5有5个键,但我认为执行外连接时最多应该有16行。然而,使用类别类型的pk,输出所有事例的数量。这是在哪部分发生的?
import pandas as pd
df1 = pd.DataFrame({'pk1': pd.Categorical(['A', 'B', 'C', 'D']),
'pk2': pd.Categorical(['E', 'F', 'G', 'H']),
'pk3': pd.Categorical(['I', 'J', 'K', 'L']),
'pk4': pd.Categorical(['M', 'N', 'O', 'P']),
'pk5': pd.Categorical(['Q', 'R', 'S', 'T']),
'value1': [1, 2, 3, 4],
'value2': [5, 6, 7, 8],
'value3': [9, 10, 11, 12]})
df2 = pd.DataFrame({'pk1': pd.Categorical(['A', 'B', 'X', 'Y']),
'pk2': pd.Categorical(['E', 'F', 'Z', 'W']),
'pk3': pd.Categorical(['I', 'J', 'K', 'L']),
'pk4': pd.Categorical(['M', 'N', 'O', 'P']),
'pk5': pd.Categorical(['Q', 'R', 'U', 'V']),
'value4': [13, 14, 15, 16],
'value5': [17, 18, 19, 20],
'value6': [21, 22, 23, 24]})
result = pd.merge(df1, df2, on=['pk1', 'pk2', 'pk3', 'pk4', 'pk5'], how='outer')
for col in ['value1', 'value2', 'value3', 'value4', 'value5', 'value6']:
result[col + '_C'] = result[col].where(result[col].notnull(), None)
result[col + '_D'] = result[col].where(result[col].isnull(), None)
grouped_sum = result.drop('pk5', axis = 1).groupby(['pk1', 'pk2', 'pk3', 'pk4']).sum()
print(grouped_sum.info())
#结果
外连接操作组合每个类别的所有值。您观察到的行为是由于数据的“分类”性质造成的。
对分类列进行外连接操作的结果是连接键类别的笛卡尔积。这是因为 Pandas “分类”数据类型不会像数据对齐那样在合并操作上对齐类别。
笛卡尔积是从多个集合中返回一个集合的运算,表示所有可能的组合。即“pk1”值与“pk2”、“pk3”、“pk4”和“pk5”值的所有组合的所有组合,无论它们是否一起出现在数据中。
在这里,就您的情况而言,每列中有 4 个独特的类别(“pk1”、“pk2”、“pk3”、“pk4”)。因此,笛卡尔积将为每个唯一的“pk5”值 4444 = 256 行。由于两个数据帧中的“pk5”都是唯一的,因此您看到的最终结果是 2562*2 = 1024 行。如果两个数据框中的分类值相同,您将看到 256 行结果。
解决此问题的一种方法是在合并操作之前将类别转换为“对象”类型。
df2之后
for col in ['pk1', 'pk2', 'pk3', 'pk4', 'pk5']:
df1[col] = df1[col].astype('object')
df2[col] = df2[col].astype('object')
结果之前
这样操作将不会返回类别的笛卡尔积。相反,它将仅包含数据中实际出现的“pk1”、“pk2”、“pk3”、“pk4”、“pk5”的组合。
希望这会有所帮助。