我有一个大型的DataFrame,如下所示:
+----------------------------------------------------------+
| Date Category Location ImpactRate |
+----------------------------------------------------------+
| 2018-04-22 Outage MT 0.05194 |
| 2018-04-22 Outage ND 0.02552 |
| 2018-04-22 Outage SD 0.09962 |
| 2018-04-24 Transport TX 0.03111 |
+----------------------------------------------------------+
我要做的是创建以下输出:
+-----------------------------------------------------------------------------------+
| Date Category ImpactRate Break Down |
+-----------------------------------------------------------------------------------+
| 2018-04-22 Outage 0.17708 MT (29.3%) SD (14.4%) ND (56.3%) |
| 2018-04-24 Transport 0.03111 TX (100.0%) |
+-----------------------------------------------------------------------------------+
首次尝试 - GroupBy
grouped_df = df.groupby('Date')['ImpactRate'].apply(list).apply(pd.Series).rename(columns=df['Location'])'
这会创建一个包含NaN的DataFrame,其中每个Location都不存在,并创建需要格式化的其他列。
第二次尝试 - 使用itertuples()循环:
r = []
for item in df.itertuples():
temp_x = df.loc[((df['Category'] == item[2]) & (df['Date'] == item[1]))
for i in range(temp_x.shape[0]):
r.append(temp_x['ImpactRate'].iloc[i])
这会创建一个巨大的ImpactRate列表 - 这会让我回到原点。
我不知道如何解决这个问题。我猜我应该在每个迭代的列表中列出一个列表,但我一直在圈子里。如何以最pythonic的方式实现此输出? (请解释,以便我可以学习!)
答案 0 :(得分:1)
这是使用围绕groupby.transform
的矢量化功能的一种方式。我已将Breakdown
系列定义为元组列表,因为这是最灵活的格式。如果您愿意,可以应用特定的字符串格式。
import pandas as pd
df = pd.DataFrame({'Date': ['2018-04-22', '2018-04-22', '2018-04-22', '2018-04-24'],
'Category': ['Outage', 'Outage', 'Outage', 'Transport'],
'Location': ['MT', 'ND', 'SD', 'TX'],
'ImpactRate': [0.05194, 0.02552, 0.09962, 0.03111]})
# apply ratio
df['Total'] = df.groupby(['Date', 'Category'])['ImpactRate'].transform('sum')
df['ImpactRate'] /= df['Total']
# create tuple column
df['Breakdown'] = list(zip(df.Location, df.ImpactRate))
# groupby to list
df = df.groupby(['Category', 'Date', 'Total'])['Breakdown'].apply(list).reset_index()
结果:
print(df)
Category Date Total \
0 Outage 2018-04-22 0.17708
1 Transport 2018-04-24 0.03111
Breakdown
0 [(MT, 0.293313756494), (ND, 0.144115653942), (...
1 [(TX, 1.0)]
答案 1 :(得分:1)
我对此感觉不太好......但是很好。
d = pd.Series(
df.ImpactRate.values,
[list(zip(df.Date, df.Category)), df.Location],
name='Impact Rate'
)
s = d.sum(level=0)
t = d.div(s, level=0).rename('Break Down')
f = lambda t: ' '.join(f'{l} ({v*100:0.2f}%)' for (_, l), v in t.items())
pd.DataFrame(pd.concat(
[s, t.groupby(level=0).apply(f)], axis=1
).to_dict()).rename_axis(['Date', 'Category']).reset_index()
Date Category Break Down Impact Rate
0 2018-04-22 Outage MT (29.33%) ND (14.41%) SD (56.26%) 0.17708
1 2018-04-24 Transport TX (100.00%) 0.03111