熊猫:在聚合时重命名和重新排序列的最佳习语

时间:2015-04-18 19:13:11

标签: python pandas

我有一只像这样的大熊猫DataFrame

n = 6000
my_data = DataFrame ({
    "Category"  : np.random.choice (['cat1','cat2'], size=n) ,
    "val_1"     : np.random.randn(n) ,
    "val_2"     : [i for i in range (1,n+1)]
})

我在Category上聚合,并将不同的函数应用于不同的列,如下所示:

counts_and_means = \
    my_data.groupby("Category").agg (
        {
            "Category"  : np.count_nonzero ,
            "val_1"     : np.mean ,
            "val_2"     : np.mean
        }
    )

完成后,我想要一个明确的列排序和新的列名。我使用reindexrename执行此操作,使用流畅的样式将原始聚合链接起来,如下所示:

counts_and_means = \
    my_data.groupby("Category").agg (
        {
            "Category"  : np.count_nonzero ,
            "val_1"     : np.mean ,
            "val_2"     : np.mean
        }
    ) \
    .reindex (columns = ["Category","val_1","val_2"]) \
    .rename (
        columns = {
            "Category" : "Count" ,
            "val_1"    : "Avg. Val_1" ,
            "val_2"    : "Avg. Val_2" ,
        }
    )

这是最好的方式(就成语,表演等而言)?或者有没有办法在agg(...)步骤中明确指定列名和顺序?

我在问,因为我对这个API的习惯用语不熟悉,并且想要让它们正确,并且因为它看起来像reindexrename都创建了DataFrame个副本,这可能是对于大型数据集来说,这是一个更大的问题(我知道inplace的{​​{1}}参数,但这不会在我的流畅设置中起作用)。非常感谢任何帮助/建议。

1 个答案:

答案 0 :(得分:2)

值得注意的是,在Python 3.3+中,dict的顺序并不是很好(并且在每次调用时它都不会相同):

In [11]: counts_and_means = \
    my_data.groupby("Category").agg (
        {
            "Category"  : np.count_nonzero ,
            "val_1"     : np.mean ,
            "val_2"     : np.mean
        }
    )

In [12]: counts_and_means
Out[12]:
                val_2  Category     val_1
Category
cat1      2972.181788      3009  0.005821
cat2      3028.988633      2991  0.027436

解决此问题的一种方法是使用OrderedDict

In [13]: from collections import OrderedDict

In [14]: counts_and_means = \
    my_data.groupby("Category").agg(
        OrderedDict([
            ("Category", np.count_nonzero),
            ("val_1",    np.mean),
            ("val_2",    np.mean)
        ])
    )

In [15]: counts_and_means
Out[15]:
          Category     val_1        val_2
Category
cat1          3009  0.005821  2972.181788
cat2          2991  0.027436  3028.988633

现在您可以使用.columns属性直接重命名:

In [16]: counts_and_means.columns = ["Count", "Avg_val1", "Avg_val2"]

注意:在列名中使用.的IMO不具有可解决性,因为您无法再以DataFrame属性的形式访问这些列。尽可能尝试并保留这些标识符。

另一种选择,我会说可能更惯用*而且更简洁,就是迭代地构建它:

In [21]: g = my_data.groupby("Category")

In [22]: counts_and_means = g["Category"].agg(np.count_nonzero).to_frame(name="Count")
         counts_and_means["Avg_val1"] = g["val_1"].agg("mean")
         counts_and_means["Avg_val2"] = g["val_2"].agg("mean")

In [23]: counts_and_means
Out[23]:
          Count  Avg_val1     Avg_val2
Category
cat1       3009  0.005821  2972.181788
cat2       2991  0.027436  3028.988633

*你不需要在一行中做所有事情! :)