我具有以下格式的数据框:
df = pd.DataFrame({'Date': np.repeat(['20190101', '20190102'], 8),
'Category': list(np.repeat(['A', 'B'], 4))*2,
'Sub-Category': list(np.repeat(['X', 'Y'], 2))*4,
'Samples': range(16)})
# print(df)
Date Category Sub-Category Samples
0 20190101 A X 0
1 20190101 A X 1
2 20190101 A Y 2
3 20190101 A Y 3
4 20190101 B X 4
5 20190101 B X 5
6 20190101 B Y 6
7 20190101 B Y 7
8 20190102 A X 8
9 20190102 A X 9
10 20190102 A Y 10
11 20190102 A Y 11
12 20190102 B X 12
13 20190102 B X 13
14 20190102 B Y 14
15 20190102 B Y 15
在每个日期中都有一个类别,并且每个类别中都有多个子类别。此外,每个子类别都有多个样本。
我想要做的是将“子类别”列从长格式转换为宽格式,而无需像这样对样本进行任何汇总:
desired_df = pd.DataFrame({'Date': np.repeat(['20190101', '20190102'], 4),
'Category': list(np.repeat(['A', 'B'], 2))*2,
'X': [0, 1, 4, 5, 8, 9, 12, 13],
'Y': [2, 3, 6, 7, 10, 11, 14, 15]
})
# print(desired_df)
Date Category X Y
0 20190101 A 0 2
1 20190101 A 1 3
2 20190101 B 4 6
3 20190101 B 5 7
4 20190102 A 8 10
5 20190102 A 9 11
6 20190102 B 12 14
7 20190102 B 13 15
我想我已经找到了一种方法来实现这一目标,但是它感觉很丑陋而且很棘手:它涉及到首先为样本编号创建一个新列,然后创建一个将所有这些信息组合在一起的新索引,然后将其再次分离:
def add_sample_index(df):
df['sample_index'] = range(len(df))
return df
new_df = df.groupby(['Date', 'Category', 'Sub-Category']).apply(add_sample_index)
new_df['new_index'] = new_df['Date'] + '_' + new_df['Category'] + '_' + new_df['sample_index'].astype(str)
wide_df = new_df.pivot(index='new_index', columns='Sub-Category', values='Samples').reset_index()
wide_df['Date'], wide_df['Category'], wide_df['sample_index'] = wide_df['new_index'].str.split('_').str
wide_df.drop(['new_index', 'sample_index'],
inplace=True, axis='columns')
final_df = wide_df[['Date', 'Category', 'X', 'Y']]
# print((final_df == desired_df).all().all())
True
我的问题:有没有更好,更有效的方法来解决此问题?
答案 0 :(得分:2)
首先我们使用groupby
cumcount
创建附加密钥,然后更像是pivot
问题
df['New']=df.groupby(['Date','Category','Sub-Category']).cumcount()
yourdf=df.pivot_table(values='Samples',index=['Date','Category','New'],columns='Sub-Category').reset_index()
yourdf
Out[703]:
Sub-Category Date Category New X Y
0 20190101 A 0 0 2
1 20190101 A 1 1 3
2 20190101 B 0 4 6
3 20190101 B 1 5 7
4 20190102 A 0 8 10
5 20190102 A 1 9 11
6 20190102 B 0 12 14
7 20190102 B 1 13 15