如何获得分类变量中类别的各种组合并同时进行汇总?

如何解决如何获得分类变量中类别的各种组合并同时进行汇总?

我试图在三列中获得各种数据组合,同时,我还想对这些值进行汇总(求和)。

我的数据如下所示,下面是我的示例输出

Dim1    Dim2    Dim3    Spend
A       X       Z       100
A       Y       Z       200
B       X       Z       300
B       Y       Z       400

样本输出

Dim 1   Dim 2   Dim 3   Spend
A       NaN     NaN     300
A       X       NaN     100
A       Y       NaN     200
A       NaN     Z       300
B       NaN     NaN     700
B       X       NaN     300
B       Y       NaN     400
B       NaN     Z       700
NaN     X       Z       400
NaN     Y       Z       600
NaN     NaN     Z       1000
NaN     X       NaN     400
NaN     Y       NaN     600
A       X       Z       100
A       Y       Z       200
B       X       Z       300
B       Y       Z       400

Dim1Dim2Dim3是分类变量,而Spend是值/度量。我们需要在分类变量的所有可能组合上找到总计Spend,而我可以使用itertools.combinations()来实现这一部分。现在,不仅对于三列,我们还可以获得任意数量的此类变量的组合,例如Dim1,Dim2,Dim3 .... Dim 30等。

我的问题是我无法在同一行上进行汇总,例如,在第12行中,对于类别Spend的{​​{1}}值,我们正在执行所有Z Z出现在主数据中的值,即1000。我们如何实现聚合的值?


可复制的数据:

sum()

解决方法

摘要

使用itertools.combinations()的想法正确。其他关键步骤:

  1. itertools.combinations()应用于所有可能要汇总的尺寸(从1n_dim-1)。即itertools.combinations(range(1,1+n_dim),i),代表i in range(1,1+n_dim)
  2. 使用df.groupby(by=column_combinations).sum()从类的组合中自动获取结果。

代码

程序包含3个逻辑部分。

  1. 从各个维度按类进行汇总。这部分基本上与您所做的相等,但是通过DFS方法进行了重新设计,以减少要处理的数据总量。当有数百万行要处理时,这很有用。随后的步骤也基于此中间数据​​集而不是原始数据集进行计算。
  2. 一个生成器,可以循环进行摘要1中提到的维组合,而无需显式枚举。
  3. 执行摘要2中提到的分组计算,并输出可以在程序末尾连接的结果数据帧列表。

警告:请务必在生产中测试性能和内存问题。

import pandas as pd
import numpy as np
import itertools

df = pd.DataFrame(
    {'Dim1': ['A','A','B','B'],'Dim2': ['X','Y','X','Y'],'Dim3': ['Z','Z','Z'],'Spend': [100,200,300,400]
     }
)

# constants: column names and dimensions
n_dim = 3
dim_cols = [f"Dim{i}" for i in range(1,n_dim + 1)]
cols = dim_cols + ["Spend"]


# 1. compute sums with every dimension
def dfs(df,ls_out,dim_now=1,ls_classes=[]):

    # termination condition (every dimension has been traversed)
    if dim_now == n_dim + 1:
        # perform aggregation
        sum = df["Spend"].sum()
        ls_classes.append(sum)
        ls_out.append(ls_classes)
        return

    # proceed
    col = f"Dim{dim_now}"

    # get categories
    classes = df[col].unique()
    classes.sort()

    for c in classes:
        # recurse next dimension with subset data
        dfs(df[df[col] == c],dim_now=dim_now + 1,ls_classes=ls_classes + [c])

ls_out = []  # the output container
dfs(df,ls_out)
# convert to dataframe
df_every_dim = pd.DataFrame(data=ls_out,columns=df.columns)
del ls_out
print(df_every_dim)


# 2. generate combinations of groupby-dimensions
def multinomial_combinations(n_dim):
    for i in range(1,1+n_dim):
        for tup in itertools.combinations(range(1,i):
            yield tup

print("Check multinomial_combinations(4):")
for i in multinomial_combinations(4):
    print(i)

# 3. Sum based on from df_every_dim
def aggr_by_dims(df,by_dims):

    # guard
    if not (0 < len(by_dims) < n_dim):
        raise ValueError(f"Wrong n_dim={n_dim},len(by_dims)={len(by_dims)}")

    # by-columns
    by_cols = [f"Dim{i}" for i in by_dims]

    # groupby-sum
    df_grouped = df.groupby(by=by_cols).sum().reset_index()

    # create none-columns (cannot be empty here)
    arr = np.ones(n_dim+1,dtype=int)
    arr[list(by_dims)] = 0
    for i in range(1,1+n_dim):
        if arr[i] == 1:
            df_grouped[f"Dim{i}"] = None  # or np.nan as you wish

    # reorder columns
    return df_grouped[cols]

print("\nCheck aggr_by_dims(df_every_dim,[1,3]):")
print(aggr_by_dims(df_every_dim,3]))

# combine 2. and 3.
ls = []
for by_dims in multinomial_combinations(n_dim):
    if len(by_dims) < n_dim:
        df_grouped = aggr_by_dims(df_every_dim,by_dims)
        ls.append(df_grouped)

# no none-dimensions
ls.append(df_every_dim)

# final result
df_ans = pd.concat(ls,axis=0)
df_ans.reset_index(drop=True,inplace=True)
print(df_ans)

输出

(省略了中间输出)

    Dim1  Dim2  Dim3  Spend
0      A  None  None    300
1      B  None  None    700
2   None     X  None    400
3   None     Y  None    600
4   None  None     Z   1000
5      A     X  None    100
6      A     Y  None    200
7      B     X  None    300
8      B     Y  None    400
9      A  None     Z    300
10     B  None     Z    700
11  None     X     Z    400
12  None     Y     Z    600
13     A     X     Z    100
14     A     Y     Z    200
15     B     X     Z    300
16     B     Y     Z    400

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?