Python熊猫:宽格式到长格式,但不同-类似于反向伪列

Python熊猫:宽格式到长格式,但不同-类似于反向伪列,python,pandas,stack,Python,Pandas,Stack,Sum_值是CS和SC特定组合的所有值的总和 我花了1.5天,无法转换它。使用了stack、transpose和groupby,但没有任何效果。10天前开始编码,刚开始编码,请帮助。请看图片,我无法在文本区域正确粘贴表格 好的,你可以这样做: df = pd.DataFrame({'Product':['R123','R234'], 'Price':[1.18,0.23], 'CS_Medium':[

Sum_值是CS和SC特定组合的所有值的总和

我花了1.5天,无法转换它。使用了stack、transpose和groupby,但没有任何效果。10天前开始编码,刚开始编码,请帮助。请看图片,我无法在文本区域正确粘贴表格


好的,你可以这样做:

df = pd.DataFrame({'Product':['R123','R234'],
                        'Price':[1.18,0.23],
                        'CS_Medium':[.15, np.nan],
                        'CS_Small':[np.nan, -0.03],
                        'SC_A':[np.nan,0.04],
                        'SC_B':[np.nan,np.nan],
                        'SC_C':[0.38,0.05]})

df.columns = df.columns.str.split('_').str[-1]

(df.melt(['Product','Medium','Small','Price'],value_name='Values_1', var_name='SC')
  .melt(['Product','SC','Price','Values_1'],value_name='Values_2',var_name='CS')
  .set_index(['Product','CS','SC','Price'])
  .sum(axis=1)
  .reset_index(name='SUM_Values')
  .sort_values(by=['Product','CS','SC']))
输出:

   Product      CS SC  Price  SUM_values
0     R123  Medium  A   1.18        0.15
2     R123  Medium  B   1.18        0.15
4     R123  Medium  C   1.18        0.53
6     R123   Small  A   1.18         NaN
8     R123   Small  B   1.18         NaN
10    R123   Small  C   1.18        0.38
1     R234  Medium  A   0.23        0.04
3     R234  Medium  B   0.23         NaN
5     R234  Medium  C   0.23        0.05
7     R234   Small  A   0.23        0.01
9     R234   Small  B   0.23       -0.03
11    R234   Small  C   0.23        0.02

好的,你可以这样做:

df = pd.DataFrame({'Product':['R123','R234'],
                        'Price':[1.18,0.23],
                        'CS_Medium':[.15, np.nan],
                        'CS_Small':[np.nan, -0.03],
                        'SC_A':[np.nan,0.04],
                        'SC_B':[np.nan,np.nan],
                        'SC_C':[0.38,0.05]})

df.columns = df.columns.str.split('_').str[-1]

(df.melt(['Product','Medium','Small','Price'],value_name='Values_1', var_name='SC')
  .melt(['Product','SC','Price','Values_1'],value_name='Values_2',var_name='CS')
  .set_index(['Product','CS','SC','Price'])
  .sum(axis=1)
  .reset_index(name='SUM_Values')
  .sort_values(by=['Product','CS','SC']))
输出:

   Product      CS SC  Price  SUM_values
0     R123  Medium  A   1.18        0.15
2     R123  Medium  B   1.18        0.15
4     R123  Medium  C   1.18        0.53
6     R123   Small  A   1.18         NaN
8     R123   Small  B   1.18         NaN
10    R123   Small  C   1.18        0.38
1     R234  Medium  A   0.23        0.04
3     R234  Medium  B   0.23         NaN
5     R234  Medium  C   0.23        0.05
7     R234   Small  A   0.23        0.01
9     R234   Small  B   0.23       -0.03
11    R234   Small  C   0.23        0.02
我用的是从宽到长

详细信息:

v1
Out[38]: 
              SCKey    SC
Product Price            
R123    1.18      A   NaN
        1.18      B   NaN
        1.18      C  0.38
R234    0.23      A  0.04
        0.23      B   NaN
        0.23      C  0.05
v2
Out[39]: 
                CSKey    CS
Product Price              
R123    1.18   Medium  0.15
        1.18    Small   NaN
R234    0.23   Medium   NaN
        0.23    Small -0.03
我用的是从宽到长

详细信息:

v1
Out[38]: 
              SCKey    SC
Product Price            
R123    1.18      A   NaN
        1.18      B   NaN
        1.18      C  0.38
R234    0.23      A  0.04
        0.23      B   NaN
        0.23      C  0.05
v2
Out[39]: 
                CSKey    CS
Product Price              
R123    1.18   Medium  0.15
        1.18    Small   NaN
R234    0.23   Medium   NaN
        0.23    Small -0.03
选择1 不太明显,但没有硬编码值

from itertools import product

d_ = df.set_index('Product')
prc = d_.pop('Price')

d_.columns = d_.columns.str.split('_', expand=True)

c = d_.columns
l0 = c.levels[0]
l1 = c.levels[1]
b0 = c.labels[0]
b1 = c.labels[1]

r0 = range(len(l0))
ptups = list(product(*(l1[b1][b0 == i] for i in r0)))

midx = pd.MultiIndex.from_tuples(
    [(x,) + t for x in l0 for t in ptups],
    names=['key'] + l0.tolist()
)
n = midx.nlevels

_d = d_[[(x0, x1) for x0, y1 in zip(l0, zip(*ptups)) for x1 in y1]]
_d.columns = midx
_d = _d.stack(list(range(1, n)), dropna=False)

_d.fillna(0).sum(1).where(_d.notna().any(1)).reset_index(name='SUM_values')

   Product      CS SC  SUM_values
0     R123  Medium  A        0.15
1     R123  Medium  B        0.15
2     R123  Medium  C        0.53
3     R123   Small  A         NaN
4     R123   Small  B         NaN
5     R123   Small  C        0.38
6     R234  Medium  A        0.04
7     R234  Medium  B         NaN
8     R234  Medium  C        0.05
9     R234   Small  A        0.01
10    R234   Small  B       -0.03
11    R234   Small  C        0.02
选择2 使用defaultdict和for循环

选择3 使用defaultdict、itertools.product和lookup

选择1 不太明显,但没有硬编码值

from itertools import product

d_ = df.set_index('Product')
prc = d_.pop('Price')

d_.columns = d_.columns.str.split('_', expand=True)

c = d_.columns
l0 = c.levels[0]
l1 = c.levels[1]
b0 = c.labels[0]
b1 = c.labels[1]

r0 = range(len(l0))
ptups = list(product(*(l1[b1][b0 == i] for i in r0)))

midx = pd.MultiIndex.from_tuples(
    [(x,) + t for x in l0 for t in ptups],
    names=['key'] + l0.tolist()
)
n = midx.nlevels

_d = d_[[(x0, x1) for x0, y1 in zip(l0, zip(*ptups)) for x1 in y1]]
_d.columns = midx
_d = _d.stack(list(range(1, n)), dropna=False)

_d.fillna(0).sum(1).where(_d.notna().any(1)).reset_index(name='SUM_values')

   Product      CS SC  SUM_values
0     R123  Medium  A        0.15
1     R123  Medium  B        0.15
2     R123  Medium  C        0.53
3     R123   Small  A         NaN
4     R123   Small  B         NaN
5     R123   Small  C        0.38
6     R234  Medium  A        0.04
7     R234  Medium  B         NaN
8     R234  Medium  C        0.05
9     R234   Small  A        0.01
10    R234   Small  B       -0.03
11    R234   Small  C        0.02
选择2 使用defaultdict和for循环

选择3 使用defaultdict、itertools.product和lookup


我知道你不能在帖子中包含数据的原因吗?在链接和图片中添加了数据,我不知道如何将其作为文本包含。感谢PiRSquared、Scott和Wen的回答。如何实现自动化,而不是硬编码列名。唯一硬编码的名称是SUM_值。这个转换是一个自动化的长过程的一部分,我没有机会看到列的名称。我唯一知道的是,在输入表中,列名用列级分隔列名。例如,在SC_A、SC_B中;我知道前面是列名SC,下划线后面是列级别A、B和C。我已经用一个通用的解决方案更新了我的帖子。我知道你不能在帖子中包含数据的原因吗?在链接和图片中添加了数据,我不知道如何作为文本包含。感谢PiRSquared、Scott和Wen的回答。如何实现自动化,而不是硬编码列名。唯一硬编码的名称是SUM_值。这个转换是一个自动化的长过程的一部分,我没有机会看到列的名称。我唯一知道的是,在输入表中,列名用列级分隔列名。例如,在SC_A、SC_B中;我知道前面是列名SC,下划线后面是列级别A、B和C。我已经用一个通用解决方案更新了我的帖子。对于r0中的I,ptups=listproduct*l1[b1][b0==I]。在选项1中,上面的行显示产品的获取错误。错误是产品未定义。我尝试将产品定义为元组,但没有成功。很抱歉,我忘记了导入。没问题,这非常有用,现在一切都正常,将扩展到30-40列。这里唯一的变化是我将_d.notna替换为_d.notnull。完成此更改是因为我获取了错误AttributeError:“DataFrame”对象没有属性“notna”。感谢您的帮助。对于r0中的i,ptups=listproduct*l1[b1][b0==i]。在选项1中,上面的行显示产品的获取错误。错误是产品未定义。我尝试将产品定义为元组,但没有成功。很抱歉,我忘记了导入。没问题,这非常有用,现在一切都正常,将扩展到30-40列。这里唯一的变化是我将_d.notna替换为_d.notnull。完成此更改是因为我获取了错误AttributeError:“DataFrame”对象没有属性“notna”。谢谢你的帮助。
from itertools import product
from collections import defaultdict

d = defaultdict(list)
for c in df.columns:
    k, *v = c.split('_')
    if v:
        d[k].append(v[0])

d = {**df[['Product']].to_dict('l'), **d}

d_ = df.set_index('Product')

ndf = pd.DataFrame(dict(zip(d.keys(), zip(*product(*d.values())))))

cs = pd.Series(d_.lookup(ndf.Product, ndf.CS.radd('CS_')), ndf.index)
sc = pd.Series(d_.lookup(ndf.Product, ndf.SC.radd('SC_')), ndf.index)

ndf['SUM_values'] = cs.add(sc, fill_value=0)
ndf[['Product', 'CS', 'SC', 'SUM_values']]

   Product      CS SC  SUM_values
0     R123  Medium  A        0.15
1     R123  Medium  B        0.15
2     R123  Medium  C        0.53
3     R123   Small  A         NaN
4     R123   Small  B         NaN
5     R123   Small  C        0.38
6     R234  Medium  A        0.04
7     R234  Medium  B         NaN
8     R234  Medium  C        0.05
9     R234   Small  A        0.01
10    R234   Small  B       -0.03
11    R234   Small  C        0.02