python - Pandas - 根据具有重复名称的重复键值对列 reshape 数据框列

标签 python pandas dataframe

我从 API 接收一个数据帧,其中包含初始列中某些实体的数据,后面的列包含这些实体的元数据。数据是专有的,所以我无法准确地显示它,但数据帧的结构如下所示:

idx  name types  value value_date        desc group owner key_name key_value   key_name   key_value   key_name  key_value
  1 name1 type1     45 2021-05-30 name1-type1    G1    O1       k1        A1         k2          A2         k3         A3
  2 name1 type2     23 2021-05-30 name1-type2    G1    O1       k3        B3        NaN         NaN         k2         B2
  3 name2 type1     41 2021-05-30 name2-type1    G2    O2      NaN       NaN         k1          C1        NaN        NaN
  4 name3 type1     39 2021-05-30 name3-type1    G1    O1       k1        D1         k3          D3        NaN        NaN
  5 name4 type1     40 2021-05-30 name4-type1    G3    O3       k1        E1         k3          E3         k2         E2
  6 name4 type2     21 2021-05-30 name4-type2    G3    O3       k3        F3         k2          F2         k1         F1
  7 name4 type3     11 2021-05-30 name4-type3    G3    O3      NaN       NaN        NaN         NaN        NaN        NaN
  8 name5 type1     44 2021-05-30 name5-type1    G1    O1      NaN       NaN         k1          H1        NaN        NaN
  9 name6 type1     49 2021-05-30 name6-type1    G2    O2      NaN       NaN         k2          I2        NaN        NaN
 10 name6 type2     26 2021-05-30 name6-type2    G2    O2       k1        J1        NaN         NaN         k3         J3

下面的代码将生成上面的示例数据帧:

df = pd.DataFrame( {'idx': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, 'name': {0: 'name1', 1: 'name1', 2: 'name2', 3: 'name3', 4: 'name4', 5: 'name4', 6: 'name4', 7: 'name5', 8: 'name6', 9: 'name6'}, 'types': {0: 'type1', 1: 'type2', 2: 'type1', 3: 'type1', 4: 'type1', 5: 'type2', 6: 'type3', 7: 'type1', 8: 'type1', 9: 'type2'}, 'value': {0: 45, 1: 23, 2: 41, 3: 39, 4: 40, 5: 21, 6: 11, 7: 44, 8: 49, 9: 26}, 'value_date': {0: '2021-05-30', 1: '2021-05-30', 2: '2021-05-30', 3: '2021-05-30', 4: '2021-05-30', 5: '2021-05-30', 6: '2021-05-30', 7: '2021-05-30', 8: '2021-05-30', 9: '2021-05-30'}, 'desc': {0: 'name1-type1', 1: 'name1-type2', 2: 'name2-type1', 3: 'name3-type1', 4: 'name4-type1', 5: 'name4-type2', 6: 'name4-type3', 7: 'name5-type1', 8: 'name6-type1', 9: 'name6-type2'}, 'group': {0: 'G1', 1: 'G1', 2: 'G2', 3: 'G1', 4: 'G3', 5: 'G3', 6: 'G3', 7: 'G1', 8: 'G2', 9: 'G2'}, 'owner': {0: 'O1', 1: 'O1', 2: 'O2', 3: 'O1', 4: 'O3', 5: 'O3', 6: 'O3', 7: 'O1', 8: 'O2', 9: 'O2'}, 'key_name': {0: 'k1', 1: 'k3', 2: float('nan'), 3: 'k1', 4: 'k1', 5: 'k3', 6: float('nan'), 7: float('nan'), 8: float('nan'), 9: 'k1'}, 'key_value': {0: 'A1', 1: 'B3', 2: float('nan'), 3: 'D1', 4: 'E1', 5: 'F3', 6: float('nan'), 7: float('nan'), 8: float('nan'), 9: 'J1'}, 'key_name_1': {0: 'k2', 1: float('nan'), 2: 'k1', 3: 'k3', 4: 'k3', 5: 'k2', 6: float('nan'), 7: 'k1', 8: 'k2', 9: float('nan')}, 'key_value_1': {0: 'A2', 1: float('nan'), 2: 'C1', 3: 'D3', 4: 'E3', 5: 'F2', 6: float('nan'), 7: 'H1', 8: 'I2', 9: float('nan')}, 'key_name_2': {0: 'k3', 1: 'k2', 2: float('nan'), 3: float('nan'), 4: 'k2', 5: 'k1', 6: float('nan'), 7: float('nan'), 8: float('nan'), 9: 'k3'}, 'key_value_2': {0: 'A3', 1: 'B2', 2: float('nan'), 3: float('nan'), 4: 'E2', 5: 'F1', 6: float('nan'), 7: float('nan'), 8: float('nan'), 9: 'J3'}} )
df.rename(columns={'key_name_1':'key_name','key_value_1':'key_value','key_name_2':'key_name','key_value_2':'key_value'}, inplace=True)

请注意所有者后面的重复“key_name”、“key_value”对列。这些列保存元数据值,因此 key_name 是元数据名称,key_value 是其值。现在,一个实体可以有不同数量的元数据,因此对于某些行,可能有 15-20 个这样的对列。

如果该元数据不适用于该实体,其他行将具有 NaN

我想将此数据框 reshape 为下面的数据框,其中每个 key_name 成为列,并且该列中的值应该是每个实体的 key_value (如果适用) ):

idx    name   types   value value_date        desc   group   owner      k1      k2      k3
  1   name1   type1      45 2021-05-30 name1-type1      G1      O1      A1      A2      A3
  2   name1   type2      23 2021-05-30 name1-type2      G1      O1     NaN      B2      B3
  3   name2   type1      41 2021-05-30 name2-type1      G2      O2      C1     NaN     NaN
  4   name3   type1      39 2021-05-30 name3-type1      G1      O1      D1     NaN      D3
  5   name4   type1      40 2021-05-30 name4-type1      G3      O3      E1      E2      E3
  6   name4   type2      21 2021-05-30 name4-type2      G3      O3      F1      F2      F3
  7   name4   type3      11 2021-05-30 name4-type3      G3      O3     NaN     NaN     NaN
  8   name5   type1      44 2021-05-30 name5-type1      G1      O1      H1     NaN     NaN
  9   name6   type1      49 2021-05-30 name6-type1      G2      O2     NaN      I2     NaN
 10   name6   type2      26 2021-05-30 name6-type2      G2      O2      J1     NaN      J3

现在的问题是,对于问题数据框中的每个实体,这些“key_name”、“key_value”对数据的顺序不同。如果您看到 name1-type1(k1, A1) 首先出现按顺序,然后 (k2, A2), .... 但对于 name4- type2, (k3, F3) 首先出现,然后是 k2 然后是 k1,完全相反。

我怀疑 API 中发生的情况是,对于每个唯一的实体,数据会在循环中获取,然后再串联,因此串联可以工作,但元数据的顺序无法保证。我无法修复该 API,因为它不是我的,因此我需要修复其输出才能继续。

最佳答案

来自 pyjanitor 的辅助工具组合可能有帮助:

# pip install pyjanitor
import janitor
import pandas as pd
(df.pivot_longer(index = slice("idx", "owner"), 
                 names_to=("names", "values"), 
                 names_pattern=["name", "value"], 
                 values_to="valued")
  .dropna()
  .pivot_wider(index = slice("idx", "owner"), 
               names_from="names")
  .merge(df.loc[:, "idx":"owner"], 
         how = 'outer')
  .sort_values('idx')
  )

    idx   name  types  value  value_date         desc group owner   k1   k3   k2
0    1  name1  type1     45  2021-05-30  name1-type1    G1    O1   A1   A3   A2
1    2  name1  type2     23  2021-05-30  name1-type2    G1    O1  NaN   B3   B2
2    3  name2  type1     41  2021-05-30  name2-type1    G2    O2   C1  NaN  NaN
3    4  name3  type1     39  2021-05-30  name3-type1    G1    O1   D1   D3  NaN
4    5  name4  type1     40  2021-05-30  name4-type1    G3    O3   E1   E3   E2
5    6  name4  type2     21  2021-05-30  name4-type2    G3    O3   F1   F3   F2
9    7  name4  type3     11  2021-05-30  name4-type3    G3    O3  NaN  NaN  NaN
6    8  name5  type1     44  2021-05-30  name5-type1    G1    O1   H1  NaN  NaN
7    9  name6  type1     49  2021-05-30  name6-type1    G2    O2  NaN  NaN   I2
8   10  name6  type2     26  2021-05-30  name6-type2    G2    O2   J1   J3  NaN

pivot_longer只是提供了一种更简单的方法来从宽到长 reshape - 对于您的情况,有一个模式(一些列有 name,一些 .value) - 我们在中使用该模式names_pattern 翻转 table 。 pivot_wider是建立在pandas hub上的,在这种情况下只是语法糖 - 这里使用的唯一原因只是因为我不想输入所有索引名称:),但你可以跳过它并只使用枢轴。结果排除了 idx 7,因为它完全为空... merging返回原来的 df 并重新引入它。

他们只是帮助者,所以我们可以不包括他们。这是实现此目的的一种可能方法:

融化列,保留原始索引:

index = [*df.columns[:8]]

base = (df.melt(index, value_name = "valued", ignore_index = False)
          .dropna()
          .drop(columns="variable"))

提取其中valued仅以K开头的数据帧,并在提取时将index附加到现有索引:

Ks = (base.loc[base.valued.str.startswith("k")]
          .set_index([*index], append = True)
      )

提取valued不以K开头的数据帧:

non_Ks = (base.loc[~base.valued.str.startswith("k")]
              .rename(columns={"valued":"flip_this_column"})
              .set_index(index, append = True)
           )

Ksnon_Ks合并,删除不相关的标签并重置索引:

(pd.concat([Ks, non_Ks], axis = 'columns')
   .set_index('valued',append=True)
   .unstack()
   .droplevel(0, axis = 'columns')
   .rename_axis(columns=None)
   .reset_index(index)
)



idx   name  types  value  value_date         desc group owner   k1   k2   k3
0    1  name1  type1     45  2021-05-30  name1-type1    G1    O1   A1   A2   A3
1    2  name1  type2     23  2021-05-30  name1-type2    G1    O1  NaN   B2   B3
2    3  name2  type1     41  2021-05-30  name2-type1    G2    O2   C1  NaN  NaN
3    4  name3  type1     39  2021-05-30  name3-type1    G1    O1   D1  NaN   D3
4    5  name4  type1     40  2021-05-30  name4-type1    G3    O3   E1   E2   E3
5    6  name4  type2     21  2021-05-30  name4-type2    G3    O3   F1   F2   F3
7    8  name5  type1     44  2021-05-30  name5-type1    G1    O1   H1  NaN  NaN
8    9  name6  type1     49  2021-05-30  name6-type1    G2    O2  NaN   I2  NaN
9   10  name6  type2     26  2021-05-30  name6-type2    G2    O2   J1  NaN   J3

关于python - Pandas - 根据具有重复名称的重复键值对列 reshape 数据框列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67759399/

相关文章:

python - 在 pandas 中乘以浮点列需要太多时间

python - 确定分组数据框中值的变化

r - 根据不同表的行值对表中的列值求和

python - Django:如何为模型实例预取相关内容。也许通过包装在查询集中?

python - 学习区间的并集

python - PyGame 中的 Conways 生命游戏

python - 获取错误无法在 '__main__' 中找到 'X' 模块

python - Altair:设置原始颜色值会弄乱 SortField

R:表格格式

r - 如何将 R 中的 colSums 结果转换为数据框