8

मेरे पास एक ऐसा फ़ंक्शन है जो डेटाफ्रेम को संसाधित करता है, मुख्य रूप से बाल्टी में डेटा को संसाधित करने के लिए pd.get_dummies(df[col]) का उपयोग करके किसी विशेष कॉलम में सुविधाओं का बाइनरी मैट्रिक्स बनाता है।डेटाफ्रेम का सहभागिता तेजी से धीमा क्यों होता है?

chunks = (len(df)/10000) + 1 
df_list = np.array_split(df, chunks) 

pd.get_dummies(df) स्वचालित रूप से पैदा करेगा:

एक ही बार में (जो स्मृति से बाहर चला जाता है और IPython के क्रैश होने का कारण बनता है) इस समारोह का उपयोग कर अपने डेटा के सभी प्रसंस्करण बचने के लिए, मैं का उपयोग कर टुकड़ों में बड़े DataFrame हड्डी टूट गई है df[col] की सामग्री के आधार पर नए कॉलम और df के लिए df_list में ये अलग-अलग होने की संभावना है।

प्रसंस्करण के बाद, मैं DataFrames वापस एक साथ का उपयोग कर श्रृंखलाबद्ध हूँ:

for i, df_chunk in enumerate(df_list): 
    print "chunk", i 
    [x, y] = preprocess_data(df_chunk) 
    super_x = pd.concat([super_x, x], axis=0) 
    super_y = pd.concat([super_y, y], axis=0) 
    print datetime.datetime.utcnow() 

पहले खंड के प्रसंस्करण समय पूरी तरह से स्वीकार्य है, तथापि, यह हिस्सा प्रति बढ़ता है! यह preprocess_data(df_chunk) के साथ नहीं है क्योंकि इसे बढ़ाने के लिए कोई कारण नहीं है। क्या pd.concat() पर कॉल के परिणामस्वरूप यह समय बढ़ रहा है?

कृपया नीचे लॉग देखें:

chunks 6 
chunk 0 
2016-04-08 00:22:17.728849 
chunk 1 
2016-04-08 00:22:42.387693 
chunk 2 
2016-04-08 00:23:43.124381 
chunk 3 
2016-04-08 00:25:30.249369 
chunk 4 
2016-04-08 00:28:11.922305 
chunk 5 
2016-04-08 00:32:00.357365 

इस तेजी लाने के लिए एक समाधान है? मेरे पास प्रक्रिया करने के लिए 2 9 00 भाग हैं इसलिए किसी भी मदद की सराहना की जाती है!

पायथन में किसी अन्य सुझाव के लिए खोलें!

उत्तर

8

कभी नहीं एक के लिए लूप के अंदर DataFrame.append या pd.concat कहते हैं। यह वर्गबद्ध प्रतिलिपि की ओर जाता है।

pd.concat एक नया डेटाफ्रेम देता है। स्पेस को नए डेटाफ्रेम के लिए आवंटित किया जाना है, और पुराने डेटाफ्रेम से डेटा को नए डेटाफ्रेम में कॉपी करना होगा।

super_x = pd.concat([super_x, x], axis=0) 

| iteration | size of old super_x | size of x | copying required | 
|   0 |     0 |   1 |    1 | 
|   1 |     1 |   1 |    2 | 
|   2 |     2 |   1 |    3 | 
|  ... |      |   |     | 
|  N-1 |     N-1 |   1 |    N | 

1 + 2 + 3 + ... + N = N(N-1)/2: for-loop अंदर इस लाइन (यह मानते हुए प्रत्येक x आकार 1 है) द्वारा अपेक्षित नकल की राशि पर विचार करें। तो पर आवश्यक प्रतियां लूप को पूरा करें।

अब विचार करना

super_x = [] 
for i, df_chunk in enumerate(df_list): 
    [x, y] = preprocess_data(df_chunk) 
    super_x.append(x) 
super_x = pd.concat(super_x, axis=0) 

एक सूची में जोड़ एक O(1) ऑपरेशन है और नकल की आवश्यकता नहीं है। अब लूप पूरा होने के बाद pd.concat पर एक एकल कॉल है। pd.concat को इस कॉल की आवश्यकता एन प्रतियां किए जाने के लिए के बाद से super_x आकार के N DataFrames 1. इसलिए जब इस तरह का निर्माण किया, super_xO(N) प्रतियां आवश्यकता होती है।

+0

हाय @unutbu, विस्तृत स्पष्टीकरण के लिए धन्यवाद, यह वास्तव में सिद्धांत को विस्तार से समझाया! – jfive

+0

क्या इस आकार के 2 9 00 ब्लॉक को जोड़ना संभव है, इस तरह (43717, 3261)? प्रसंस्करण चरण में केवल 10 सेकंड लगते हैं। – jfive

4

हर बार जब आप संयोजित होते हैं, तो आप डेटा की एक प्रति वापस कर रहे हैं।

आप अपने हिस्सों की एक सूची रखना चाहते हैं, और फिर अंतिम चरण के रूप में सबकुछ जोड़ना चाहते हैं।

df_x = [] 
df_y = [] 
for i, df_chunk in enumerate(df_list): 
    print "chunk", i 
    [x, y] = preprocess_data(df_chunk) 
    df_x.append(x) 
    df_y.append(y) 

super_x = pd.concat(df_x, axis=0) 
del df_x # Free-up memory. 
super_y = pd.concat(df_y, axis=0) 
del df_y # Free-up memory. 
+0

बहुत बहुत धन्यवाद, इस मुद्दे को ठीक किया गया! – jfive

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