มีวิธีที่ตรงไปตรงมาในการรัน pandas.DataFrame.isin แบบขนานหรือไม่?


25

ฉันมีโปรแกรมการสร้างแบบจำลองและการให้คะแนนที่ใช้ประโยชน์จากDataFrame.isinฟังก์ชั่นของหมีแพนด้าอย่างหนักโดยค้นหาจากรายการบันทึกของ Facebook "ชอบ" ของผู้ใช้แต่ละคนสำหรับแต่ละหน้าไม่กี่พันหน้า นี่คือส่วนที่ใช้เวลานานที่สุดของโปรแกรมมากกว่าการสร้างแบบจำลองหรือให้คะแนนชิ้นส่วนเพียงเพราะมันทำงานบนแกนเดียวเท่านั้นในขณะที่ส่วนที่เหลือทำงานบนสองสามโหลพร้อมกัน

แม้ว่าฉันจะรู้ว่าฉันสามารถแบ่งดาต้าเฟรมออกเป็นชิ้น ๆ และดำเนินการแบบขนานได้เองมีวิธีที่ตรงไปตรงมาในการทำสิ่งนั้นโดยอัตโนมัติหรือไม่? กล่าวอีกนัยหนึ่งมีแพ็คเกจประเภทใดบ้างที่จะรับรู้ว่าฉันกำลังใช้งานที่ได้รับมอบหมายอย่างง่ายดายและแจกจ่ายโดยอัตโนมัติหรือไม่ บางทีนั่นอาจจะขอมากเกินไป แต่ฉันก็รู้สึกประหลาดใจมากพอในอดีตโดยสิ่งที่มีอยู่ใน Python ดังนั้นฉันคิดว่ามันคุ้มค่าที่จะถาม

ข้อเสนอแนะอื่น ๆ เกี่ยวกับวิธีการนี้อาจสำเร็จ (แม้ว่าจะไม่ใช่แพ็คเกจยูนิคอร์นเวทมนตร์) ก็จะได้รับการชื่นชมเช่นกัน ส่วนใหญ่เพียงแค่พยายามหาวิธีกำจัด 15-20 นาทีต่อการวิ่งโดยไม่ต้องใช้เวลาพอสมควรในการเข้ารหัสโซลูชัน


รายการค่าของคุณมีขนาดเท่าใด คุณพยายามที่จะผ่านมันเป็นชุด? สำหรับขนานคุณอาจสนใจ Joblib มันใช้งานง่ายและสามารถเพิ่มความเร็วในการคำนวณ ใช้กับกลุ่มข้อมูลขนาดใหญ่
oao

อีกทางเลือกหนึ่งคือการใส่ใหม่ปัญหาของคุณในการเข้าร่วม การเข้าร่วมเร็วกว่าใน Pandas stackoverflow.com/questions/23945493/…
Brian Spiering

ตัวเลือกอื่นคือใช้ np.in1d ​​ซึ่งเร็วกว่าstackoverflow.com/questions/21738882/fast-pandas-filtering
Brian Spiering

คำตอบ:


8

น่าเสียดายที่การขนานยังไม่ได้นำมาใช้ในแพนด้า คุณสามารถเข้าร่วมปัญหา GitHub นี้หากคุณต้องการมีส่วนร่วมในการพัฒนาคุณลักษณะนี้

ฉันไม่รู้ว่า "magic unicorn package" สำหรับจุดประสงค์นี้ดังนั้นสิ่งที่ดีที่สุดจะเป็นทางออกของคุณเอง แต่ถ้าคุณยังไม่ต้องการใช้เวลากับสิ่งนั้นและต้องการที่จะเรียนรู้สิ่งใหม่ - คุณสามารถลองใช้สองวิธีที่สร้างขึ้นใน MongoDB (ลดแผนที่และเฟรมเวิร์ก agg) ดูmongodb_agg_framework


6

ผมคิดว่าทางออกที่ดีที่สุดของคุณจะเป็นRosetta ฉันพบว่ามันมีประโยชน์และง่ายมาก ตรวจสอบของวิธีหมีแพนด้า

คุณจะได้รับจากจุดเล็ก ๆ


ฉันขอแนะนำให้รับ Rosetta โดยไปที่ GitHub โดยตรง ที่ทำให้คุณได้รับเวอร์ชันล่าสุด github.com/columbia-applied-data-science/rosetta
Ian Langmore


0

มีคำถามที่พบบ่อยเกี่ยวกับการทำงานแบบคู่ขนานบน pandas ใช้ฟังก์ชั่น - ดังนั้นนี่เป็นคำถามที่สดชื่น :)

ก่อนอื่นฉันอยากจะพูดถึงswifterตั้งแต่คุณถามหา "บรรจุ" และมันก็ปรากฏในคำถาม SO ส่วนใหญ่เกี่ยวกับการขนานของแพนด้า

แต่ ..ฉันยังคงต้องการแบ่งปันรหัสส่วนสำคัญของฉันเพราะหลังจากทำงานกับ DataFrame มาหลายปีฉันไม่เคยพบวิธีแก้ปัญหาขนาน 100% (ส่วนใหญ่ใช้กับฟังก์ชั่นการใช้งาน) และฉันต้องกลับมาหาฉันเสมอ " คู่มือ "รหัส

ขอบคุณที่ฉันทำให้มันเป็นเรื่องธรรมดามากขึ้นที่จะสนับสนุนใด ๆ (ในทางทฤษฎี) วิธี DataFrame ด้วยชื่อของมัน (ดังนั้นคุณจะไม่ต้องเก็บรุ่นสำหรับไอซิน, สมัคร, ฯลฯ .. )

ฉันทดสอบกับฟังก์ชั่น "isin", "Apply" และ "isna" โดยใช้ทั้ง python 2.7 และ 3.6 มันต่ำกว่า 20 บรรทัดและฉันทำตามแบบแผนการตั้งชื่อของแพนด้าเช่น "subset" และ "njobs"

ฉันยังเพิ่มการเปรียบเทียบเวลากับรหัสเทียบเท่า dask สำหรับ "isin" และดูเหมือนว่า ~ X2 ครั้งช้ากว่าส่วนสำคัญนี้

มันมี 2 ฟังก์ชั่น:

df_multi_core - นี่คือสิ่งที่คุณเรียก มันยอมรับ:

  1. วัตถุ df ของคุณ
  2. ชื่อฟังก์ชันที่คุณต้องการโทร
  3. ชุดย่อยของคอลัมน์ที่สามารถใช้งานได้ (ช่วยลดเวลา / หน่วยความจำ)
  4. จำนวนของงานที่ต้องรันแบบขนาน (-1 หรือละเว้นสำหรับทุกคอร์)
  5. kwargs อื่น ๆ ที่ฟังก์ชั่นของ df ยอมรับ (เช่น "แกน")

_df_split - นี่คือฟังก์ชั่นตัวช่วยภายในที่จะต้องวางตำแหน่งทั่วโลกในโมดูลที่กำลังทำงาน (Pool.map คือ "การจัดวาง") มิฉะนั้นฉันจะหามันภายใน ..

นี่คือรหัสจากส่วนสำคัญของฉัน(ฉันจะเพิ่มการทดสอบฟังก์ชั่นแพนด้าเพิ่มเติมที่นั่น):

import pandas as pd
import numpy as np
import multiprocessing
from functools import partial

def _df_split(tup_arg, **kwargs):
    split_ind, df_split, df_f_name = tup_arg
    return (split_ind, getattr(df_split, df_f_name)(**kwargs))

def df_multi_core(df, df_f_name, subset=None, njobs=-1, **kwargs):
    if njobs == -1:
        njobs = multiprocessing.cpu_count()
    pool = multiprocessing.Pool(processes=njobs)

    try:
        splits = np.array_split(df[subset], njobs)
    except ValueError:
        splits = np.array_split(df, njobs)

    pool_data = [(split_ind, df_split, df_f_name) for split_ind, df_split in enumerate(splits)]
    results = pool.map(partial(_df_split, **kwargs), pool_data)
    pool.close()
    pool.join()
    results = sorted(results, key=lambda x:x[0])
    results = pd.concat([split[1] for split in results])
    return results

ร้องเป็นรหัสการทดสอบสำหรับ parallelized ISINเปรียบเทียบพื้นเมืองเค้าแบบ multi-core และประสิทธิภาพการทำงาน dask บนเครื่อง I7 ที่มี 8 ฟิสิคัลคอร์ฉันได้รับความเร็วเพิ่มขึ้น X4 เท่า ฉันชอบที่จะได้ยินสิ่งที่คุณได้รับจากข้อมูลจริงของคุณ!

from time import time

if __name__ == '__main__': 
    sep = '-' * 50

    # isin test
    N = 10000000
    df = pd.DataFrame({'c1': np.random.randint(low=1, high=N, size=N), 'c2': np.arange(N)})
    lookfor = np.random.randint(low=1, high=N, size=1000000)

    print('{}\ntesting pandas isin on {}\n{}'.format(sep, df.shape, sep))
    t1 = time()
    print('result\n{}'.format(df.isin(lookfor).sum()))
    t2 = time()
    print('time for native implementation {}\n{}'.format(round(t2 - t1, 2), sep))

    t3 = time()
    res = df_multi_core(df=df, df_f_name='isin', subset=['c1'], njobs=-1, values=lookfor)
    print('result\n{}'.format(res.sum()))
    t4 = time()
    print('time for multi core implementation {}\n{}'.format(round(t4 - t3, 2), sep))


    t5 = time()
    ddata = dd.from_pandas(df, npartitions=njobs)
    res = ddata.map_partitions(lambda df: df.apply(apply_f, axis=1)).compute(scheduler='processes')
    t6 = time()
    print('result random sample\n{}'.format(res.sample(n=3, random_state=0)))
    print('time for dask implementation {}\n{}'.format(round(t6 - t5, 2), sep))

--------------------------------------------------
testing pandas isin on (10000000, 2)
--------------------------------------------------
result
c1    953213
c2    951942
dtype: int64
time for native implementation 3.87
--------------------------------------------------
result
c1    953213
dtype: int64
time for multi core implementation 1.16
--------------------------------------------------
result
c1    953213
c2    951942
dtype: int64
time for dask implementation 2.88

@Therriault ฉันเพิ่มการเปรียบเทียบ dask ด้วยisin- ดูเหมือนว่าข้อมูลโค้ดมีประสิทธิภาพมากที่สุดกับ 'isin' - ~ X1.75 ครั้งเร็วขึ้นแล้ว dask (เมื่อเทียบกับapplyฟังก์ชั่นที่ได้เร็วขึ้น 5% แล้ว dask)
mork
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.