Python 在数据帧连接时保留分类数据类型

Python 在数据帧连接时保留分类数据类型,python,pandas,dataframe,Python,Pandas,Dataframe,我有两个具有相同列名和数据类型的数据帧,如下所示: A object B category C category 每个数据帧中的类别都不相同 for column in df: if df[column].dtype.name == "category" and cdf[column].dtype.name == "category": print (column) union_ca

我有两个具有相同列名和数据类型的数据帧,如下所示:

A             object
B             category
C             category
每个数据帧中的类别都不相同

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])
正常浓缩时,熊猫输出:

A             object
B             object
C             object
这是根据的预期行为

但是,我希望保留分类并希望合并类别,因此我尝试了数据框架中两个都是分类的列中的union_分类。cdf和df是我的两个数据帧

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])

这仍然没有为我提供分类输出。

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

df1=pd.DataFrame({'x':pd.Categorical(['dog','cat'])})
df2=pd.DataFrame({'x':pd.Categorical(['cat','rat'])})
使用union_CATEGRICALS1获得一致的类别accros数据帧。如果您需要说服自己这是可行的,请尝试使用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 )
连接并验证数据类型是分类的

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

df3.x.dtypes
category

正如@C8H10N4O2所建议的,您也可以在连接后将对象强制返回到分类。老实说,对于较小的数据集,我认为这是最好的方法,因为它更简单。但对于更大的数据帧,使用union_分类应该更节省内存。

JohnE的回答很有帮助,但在pandas 0.19.2中,union_分类只能按如下方式导入: 来自pandas.types.concat导入联合目录

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

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)
注意:输入列表中的类别已更改到位:

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

你用的是什么版本的熊猫?我无法复制此行为。0.20.1-union_分类在0.19.0版中是新的。我得到一个ValueError:在Category concat中不兼容的分类,但我仍然在0.18.1是-union_分类似乎完全克服了这个问题-请参阅I dunno。你可以像df['A']=df['A']那样强制返回到类别。aType'category'感谢你这样做-最终在整个框架中混合了强制和联合。你确定吗?如果我尝试从pandas.api导入,我会收到一条不推荐警告。types在23.4版中仍然可以正常工作,并且在24.1版的文档中。我承认我不知道union_分类的历史,所以也许你的断言在过去是正确的,但现在可能不再正确了。我刚刚艰难地了解到,pd.category df[col],categories=uc.categories会保持df[col]的分类代码不变,但会根据uc.categories将它们重新映射到分类,可能将它们错误地关联起来。为了避免这种情况,请将df[col]替换为np.asarraydf[col]。您能提供一个有问题的示例吗?对于上面的玩具示例和我的数据集,它似乎工作得很好。根据pandas的版本,可能需要include=['category'],因为其他任何人遇到这个@FalafelPita是正确的,使用建议的代码将无法正确映射分类。不过,您不需要使用np.asarray。您可以这样做:df[col]=pd.Categoricaldf[col].values,categories=uc.categories。我已经相应地更新了答案。@MarkRucker你是对的。我刚刚用Pandas 0.24.1重新测试,并使用df[col]而不是df[col]。值给出了错误的结果。在熊猫0.24.2的情况下,它将继续工作。