【问题标题】:How to transform rows of other columns to columns on the basis of unique values of a column?如何根据列的唯一值将其他列的行转换为列?
【发布时间】:2021-06-07 05:40:18
【问题描述】:

假设我在以下结构中有一个 df,

column1 | column2 | column3 | column4 | column5 | column6 | column7
   A    |    B    |    C    |    10   |    78   |   12    |  202001
   A    |    B    |    D    |    21   |    64   |   87    |  202001
   A    |    B    |    E    |    21   |    64   |   87    |  202001
   X    |    K    |    C    |    54   |    23   |   23    |  202001
   X    |    K    |    D    |    21   |    55   |   87    |  202001
   X    |    K    |    E    |    21   |    43   |   22    |  202001
   A    |    B    |    C    |    10   |    78   |   12    |  202002
   A    |    B    |    D    |    23   |    64   |   87    |  202002
   A    |    B    |    E    |    21   |    11   |   34    |  202002
   Z    |    K    |    C    |    10   |    78   |   12    |  202002
   Z    |    K    |    D    |    21   |    13   |   56    |  202002
   Z    |    K    |    E    |    12   |    77   |   34    |  202002

column1 和 column2 之间的关系 - 一对多

column2 与 column1 之间的关系 - 一对多

预期输出:

column1 | column2 | column3 | column4_202001 | column5_202001 | column6_202001 | column4_202002 | column5_202002 | column6_202002 |
   A    |    B    |    C    |      10        |       78       |       12       |      10        |      78        |      12        |
   A    |    B    |    D    |      21        |       64       |       87       |      23        |      64        |      87        |
   A    |    B    |    E    |      21        |       64       |       87       |      21        |      11        |      34        |   
   X    |    K    |    C    |      54        |       23       |       23       |       0        |       0        |       0        |   
   X    |    K    |    D    |      21        |       55       |       87       |       0        |       0        |       0        |   
   X    |    K    |    E    |      21        |       43       |       22       |       0        |       0        |       0        |    
   Z    |    K    |    C    |       0        |        0       |        0       |      10        |      78        |      12        |    
   Z    |    K    |    D    |       0        |        0       |        0       |      21        |      13        |      56        |   
   Z    |    K    |    E    |       0        |        0       |        0       |      12        |      77        |      34        |  

另外,在转换时,我可以在 column6_yyyymm 旁边为每个 column7 创建一个空列吗?

最终输出,

column1 | column2 | column3 | column4_202001 | column5_202001 | column6_202001 |   empty_202001 | column4_202002 | column5_202002 | column6_202002 | empty_202002 ....
   A    |    B    |    C    |      10        |       78       |       12       |                |      10        |      78        |      12        |
   A    |    B    |    D    |      21        |       64       |       87       |                |      23        |      64        |      87        |
   A    |    B    |    E    |      21        |       64       |       87       |                |      21        |      11        |      34        |   
   X    |    K    |    C    |      54        |       23       |       23       |                |      0         |       0        |       0        |   
   X    |    K    |    D    |      21        |       55       |       87       |                |      0         |       0        |       0        |   
   X    |    K    |    E    |      21        |       43       |       22       |                |      0         |       0        |       0        |    
   Z    |    K    |    C    |       0        |        0       |        0       |                |      10        |      78        |      12        |    
   Z    |    K    |    D    |       0        |        0       |        0       |                |      21        |      13        |      56        |   
   Z    |    K    |    E    |       0        |        0       |        0       |                |      12        |      77        |      34        | 

如何使用 python 函数和/或 pandas 库实现最终输出?如果有什么不清楚的地方请告诉我。

更新:

对于所有 empty_yyyymm 列我想实现以下功能,

        def get_final(row):
        if row['column2'].isin(['H', 'S', 'Z']):
            return 0
        elif row['column4_yyyymm'] + row['column5_yyyymm'] - row['column6_yyyymm'] < 0 and not row['column2'].isin(['H', 'S', 'Z']):
            return 0
        else:
            return row['column4_yyyymm'] + row['column5_yyyymm'] - row['column6_yyyymm']

如何也能做到这一点?

注意:yyyymm 是引用 column7 的通用方式。它实际上不是一个列。

【问题讨论】:

    标签: python pandas dataframe data-manipulation


    【解决方案1】:

    首先通过DataFrame.assign 创建空列,然后通过DataFrame.set_index 使用DataFrame.unstack 重塑,并通过DataFrame.sort_index 在第二级排序日期时间:

    df = (df.assign(empty = np.nan)
            .set_index(['column1','column2','column3','column7'])
            .unstack(fill_value=0)
            .sort_index(level=1, axis=1))
    

    然后设置所有empty 列的缺失值,将MultiIndex in columns 扁平化map,最后将index 转换为DataFrame.reset_index 的列:

    df['empty'] = np.nan
    #if need fill by empty string
    #df['empty'] = ''
    df.columns = df.columns.map(lambda x: f'{x[0]}_{x[1]}')
    df = df.reset_index()
    print (df)
      column1 column2 column3  column4_202001  column5_202001  column6_202001  \
    0       A       B       C              10              78              12   
    1       A       B       D              21              64              87   
    2       A       B       E              21              64              87   
    3       X       K       C              54              23              23   
    4       X       K       D              21              55              87   
    5       X       K       E              21              43              22   
    6       Z       K       C               0               0               0   
    7       Z       K       D               0               0               0   
    8       Z       K       E               0               0               0   
    
       empty_202001  column4_202002  column5_202002  column6_202002  empty_202002  
    0           NaN              10              78              12           NaN  
    1           NaN              23              64              87           NaN  
    2           NaN              21              11              34           NaN  
    3           NaN               0               0               0           NaN  
    4           NaN               0               0               0           NaN  
    5           NaN               0               0               0           NaN  
    6           NaN              10              78              12           NaN  
    7           NaN              21              13              56           NaN  
    8           NaN              12              77              34           NaN  
    

    编辑:首先按条件计算新列empty,然后在不设置NaN 的情况下应用上面的解决方案:

    m1 = df['column2'].isin(['H', 'S', 'Z'])
    
    s = df['column4'] + df['column5'] - df['column6']
    m2 = (s < 0) & ~m1
    
    out = np.where(m1 | m2, 0, s)
    df = (df.assign(empty = out)
            .set_index(['column1','column2','column3','column7'])
            .unstack(fill_value=0)
            .sort_index(level=1, axis=1))
    
    df.columns = df.columns.map(lambda x: f'{x[0]}_{x[1]}')
    df = df.reset_index()
    

    print (df)
      column1 column2 column3  column4_202001  column5_202001  column6_202001  \
    0       A       B       C              10              78              12   
    1       A       B       D              21              64              87   
    2       A       B       E              21              64              87   
    3       X       K       C              54              23              23   
    4       X       K       D              21              55              87   
    5       X       K       E              21              43              22   
    6       Z       K       C               0               0               0   
    7       Z       K       D               0               0               0   
    8       Z       K       E               0               0               0   
    
       empty_202001  column4_202002  column5_202002  column6_202002  empty_202002  
    0            76              10              78              12            76  
    1             0              23              64              87             0  
    2             0              21              11              34             0  
    3            54               0               0               0             0  
    4             0               0               0               0             0  
    5            42               0               0               0             0  
    6             0              10              78              12            76  
    7             0              21              13              56             0  
    8             0              12              77              34            55  
    

    【讨论】:

    • 感谢您的回答!我为这个问题添加了一个小的更新。您认为对给定的 empty_yyyymm 列使用该函数的最佳方法是什么?每个 empty_yyyymm 列将引用其各自的 column4_yyyymm、column5_yyyymm、column6_yyyymm。如果有任何不清楚的地方,请告诉我。
    • @royalewithcheese - 我明白了,我需要一些时间。但可能是第一眼
    • 当然,没问题:)
    • @royalewithcheese - 功能应该改变吗?例如测试str(row['column2']) in ['H', 'S', 'Z'] 使用df['column2'].isin(['H', 'S', 'Z']) ?
    • 当然,只要它检查 column2 是否具有其中一个值..
    【解决方案2】:

    尝试:

    df1 = (df.set_index(['column1', 'column2', 'column3', 'column7'])
       .rename_axis(['idx'], axis=1)
       .unstack('column7')
       .reset_index().fillna(0))
    df1.columns = df1.columns.map(lambda x: '_'.join([str(i) for i in x]) if (x[1])!='' else x[0])
    

    column1 column2 column3 column4_202001 column4_202002 column5_202001 column5_202002 column6_202001 column6_202002
    0 A B C 10.0 10.0 78.0 78.0 12.0 12.0
    1 A B D 21.0 23.0 64.0 64.0 87.0 87.0
    2 A B E 21.0 21.0 64.0 11.0 87.0 34.0
    3 X K C 54.0 0.0 23.0 0.0 23.0 0.0
    4 X K D 21.0 0.0 55.0 0.0 87.0 0.0
    5 X K E 21.0 0.0 43.0 0.0 22.0 0.0
    6 Z K C 0.0 10.0 0.0 78.0 0.0 12.0
    7 Z K D 0.0 21.0 0.0 13.0 0.0 56.0
    8 Z K E 0.0 12.0 0.0 77.0 0.0 34.0

    【讨论】:

    • 我没有投反对票,但可能是因为您忘记添加空列,因为它是问题的标准之一。我已经更新了我的问题,请看一下。
    猜你喜欢
    • 2023-02-07
    • 2015-10-10
    • 1970-01-01
    • 1970-01-01
    • 2015-05-30
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多