如何在python中对两列进行透视和排序?

Posted

技术标签:

【中文标题】如何在python中对两列进行透视和排序?【英文标题】:How to Pivot-and-Sort for two columns in python? 【发布时间】:2019-07-07 09:37:00 【问题描述】:

我有一个包含客户、商品类别及其价格的超大型数据框。我想做一些初步调查:

根据总支出确定前 5 个客户,例如 n=5。 为每个客户确定他们花费最多的类别。 然后可能按降序绘制显示最高客户的图 他们的名字是X,他们的消费是Y。对于每个人,如何显示他们的购物类别?

这需要旋转和排序。这是一个样本数据生成器,感谢here。

import numpy as np
import pandas as pd
from numpy.core.defchararray import add

np.random.seed(42)
n = 20

cols = np.array(['cust', 'cat'])
arr1 = (np.random.randint(5, size=(n, 2)) // [2, 1]).astype(str)
df = pd.DataFrame(
    add(cols, arr1), columns=cols
).join(
    pd.DataFrame(np.random.rand(n, 1).round(2)).add_prefix('val')
)
print(df)

df.pivot_table(index=['cust'],values=['val0'],aggfunc=[np.sum])

df.pivot_table(index=['cust','cat'],values=['val0'],aggfunc=[np.size,np.sum])

# the order according the previous line should be cust1,cust0,cust2. How to do? The following is the desired output in this case.

                size sum
                val0 val0
cust    cat
cust1   cat4    6.0  4.27
        cat3    2.0  1.07
        cat2    2.0  0.98
        cat0    2.0  0.44
        cat1    2.0  0.43

cust0   cat1    1.0  0.94
        cat4    1.0  0.91
        cat2    1.0  0.66
        cat3    1.0  0.03

cust2   cat1    2.0  1.25

非常感谢!

【问题讨论】:

你的熊猫版本是什么? 我使用的是熊猫 0.23.4 你需要阴谋蝙蝠吗?还是线条? bar 会更好,当我得到第一个解决方案时我可以更改它。 已编辑答案,请检查。 【参考方案1】:

这里最好聚合sum,以避免在列中使用MultiIndex

第一次聚合sum

s = df.groupby('cust')['val0'].sum()
print (s)
cust
cust0    2.54
cust1    7.19
cust2    1.25
Name: val0, dtype: float64

然后通过Series.nlargest获取最高值:

top5 = s.nlargest(5)
print (top5)
cust
cust1    7.19
cust0    2.54
cust2    1.25
Name: val0, dtype: float64

如有必要,仅按boolean indexingisin 过滤前5 个值:

df1 = df[df['cust'].isin(top5.index)].copy()
#print(df1)

为了正确排序 cust 创建有序分类并按两个过滤列聚合,最后按第一级 cust 和列 size 排序:

df1['cust'] = pd.Categorical(df1['cust'], ordered=True, categories=top5.index)
df2 = (df1.groupby(['cust','cat'])['val0'].agg([np.size,np.sum])
         .sort_values(['cust','size'], ascending=[True, False])
         .reset_index())
print (df2)
    cust   cat  size   sum
0  cust1  cat4   6.0  4.27
1  cust1  cat0   2.0  0.44
2  cust1  cat1   2.0  0.43
3  cust1  cat2   2.0  0.98
4  cust1  cat3   2.0  1.07
5  cust0  cat1   1.0  0.94
6  cust0  cat2   1.0  0.66
7  cust0  cat3   1.0  0.03
8  cust0  cat4   1.0  0.91
9  cust2  cat1   2.0  1.25

DataFrame.plot.bar 的最后一个轴和绘图:

df2.pivot('cust','cat','size').plot.bar()

【讨论】:

谢谢@jezrael,但是您手动设置了类别的顺序,这里只有 3 个。当我们想要前 n=100 个客户时如何自动执行? @physiker - 哎呀,给他们一些时间 太棒了@jezrael !!非常感谢您的时间和精力。顺便说一句,我真的很喜欢你的个人资料代码来显示你的电子邮件:)【参考方案2】:

不确定我是否理解您想要的确切概述,但这也可以通过使用groupby 然后使用agg 方法,如下所示:

overview = df.groupby('cust').agg('val0':'sum',
                                   'cat':'max').reset_index().sort_values('val0', ascending=False)

    cust    val0    cat
1   cust1   7.19    cat4
0   cust0   2.54    cat4
2   cust2   1.25    cat1

因此,这会汇总客户级别并汇总他们的总支出并显示他们花费最多的类别。

您不必使用reset_index() 函数,在这种情况下,它会产生以下结果:

overview = df.groupby('cust').agg('val0':'sum',
                                   'cat':'max').sort_values('val0', ascending=False)


        val0    cat
cust        
cust1   7.19    cat4
cust0   2.54    cat4
cust2   1.25    cat1

最后如果您想要前 5 名客户,您可以简单地使用 .head(5),因为这些值已经按降序排序:

overview = df.groupby('cust').agg('val0':'sum',
                                   'cat':'max').sort_values('val0', ascending=False).head(5)

【讨论】:

感谢@Erfan,请在问题中查看我想要的输出。

以上是关于如何在python中对两列进行透视和排序?的主要内容,如果未能解决你的问题,请参考以下文章

JQuery UI Sortable - 如何在一个容器中对两种类型的项目进行排序

CreateCriteria 对两列组合进行排序

如何按id python按一列顺序对两列进行分组[重复]

熊猫:对两列一起排序[重复]

对两列数据进行排序并保留不重复的值

SQL Server:如何对两列/条件进行重复数据删除?