我可以根据元组列表在 pandas 数据框中旋转一列吗?
Can I pivot a column in a pandas dataframe based on a list of tuples?
我正在尝试按如下方式更改数据框的结构。我有一个包含历史 KPI 信息的数据集:每条记录包含日期、KPI ID、多个维度和 KPI 值。
基于 3 元组列表,我想转换此数据框,以便最终结果是现有数据框中的 2 条记录与分子和分母的组合,每条记录都来自具有相同 date/dimensions.
当前数据帧:
Date | KPI_ID | Dimension | Value
Apr 5 | KPI_1 | Lorem | 1
Apr 5 | KPI_2 | Lorem | 3
Apr 5 | KPI_1 | Ipsum | 4
Apr 5 | KPI_2 | Ipsum | 8
Apr 5 | KPI_3 | Dolor | 2
Apr 5 | KPI_4 | Dolor | 2
给出 KPI_IDs 组合的三元组列表,例如 [Result_ID、KPI_Numerator、KPI_Denominator]:
[['Result_1', 'KPI_1', 'KPI_2'], ['Result_2', 'KPI_3', 'KPI_4']]
想要的结果:
Date | Result_ID | Dimension | Numerator | Denominator
Apr 5 | Result_1 | Lorem | 1 | 3
Apr 5 | Result_1 | Ipsum | 4 | 8
Apr 5 | Result_2 | Dolor | 2 | 2
我曾尝试将 df.merge 和 df.groupby 与聚合函数一起使用,但我很难理解如何才能最好地将元组列表整合到等式中。遍历数据框似乎不是答案,因为我必须手动查找具有完全相同维度的记录,我认为这是不高效的。
您可以创建一个组合(Result_ID、KPI_1、KPI_2)的dataframe,然后先根据KPI_1合并两次到原始dataframe,然后然后在KPI_2(这次也在时间和维度上匹配):
# Create combinations dataframe
cs = [['Result_1', 'KPI_1', 'KPI_2'], ['Result_2', 'KPI_3', 'KPI_4']]
df_cs = pd.DataFrame(cs, columns=['Result_ID', 'KPI_1', 'KPI_2'])
# Merge combinations dataframe to original data:
# 1. So that 'KPI_1' in combinations = 'KPI_ID' in data
# 2. So that 'KPI_2' in combinations = 'KPI_ID' in data,
# and we get a match on ['Date', 'Dimension']
cols = ['Date', 'Result_ID', 'Dimension', 'Numerator', 'Denominator']
df_out = (df_cs
.merge(df.rename(columns={'Value': 'Numerator'}),
left_on='KPI_1', right_on='KPI_ID')
.drop(columns='KPI_ID')
.merge(df.rename(columns={'Value': 'Denominator'}),
left_on=['Date', 'Dimension', 'KPI_2'],
right_on=['Date', 'Dimension', 'KPI_ID'])
.drop(columns=['KPI_ID', 'KPI_1', 'KPI_2'])
)[cols]
输出:
Date Result_ID Dimension Numerator Denominator
0 Apr 5 Result_1 Lorem 1 3
1 Apr 5 Result_1 Ipsum 4 8
2 Apr 5 Result_2 Dolor 2 2
让我们在每个映射中创建一个组合,将 Result
与 KPIs
配对。
创建此组合的数据框,与原始数据框合并,透视,最后进行一些按摩,以获得 OP 所需的最终形式的数据。
需要注意的是 pivot
需要 index
和 columns
的独特组合;对于共享的数据,就不用担心了。
from itertools import product, chain
mapping = [['Result_1', 'KPI_1', 'KPI_2'], ['Result_2', 'KPI_3', 'KPI_4']]
maps = (product([left], [*right]) for left, *right in mapping)
maps = chain.from_iterable(maps)
maps = pd.DataFrame(maps, columns=['Result_ID', 'KPI_ID'])
maps
Result_ID KPI_ID
0 Result_1 KPI_1
1 Result_1 KPI_2
2 Result_2 KPI_3
3 Result_2 KPI_4
(df
.merge(maps, how='left', on='KPI_ID')
.assign(KPI_ID = lambda df: df.KPI_ID.map({"KPI_1":"Numerator",
"KPI_2":"Denominator",
"KPI_3":"Numerator",
"KPI_4":"Denominator"}),
sorter = lambda df: df.Dimension.factorize()[0])
.pivot(['Date','Result_ID','Dimension', 'sorter'],
'KPI_ID',
'Value')
.rename_axis(columns=None)
.sort_values('sorter')
.droplevel('sorter')
.iloc[:, ::-1]
.reset_index()
)
Date Result_ID Dimension Numerator Denominator
0 Apr 5 Result_1 Lorem 1 3
1 Apr 5 Result_1 Ipsum 4 8
2 Apr 5 Result_2 Dolor 2 2
我正在尝试按如下方式更改数据框的结构。我有一个包含历史 KPI 信息的数据集:每条记录包含日期、KPI ID、多个维度和 KPI 值。
基于 3 元组列表,我想转换此数据框,以便最终结果是现有数据框中的 2 条记录与分子和分母的组合,每条记录都来自具有相同 date/dimensions.
当前数据帧:
Date | KPI_ID | Dimension | Value
Apr 5 | KPI_1 | Lorem | 1
Apr 5 | KPI_2 | Lorem | 3
Apr 5 | KPI_1 | Ipsum | 4
Apr 5 | KPI_2 | Ipsum | 8
Apr 5 | KPI_3 | Dolor | 2
Apr 5 | KPI_4 | Dolor | 2
给出 KPI_IDs 组合的三元组列表,例如 [Result_ID、KPI_Numerator、KPI_Denominator]:
[['Result_1', 'KPI_1', 'KPI_2'], ['Result_2', 'KPI_3', 'KPI_4']]
想要的结果:
Date | Result_ID | Dimension | Numerator | Denominator
Apr 5 | Result_1 | Lorem | 1 | 3
Apr 5 | Result_1 | Ipsum | 4 | 8
Apr 5 | Result_2 | Dolor | 2 | 2
我曾尝试将 df.merge 和 df.groupby 与聚合函数一起使用,但我很难理解如何才能最好地将元组列表整合到等式中。遍历数据框似乎不是答案,因为我必须手动查找具有完全相同维度的记录,我认为这是不高效的。
您可以创建一个组合(Result_ID、KPI_1、KPI_2)的dataframe,然后先根据KPI_1合并两次到原始dataframe,然后然后在KPI_2(这次也在时间和维度上匹配):
# Create combinations dataframe
cs = [['Result_1', 'KPI_1', 'KPI_2'], ['Result_2', 'KPI_3', 'KPI_4']]
df_cs = pd.DataFrame(cs, columns=['Result_ID', 'KPI_1', 'KPI_2'])
# Merge combinations dataframe to original data:
# 1. So that 'KPI_1' in combinations = 'KPI_ID' in data
# 2. So that 'KPI_2' in combinations = 'KPI_ID' in data,
# and we get a match on ['Date', 'Dimension']
cols = ['Date', 'Result_ID', 'Dimension', 'Numerator', 'Denominator']
df_out = (df_cs
.merge(df.rename(columns={'Value': 'Numerator'}),
left_on='KPI_1', right_on='KPI_ID')
.drop(columns='KPI_ID')
.merge(df.rename(columns={'Value': 'Denominator'}),
left_on=['Date', 'Dimension', 'KPI_2'],
right_on=['Date', 'Dimension', 'KPI_ID'])
.drop(columns=['KPI_ID', 'KPI_1', 'KPI_2'])
)[cols]
输出:
Date Result_ID Dimension Numerator Denominator
0 Apr 5 Result_1 Lorem 1 3
1 Apr 5 Result_1 Ipsum 4 8
2 Apr 5 Result_2 Dolor 2 2
让我们在每个映射中创建一个组合,将 Result
与 KPIs
配对。
创建此组合的数据框,与原始数据框合并,透视,最后进行一些按摩,以获得 OP 所需的最终形式的数据。
需要注意的是 pivot
需要 index
和 columns
的独特组合;对于共享的数据,就不用担心了。
from itertools import product, chain
mapping = [['Result_1', 'KPI_1', 'KPI_2'], ['Result_2', 'KPI_3', 'KPI_4']]
maps = (product([left], [*right]) for left, *right in mapping)
maps = chain.from_iterable(maps)
maps = pd.DataFrame(maps, columns=['Result_ID', 'KPI_ID'])
maps
Result_ID KPI_ID
0 Result_1 KPI_1
1 Result_1 KPI_2
2 Result_2 KPI_3
3 Result_2 KPI_4
(df
.merge(maps, how='left', on='KPI_ID')
.assign(KPI_ID = lambda df: df.KPI_ID.map({"KPI_1":"Numerator",
"KPI_2":"Denominator",
"KPI_3":"Numerator",
"KPI_4":"Denominator"}),
sorter = lambda df: df.Dimension.factorize()[0])
.pivot(['Date','Result_ID','Dimension', 'sorter'],
'KPI_ID',
'Value')
.rename_axis(columns=None)
.sort_values('sorter')
.droplevel('sorter')
.iloc[:, ::-1]
.reset_index()
)
Date Result_ID Dimension Numerator Denominator
0 Apr 5 Result_1 Lorem 1 3
1 Apr 5 Result_1 Ipsum 4 8
2 Apr 5 Result_2 Dolor 2 2