2016-04-12 6 views
5

मान लीजिए मेरे पास एक पांडा डेटाफ्रेम है और एक फ़ंक्शन जिसे मैं प्रत्येक पंक्ति पर लागू करना चाहता हूं। मैं df.apply(apply_fn, axis=1) पर कॉल कर सकता हूं, जिसमें df के आकार में समय रैखिक होना चाहिए। या मैं प्रत्येक टुकड़े पर अपने फ़ंक्शन को कॉल करने के लिए df विभाजित कर सकता हूं और pool.map का उपयोग कर सकता हूं, और फिर परिणामों को जोड़ सकता हूं।पांडा के साथ मल्टीप्रोसेसिंग का उपयोग क्यों नाटकीय गति के लिए लागू होता है?

मैं pool.map का उपयोग कर मोटे तौर पर पूल में प्रक्रियाओं की संख्या के बराबर होने के लिए से speedup कारक उम्मीद कर रहा था (new_execution_time = original_execution_time/एन अगर एन प्रोसेसर का उपयोग कर - और कि शून्य भूमि के ऊपर यह सोचते है)।

इसके बजाए, इस खिलौने उदाहरण में, समय 4 प्रोसेसर का उपयोग करते समय लगभग 2% (0.005272/0.230757) तक गिर जाता है। मैं सबसे अच्छा 25% की उम्मीद कर रहा था। क्या चल रहा है और मैं क्या समझ नहीं पा रहा हूं?

import numpy as np 
from multiprocessing import Pool 
import pandas as pd 
import pdb 
import time 

n = 1000 
variables = {"hello":np.arange(n), "there":np.random.randn(n)} 
df = pd.DataFrame(variables) 

def apply_fn(series): 
    return pd.Series({"col_5":5, "col_88":88, 
         "sum_hello_there":series["hello"] + series["there"]}) 

def call_apply_fn(df): 
    return df.apply(apply_fn, axis=1) 

n_processes = 4 # My machine has 4 CPUs 
pool = Pool(processes=n_processes) 

t0 = time.process_time() 
new_df = df.apply(apply_fn, axis=1) 
t1 = time.process_time() 
df_split = np.array_split(df, n_processes) 
pool_results = pool.map(call_apply_fn, df_split) 
new_df2 = pd.concat(pool_results) 
t2 = time.process_time() 
new_df3 = df.apply(apply_fn, axis=1) # Try df.apply a second time 
t3 = time.process_time() 

print("identical results: %s" % np.all(np.isclose(new_df, new_df2))) # True 
print("t1 - t0 = %f" % (t1 - t0)) # I got 0.230757 
print("t2 - t1 = %f" % (t2 - t1)) # I got 0.005272 
print("t3 - t2 = %f" % (t3 - t2)) # I got 0.229413 

मैंने उपरोक्त कोड को सहेजा और python3 my_filename.py का उपयोग करके इसे चलाया।

पीएस मुझे एहसास है कि इस खिलौने उदाहरण में new_df लागू किए बिना, अधिक सरल तरीके से बनाया जा सकता है। मुझे एक और जटिल apply_fn के साथ समान कोड लागू करने में दिलचस्पी है जो केवल कॉलम नहीं जोड़ता है।

उत्तर

1

संपादित (मेरे पिछले जवाब वास्तव में गलत था।)

time.process_time() (doc) केवल वर्तमान प्रक्रिया में समय का आकलन करता है (और सो समय शामिल नहीं है)। तो बाल प्रक्रियाओं में बिताए गए समय को ध्यान में नहीं रखा जाता है।

मैं time.time() के साथ अपना कोड चलाता हूं, जो वास्तविक दुनिया के समय को मापता है (बिल्कुल कोई गति नहीं दिखाता है) और अधिक विश्वसनीय timeit.timeit (लगभग 50% गति) के साथ। मेरे पास 4 कोर हैं।

+0

धन्यवाद, आपको सही होना चाहिए। मुझे समझ में नहीं आता कि क्या हो रहा है, यद्यपि। ऐसा क्यों होता है भले ही 'time.process_time()' कॉल मल्टीप्रोसेसिंग कॉल के बाहर हों? क्या ऐसा इसलिए है क्योंकि 'time.process_time()' केवल माता-पिता प्रक्रिया के CPU समय को वापस कर रहा है? – Adrian

+0

@ एड्रियन क्षमा करें, मैं गलत था - बाल प्रक्रियाओं को 'process_time' के साथ गड़बड़ नहीं हुई थी। गलतफहमी के लिए खेद है। मैं जवाब अद्यतन करता हूँ। – ptrj

संबंधित मुद्दे