【问题标题】:Python3 how to assign an ordinal value from a column and create multiple rows based on another columnPython3如何从一列分配一个序数值并基于另一列创建多行
【发布时间】:2021-03-23 08:32:55
【问题描述】:

如何通过在 ColA 值中创建新列以逗号“,”拆分并分配其排序值来转换数据集。 PLus 为 ColB 创建多行,按空格“”分割?在为索引创建另一列时

当前数据框

Record_No         COlA           ColB
 1                A1,A2,A3       B1 B2 
 2                A4,A5          B3
 3                A1,A4,A2     

预期结果

NewNo.  Record_No         A1    A2    A3   A4   A5     ColB
  1        1               1     2    3    0    0       B1
  2        1               1     2    3    0    0       B2
  3        2               0     0    0    1    2       B3 
  4        3               1     3    0    2    0       Blank 

【问题讨论】:

  • 请检查答案@foy

标签: python python-3.x dataframe etl


【解决方案1】:

你必须使用:

  • str.split 将字符串从 COlAColB 转换为列表
  • explode 将这些列表转换为行
  • get_dummies 构建包含 0 和 1 值的指标列
  • group-by.sum 按 Record_No,ColB 对对以上行进行分组

困难的部分是您想在 Ai 列中使用排序值而不仅仅是 1。所以我会使用enumerate 来获取该排序值并使用它来乘以get_dummies 将提供的值。

可能的代码:

# explode the "lists" and keep the ordering value for COlA
result = df.assign(COlA=df['COlA'].str.split(',').apply(
    lambda x: list(enumerate(x, 1)))).assign(ColB=df['ColB'].str.split(' ')
                                             ).explode('COlA').explode('ColB')

# separate the ordering value from the value itself in different columns
result['Coeff'] = result['COlA'].apply(lambda x: x[0])
result['COlA'] = result['COlA'].apply(lambda x: x[1])

它给出:

   Record_No COlA  ColB  Coeff
0          1   A1    B1      1
0          1   A1    B2      1
0          1   A2    B1      2
0          1   A2    B2      2
0          1   A3    B1      3
0          1   A3    B2      3
1          2   A4    B3      1
1          2   A5    B3      2
2          3   A1  None      1
2          3   A4  None      2
2          3   A2  None      3

让我们继续:

# build the indicator values and replace None with Blank in ColB
result = pd.get_dummies(result.fillna('Blank'), columns=['COlA'])

# multiply the indicator value by the ordering value
result.iloc[:, 3:] = np.transpose(np.transpose(result.iloc[:, 3:].values
                                             ) * result.Coeff.values)

我们有:

   Record_No   ColB  Coeff  COlA_A1  COlA_A2  COlA_A3  COlA_A4  COlA_A5
0          1     B1      1        1        0        0        0        0
0          1     B2      1        1        0        0        0        0
0          1     B1      2        0        2        0        0        0
0          1     B2      2        0        2        0        0        0
0          1     B1      3        0        0        3        0        0
0          1     B2      3        0        0        3        0        0
1          2     B3      1        0        0        0        1        0
1          2     B3      2        0        0        0        0        2
2          3  Blank      1        1        0        0        0        0
2          3  Blank      2        0        0        0        2        0
2          3  Blank      3        0        3        0        0        0

只需重命名列、分组值并删除现在无用的 Coeff 列

result = result.drop(columns='Coeff').rename(
    columns=lambda x: x.replace('COlA_', '')).groupby(
        ['Record_No', 'ColB']).sum().reset_index()

我们得到期望值:

   Record_No   ColB  A1  A2  A3  A4  A5
0          1     B1   1   2   3   0   0
1          1     B2   1   2   3   0   0
2          2     B3   0   0   0   1   2
3          3  Blank   1   3   0   2   0

如果您需要 NewNo.列,它现在是微不足道的:

result = result.rename_axis('NewNo.').reset_index()

我们终于有了:

   NewNo.  Record_No   ColB  A1  A2  A3  A4  A5
0       0          1     B1   1   2   3   0   0
1       1          1     B2   1   2   3   0   0
2       2          2     B3   0   0   0   1   2
3       3          3  Blank   1   3   0   2   0

【讨论】:

  • 您可以在pd.get_dummies 中使用prefix='', prefix_sep='' 来简化一些语句。
  • 感谢您的帮助 Serge,然而,第一条记录 NewNo.0 Record_No 1 的 A1 >1 而不是 1 –
【解决方案2】:

只需三个简单的步骤即可完成。

首先,创建ColB的分解图

df['ColB'] = df.ColB.str.split(' ')
exp_df = df.explode('ColB')

然后,用ColA中的项目索引创建列

index_df = (
    exp_df.COlA.apply(lambda x: pd.Series(
        {v:i for i, v in enumerate(x)}
    )
).add(1).fillna(0).astype(int)

然后将两者连接起来

pd.concat([exp_df, index_df], axis=1)

输出

   Record_No          COlA  ColB  A1  A2  A3  A4  A5
0          1  [A1, A2, A3]    B1   1   2   3   0   0
0          1  [A1, A2, A3]    B2   1   2   3   0   0
1          2      [A4, A5]    B3   0   0   0   1   2
2          3  [A1, A4, A2]  None   1   3   0   2   0

注意:如果需要,您可以删除 COlA

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    • 2015-03-10
    • 2022-12-05
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 2021-12-02
    相关资源
    最近更新 更多