为什么分类类型的外连接结果会输出所有事例的数量?

问题描述 投票:0回答:1

我的示例数据框每行有 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())

#结果

MultiIndex:576 个条目,('A', 'E', 'I', 'M') 到 ('Y', 'Z', 'L', 'P')

python types categories outer-join
1个回答
0
投票

外连接操作组合每个类别的所有值。您观察到的行为是由于数据的“分类”性质造成的。

对分类列进行外连接操作的结果是连接键类别的笛卡尔积。这是因为 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”的组合。

希望这会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.