【问题标题】:How to restructure Python pandas Dataframe, optimization如何重构 Python pandas Dataframe,优化
【发布时间】:2021-05-02 11:54:35
【问题描述】:

我有一个交易数据集(40k 行,45 列,11 MB RAM),其 ID 跟踪整个交易过程(发送、取款、退款),我需要根据“参考号”列中的值重组 Dataframe,以便与此事务相关的所有数据都在一行中。

我做什么: 加载源Dataframe,对其进行排序,逐行迭代以一次过滤一个ID的出现,迭代最终的Dataframe列并将相应的值分配给本地字典。 最后,连接字典并创建一个新的数据框(大约 1/2 * 40k 行,69 列)。

根据我的测试,for 循环创建 Dict 键(对于 dictOfCols.items() 中的 x、y)消耗了 85% 的所需时间 有更好的方法吗? 目前,此脚本在具有 8 GB RAM 的单核 AMD Epyc(服务器)上需要 30 多分钟。

dictOfCols 包含 3 种可能的交易类型(发送、取款、退款)的键(最终 DF 列名称)和值(列表 [源 DF 列名称])对。简化示例:

dictOfCols  = {'reference_number': ['Reference Number', 'Reference Number', 'Reference Number'], 'send_Destination_Country': ['Destination Country', None, None], 'send_ToCountry/Countrpart': ['ToCountry/Countrpart', None, None], 'payout_Destination_Country': [None, 'Destination Country', None], 'payout_ToCountry/Countrpart': [None, 'ToCountry/Countrpart', None], 'bestpay': [None, None, None], 'send': ['Operation', None, None], 'send_DocumentId': ['DocumentId', None, None], 'send_Related_Document_Id': ['Related Document Id', None, None], 'send_Date': ['Date', None, None], 'payout': [None, 'Operation', None], 'payout_documentId': [None, 'DocumentId', None], 'payout_Related_Document_Id': [None, 'Related Document Id', None], 'time_payout': [None, 'Related Document Date', None], 'refund': [None, None, 'Operation'], 'cancelled_time': [None, None, 'Date'], 'send_Point': ['Point', None, None],  ....}

DF 看起来像这样: https://docs.google.com/spreadsheets/d/1OhWu_GrqwZBasuPdGFGynBuDXO7fuBjbFOCjrcIPFis/edit#gid=0

我的代码:

data = []
df_master = df_master.sort_values(by='Reference Number', axis='index')
df_master = df_master.set_index('Reference Number', drop=False)
df_master = df_master.sort_index()
ref_cols = df_master['Reference Number'].unique().tolist()

for i in ref_cols:
    local = df_master.loc[df_master['Reference Number'] == i]
    if local.empty:
        continue
    # creates slices of local dataframe based on Operation type
    send = local.loc[local['Operation'] == 'SEND']
    payout = local.loc[local['Operation'] == 'PAYOUT']
    refund = local.loc[local['Operation'] == 'REFUND']
    # if len of any DF is more than 1, raise error
    lenCheck([send, payout, refund])

    dict = {}
    # create Dict of one Refenrece number, assign values based on column names from dictOfCols
    for x, y in dictOfCols.items():
        if (y[0] is not None and send.empty == False):
            dict[x] = send.iloc[0][y[0]]  
        elif (y[1] is not None and payout.empty == False):
            dict[x] = payout.iloc[0][y[1]]
        elif (y[2] is not None and refund.empty == False):
            dict[x] = refund.iloc[0][y[2]]
        else:
            dict[x] = False
            # raise ValueError

    data.append(dict)
    df_master.loc[local.index, 'Drop'] = 1

df = pd.DataFrame(data)

我加快进程的唯一想法是创建源 Dataframe 块并使用多处理。

最终数据框示例:

【问题讨论】:

  • 您的问题不清楚。请解释你在代码中做了什么。其他几个问题 - 这里的 dictOfCols 是什么? lenCheck 在这里有什么用?它是什么?另外,不要发布输出df的图像。使用 df.to_dict() 并在此处发布字典。
  • @Nk03:您能详细说明一下不清楚的地方吗?我似乎已经在原帖中回答了你所有的问题。问题是缓慢的内部 For 循环。 dictOfCols 基本上是帖子中描述的列名映射。 lenCheck 是评论所说的 - 检查任何操作类型是否包含超过 1 行,因为每个事务只能包含最大值。 1 次发送,最多 1 次付款和最多 1 次退款操作。输出应包含 dictOfCols 对象键中描述的列,当然还有与这些列对应的数据。谢谢。

标签: python pandas dataframe multiprocessing


【解决方案1】:

事实证明,multiprocessing 大大加快了这项工作的速度。我只需在 8 核 CPU 上将数据帧拆分为 8 个块。

我还发现脚本仅在 debug 模式下需要 30 分钟,而不是在实际运行中。然后只需要大约 5 分钟。

【讨论】:

  • 能否详细说明 1. 多处理究竟是如何实现的? 2.你说的调试模式是什么意思?在VS、Jupyter、终端?
猜你喜欢
  • 1970-01-01
  • 2019-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多