在数据帧级联时保留类别dtype

tom*_*tom 7 python dataframe pandas

我有两个具有相同列名和dtypes的数据框,类似于以下内容:

A             object
B             category
C             category
Run Code Online (Sandbox Code Playgroud)

每个数据帧中的类别都不相同。

通常情况下,熊猫输出:

A             object
B             object
C             object
Run Code Online (Sandbox Code Playgroud)

根据文档,这是预期的行为。

但是,我希望保持分类并希望合并类别,因此我在数据框中的所有类别的列中尝试了union_categoricals。cdfdf是我的两个数据框。

for column in df:
    if df[column].dtype.name == "category" and cdf[column].dtype.name == "category":
        print (column)
        union_categoricals([cdf[column], df[column]], ignore_order=True)

cdf = pd.concat([cdf,df])
Run Code Online (Sandbox Code Playgroud)

这仍然不能为我提供绝对的输出。

小智 10

为了补充 JohnE 的答案,这里有一个函数通过将所有输入数据帧上存在的所有类别列转换为 union_categoricals 来完成这项工作:

def concatenate(dfs):
    """Concatenate while preserving categorical columns.

    NB: We change the categories in-place for the input dataframes"""
    from pandas.api.types import union_categoricals
    import pandas as pd
    # Iterate on categorical columns common to all dfs
    for col in set.intersection(
        *[
            set(df.select_dtypes(include='category').columns)
            for df in dfs
        ]
    ):
        # Generate the union category across dfs for this column
        uc = union_categoricals([df[col] for df in dfs])
        # Change to union category for all dataframes
        for df in dfs:
            df[col] = pd.Categorical(df[col].values, categories=uc.categories)
    return pd.concat(dfs)
Run Code Online (Sandbox Code Playgroud)

请注意,输入列表中的类别已更改:

df1=pd.DataFrame({'a': [1, 2],
                  'x':pd.Categorical(['dog','cat']),
                  'y': pd.Categorical(['banana', 'bread'])})
df2=pd.DataFrame({'x':pd.Categorical(['rat']),
                  'y': pd.Categorical(['apple'])})

concatenate([df1, df2]).dtypes
Run Code Online (Sandbox Code Playgroud)

  • 对于遇到此问题的其他人来说,@FalafelPita 是正确的,并且使用建议的代码将无法正确映射分类。不过,您不需要使用 np.asarray 。你可以这样做:`df[col] = pd.Categorical(df[col].values,categories=uc.categories)`。我已相应更新了答案。 (3认同)

Joh*_*hnE 7

我认为这在文档中并不十分明显,但是您可以执行以下操作。以下是一些示例数据:

df1=pd.DataFrame({'x':pd.Categorical(['dog','cat'])})
df2=pd.DataFrame({'x':pd.Categorical(['cat','rat'])})
Run Code Online (Sandbox Code Playgroud)

使用union_categoricals1得到一致的类别accros dataframes。df.x.cat.codes如果您需要使自己确信这可行,请尝试。

from pandas.api.types import union_categoricals

uc = union_categoricals([df1.x,df2.x])
df1.x = pd.Categorical( df1.x, categories=uc.categories )
df2.x = pd.Categorical( df2.x, categories=uc.categories )
Run Code Online (Sandbox Code Playgroud)

串联并确认dtype是类别的。

df3 = pd.concat([df1,df2])

df3.x.dtypes
category
Run Code Online (Sandbox Code Playgroud)

正如@ C8H10N4O2所建议的那样,您还可以在连接后将对象强制转换回类别。老实说,对于较小的数据集,我认为这是最好的方法,因为它更简单。但是对于较大的数据帧,使用union_categoricals应该具有更高的内存效率。