基于公共列合并 Pandas 数据框中的行,同时附加一些字段
Posted
技术标签:
【中文标题】基于公共列合并 Pandas 数据框中的行,同时附加一些字段【英文标题】:Merge rows in Pandas dataframe based on common columns, while appending some fields 【发布时间】:2021-06-02 14:02:49 【问题描述】:如果这是一个非常基本的问题,请原谅我是 Python 和 Pandas 的相对初学者。
我有一个包含观察和分类的 csv 文件。每个观察在结果中出现多次,因为使用不同的训练数据重复分类,由“split_on”列指示。我希望将同一观察的所有实例合并到一行中,同时保留不同的分类结果,并另外添加平均值列。
这是原始形式中单个观察的样子:
datetime | bID | data1 | data2 | data3 | split_on | probability | prediction |
---|---|---|---|---|---|---|---|
50:03.3 | WI172 | 123 | 456 | 789 | group1 | 0.2 | class1 |
50:03.3 | WI172 | 123 | 456 | 789 | group2 | 0.4 | class1 |
50:03.3 | WI172 | 123 | 456 | 789 | group3 | 0.7 | class2 |
50:03.3 | WI172 | 123 | 456 | 789 | group4 | 0.2 | class1 |
这就是合并后的样子:
datetime | bID | data1 | data2 | data3 | group1_prob | group2_prob | group3_prob | group4_prob | group1_pred | group2_pred | group3_pred | group4_pred | probabilityAvg | predictionAvg |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
50:03.3 | WI172 | 123 | 456 | 789 | 0.2 | 0.4 | 0.7 | 0.2 | class1 | class1 | class2 | class1 | 0.375 | class1 |
有一些注意事项:
观察不一定有对应于所有可能组的行,因此 NaN 是预期的和适当的。 结果文件的大小约为 10GB,因此我将“chunksize”参数与“load_csv”一起使用,并且我必须对每个观察结果的每个块进行迭代,以确保我拥有所有相关的行。我写了以下内容来实现这一点:
import pandas as pd
group_cols = ["datetime", "bID"] #this is enough to uniquely identify a single observation
groups = set()
chunksize = 10 ** 6
#first pass over file collects a list of groups
for chunk in pd.read_csv("result.csv",
chunksize=chunksize, usecols=group_cols):
chunkGroups = chunk.groupby(group_cols)
for (groupLevels), chunkGroup in chunkGroups:
groups.add(groupLevels)
rows = []
#now pass over file for each group to collect associated rows
for group in groups:
result = []
for chunk in pd.read_csv("result.csv", chunksize=chunksize):
chunkGroups = chunk.groupby(group_cols)
if group in chunkGroups.groups.keys():
result.append(chunkGroups.get_group(group))
result_df = pd.concat(result) #This dataframe contains all rows pertaining to a single observation
result_df.set_index('split_on', inplace=True)
probs=result_df['probability']
probs.index += "_prob"
preds=result_df['prediction']
preds.index += "_pred"
new_row = pd.Series(result_df.iloc[0].drop(['probability','prediction']))
new_row = pd.concat([new_row,probs,preds])
#add a class label based on the average probability
new_row['probability-avg'] = result_df['probability'].mean()
if new_row['probability-avg'] > 0.5:
new_row['predictedAspect-avg'] = "class2"
else:
new_row['predictedAspect-avg'] = "class1"
rows.append(new_row)
print('merged row: ', new_row)
rows_df = pd.concat(rows, axis=1,sort=True).transpose()
rows_df.to_csv("mergedResults.csv", index=False)
这可行,但转换速度非常慢(每行几秒钟!),并且像这样处理我的整个文件会花费比我更多的时间。
有没有更明智的方法来实现这一点?
【问题讨论】:
【参考方案1】:使用pivot
:
from statistics import mode
k = df.pivot(index=['datetime', 'bID', 'data1', 'data2', 'data3'], columns=[
'split_on'], values=['probability', 'prediction'])
k.columns = k.columns.map(lambda x: '_'.join(x[::-1]))
df = k.reset_index()
df['prediction_avg'] = df.filter(regex=r'.*_prediction').mode(1)
df['probability_avg'] = df.filter(regex=r'.*_probability').mean(1)
输出:
datetime | bID | data1 | data2 | data3 | group1_probability | group2_probability | group3_probability | group4_probability | group1_prediction | group2_prediction | group3_prediction | group4_prediction | prediction_avg | probability_avg |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
50:03.3 | WI172 | 123 | 456 | 789 | 0.2 | 0.4 | 0.7 | 0.2 | class1 | class1 | class2 | class1 | class1 | 0.375 |
【讨论】:
这很棒。谢谢以上是关于基于公共列合并 Pandas 数据框中的行,同时附加一些字段的主要内容,如果未能解决你的问题,请参考以下文章
折叠 Pandas 数据框中的行,每列具有不同的逻辑 [重复]