代码之家  ›  专栏  ›  技术社区  ›  Digital Farmer

使用DataFrame时使用一对行进行迭代

  •  0
  • Digital Farmer  · 技术社区  · 4 年前

    迭代我使用的数据帧的每一行 .iterrows() :

    list_soccer = pd.DataFrame({
        'EventName': [obj_event.event.name for obj_event in matches],
        'IDEvent': [obj_event.event.id for obj_event in matches],
        'LocalEvent': [obj_event.event.venue for obj_event in matches],
        'CodeCountry': [obj_event.event.country_code for obj_event in matches],
        'TimeZone': [obj_event.event.time_zone for obj_event in matches],
        'OpenDate': [obj_event.event.open_date for obj_event in matches],
        'Total_Market': [obj_event.market_count for obj_event in matches],
        'Local_Date': [obj_evento.event.open_date.replace(tzinfo=datetime.timezone.utc).astimezone(tz=None) 
                                for obj_evento in matches]
        })
    
    for_iterate = list_soccer.reset_index()
    for_iterate = for_iterate[for_iterate['EventName'].str.contains(" v ")]
    data_for_compare = (datetime.datetime.utcnow()).strftime("%Y-%m-%d %H:%M")
    for_iterate = for_iterate[for_iterate['OpenDate'] >= data_for_compare]
        
    for index, example_dataframe in for_iterate.iterrows():
        multiprocessing.Process(target=add_hour, args=(example_dataframe,))
    

    因为我需要将这个迭代的速度提高一倍(称为二次迭代) multiprocessing 同时),我正在寻找一种一次使用两行的方法。

    如果它是一个常规列表(请注意,我下面给出的示例只是为了演示我需要什么,我理解列表和数据帧之间没有相似之处),我可以这样做:

    a_list = ['a','b','c','d']
    a_pairs = [a_list[i:i+2] for i in range(0, len(a_list)-1, 2)]
    # a_pairs = [['a','b'],['c','d']]
    for a, b in a_pairs:
        multiprocessing.Process(target=add_hour, args=(a,))
        multiprocessing.Process(target=add_hour, args=(b,))
    
    

    我应该如何处理DataFrame以同时处理两行?

    在这个问题中,我找到了两个答案,但它们提供的选项会在数据框中重复值:
    Pandas iterate over DataFrame row pairs

    我无法创建一个模型,这样线就不会重复,例如,使用行 0 and 1 然后使用 2 and 3 然后使用 4 and 5 ,所以可能有人说这个问题重复了,但事实上,我的需求是不同的,我无法将这些选项转换为我的需求。

    1 回复  |  直到 4 年前
        1
  •  2
  •   mxbi    4 年前

    您应该能够将数据帧一分为二,使用与列表类似的索引。

    然后,你可以一次迭代这两行,每次按顺序给你两行(所以0,1,然后2,3等等)

    df_a = for_iterate.iloc[::2] # Get all the even rows
    df_b = for_iterate.iloc[1::2] # Get all the odd rows
    
    for (_, example_dataframe_a), (_, example_dataframe_b) in zip(df_a.iterrows(), df_b.iterrows()):
        multiprocessing.Process(target=add_hour, args=(example_dataframe_a,))
        multiprocessing.Process(target=add_hour, args=(example_dataframe_b,))
    

    (虽然我不清楚为什么需要为数据帧的每一行生成一个进程,而不是为数据帧的每一半生成两个进程。) for_iterate ).

    或者:

    你可以试试使用 multiprocessing.Pool.map() 一次执行两个请求。与上述方法不同,前一个请求完成后会立即发出新请求(因此不会等到两个请求都完成后再发送下两个请求),并且只需要两个可以重复使用的进程:

    from multiprocessing import Pool
    
    def add_hour_wrapper(data):
      # iterrows returns two arguments, we only want one
      _, row = data
      return add_hour(row)
    
    pool = Pool(2) # 2 processes
    
    pool.map(add_hour, for_iterate.iterrows())