基于公共列合并 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 中的行

折叠 Pandas 数据框中的行,每列具有不同的逻辑 [重复]

Pandas:如果特定列不包含特定文本,则删除数据框中的行

如何根据列中的最新日期聚合 pandas 数据框中的行?

Pandas:如何根据特定列上特定值的条件选择数据框中的行[重复]

合并 Pandas 数据框中的 2 列,用前一个值填充 NaN [重复]