我从 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)
)
将Ks
与non_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/