2017-02-10 4 views
34

मेरे पास कई टेक्स्ट फाइलें हैं, 50 कहें, मुझे एक बड़े डेटाफ्रेम में पढ़ने की जरूरत है। फिलहाल, मैं निम्नलिखित चरणों का उपयोग कर रहा हूं।मैं एकाधिक फ़ाइलों को पढ़ने और डेटा को डेटाफ्रेम में कैसे डाल सकता हूं?

  1. प्रत्येक फ़ाइल को पढ़ें और जांचें कि लेबल क्या हैं। मुझे जो जानकारी चाहिए वह अक्सर पहले कुछ पंक्तियों में निहित होती है। वही लेबल बस फाइल के बाकी हिस्सों के लिए दोहराते हैं, प्रत्येक बार उनके खिलाफ सूचीबद्ध विभिन्न प्रकार के डेटा के साथ।
  2. उन लेबलों के साथ डेटाफ्रेम बनाएं।
  3. फ़ाइल को फिर से पढ़ें और डेटाफ्रेम को मानों के साथ भरें।
  4. एक मास्टर डेटाफ्रेम के साथ उस डेटाफ्रेम को समेकित करें।

यह 100 केबी आकार के कुछ फ़ाइलों के लिए बहुत अच्छी तरह से काम करता है - कुछ मिनट, लेकिन 50 एमबी पर, इसमें बस घंटे लगते हैं, और व्यावहारिक नहीं है।

मैं अपना कोड कैसे अनुकूलित कर सकता हूं? विशेष रूप से -

  1. मैं कैसे पहचान सकता हूं कि कौन से फ़ंक्शन सबसे अधिक समय ले रहे हैं, जिसे मुझे अनुकूलित करने की आवश्यकता है? क्या यह फाइल का पठन है? क्या यह डेटा फ्रेम के लिए लेखन है? मेरा कार्यक्रम समय व्यतीत कहां है?
  2. क्या मुझे मल्टीथ्रेडिंग या मल्टीप्रोसेसिंग पर विचार करना चाहिए?
  3. क्या मैं एल्गोरिदम सुधार सकता हूं?
    • शायद में पूरी फ़ाइल को पढ़ने के एक नहीं बल्कि लाइन द्वारा लाइन से एक सूची में जाने में,,
    • पार्स में dataframe को हिस्सा/पूरी फ़ाइल में डेटा, बल्कि लाइन द्वारा लाइन से,
    • असाइन डेटा पंक्ति से पंक्ति के बजाए भाग/एक जाना।
  4. क्या कोई और चीज है जो मैं अपना कोड तेजी से निष्पादित करने के लिए कर सकता हूं?

यहां एक उदाहरण कोड है। मेरा स्वयं का कोड थोड़ा अधिक जटिल है, क्योंकि टेक्स्ट फाइलें अधिक जटिल हैं जैसे कि मुझे लगभग 10 नियमित अभिव्यक्तियों और एकाधिक का उपयोग करना होता है जबकि डेटा को पढ़ने के लिए लूप और सही सरणी में सही स्थान पर आवंटित करते हैं। एमडब्ल्यूई को सरल रखने के लिए, मैंने MWE के लिए इनपुट फ़ाइलों में दोहराने वाले लेबल का उपयोग नहीं किया है, इसलिए मैं किसी भी कारण से फ़ाइल को दो बार पढ़ रहा हूं। मुझे उम्मीद है कि इसका कोई अर्थ है!

import re 
import pandas as pd 

df = pd.DataFrame() 
paths = ["../gitignore/test1.txt", "../gitignore/test2.txt"] 
reg_ex = re.compile('^(.+) (.+)\n') 
# read all files to determine what indices are available 
for path in paths: 
    file_obj = open(path, 'r') 
    print file_obj.readlines() 

['a 1\n', 'b 2\n', 'end'] 
['c 3\n', 'd 4\n', 'end'] 

indices = [] 
for path in paths: 
    index = [] 
    with open(path, 'r') as file_obj: 
     line = True 
     while line: 
      try: 
       line = file_obj.readline() 
       match = reg_ex.match(line) 
       index += match.group(1) 
      except AttributeError: 
       pass 
    indices.append(index) 
# read files again and put data into a master dataframe 
for path, index in zip(paths, indices): 
    subset_df = pd.DataFrame(index=index, columns=["Number"]) 
    with open(path, 'r') as file_obj: 
     line = True 
     while line: 
      try: 
       line = file_obj.readline() 
       match = reg_ex.match(line) 
       subset_df.loc[[match.group(1)]] = match.group(2) 
      except AttributeError: 
       pass 
    df = pd.concat([df, subset_df]).sort_index() 
print df 

    Number 
a  1 
b  2 
c  3 
d  4 

मेरे इनपुट फाइलें:

test1.txt

a 1 
b 2 
end 

test2.txt

c 3 
d 4 
end 
+2

शायद एक तेज डिस्क प्राप्त करें :) –

+3

इस बीच, एक अच्छा पायथन प्रोफाइलर देखें। यह टूल का सामान्य वर्ग है जो आपको बताएगा कि कार्यक्रम का कौन सा हिस्सा बाधा है। –

+1

क्या आप डेटाफ्रेम में पूरी 50 फाइलें नहीं पढ़ सकते हैं और फिर रेगेक्स आधारित मैनिपुलेशन चला सकते हैं? यह तेजी से होगा क्योंकि पांडा पर फ़िल्टर ऑपरेशंस बहुत तेज़ है .... – vks

उत्तर

0

यह पता चला है कि पहले एक खाली डेटाफ्रेम बनाना, डेटा की एक पंक्ति के लिए सही जगह खोजने के लिए इंडेक्स खोजना, और फिर डेटाफ्रेम की केवल एक पंक्ति को अपडेट करना एक बेवकूफ समय महंगी प्रक्रिया है।

ऐसा करने का एक तेज़ तरीका इनपुट फ़ाइल की सामग्री को मूलभूत डेटा संरचना जैसे सूचियों की सूची, या डिक्ट्स की सूची में पढ़ना है, और उसके बाद इसे डेटाफ्रेम में परिवर्तित करना है।

सूचियों का उपयोग करें जब आप पढ़ रहे सभी डेटा एक ही कॉलम में हैं। अन्यथा, स्पष्ट रूप से यह कहने के लिए डिक्ट्स का उपयोग करें कि प्रत्येक कॉल का कौन सा कॉलम जाना चाहिए।

अद्यतन जनवरी 18: यह How to parse complex text files using Python? से जुड़ा हुआ है मैं भी एक blog article explaining how to parse complex files to beginners लिखा था।

1

आप बहु मॉडल आयात और कार्यकर्ता प्रक्रियाओं की एक पूल का उपयोग कर सकते फाइल ऑब्जेक्ट्स के रूप में कई फ़ाइलों को एक साथ खोलने के लिए, तेजी से बढ़ाना आपके कोड का लोडिंग हिस्सा।समय परीक्षण करने के लिए, या तो दिनांक समारोह आयात और निम्नलिखित कोड का उपयोग करें:

import datetime 
start=datetime.datetime.now() 

#part of your code goes here 

execTime1=datetime.datetime.now() 
print(execTime1-start) 

#the next part of your code goes here 

execTime2=datetime.datetime.now() 
print(execTime2-execTime1) 

, केवल एक बार प्रत्येक फ़ाइल को पढ़ने के रूप में जहाँ तक एक और बहु ​​स्क्रिप्ट का उपयोग कर प्रत्येक फ़ाइल में लाइनों की एक सूची बनाने के लिए विचार करना है, तो आप जाँच कर सकते हैं फ़ाइल I/O ऑपरेशन के बिना एक मैच के लिए।

1

सबसे पहले, अपनी स्क्रिप्ट (see this question) के लिए एक प्रोफाइलर का उपयोग करें। वास्तव में विश्लेषण करें कि कौन हिस्सा अधिक समय लगता है। अगर आप इसे अनुकूलित कर सकते हैं देखें।

दूसरा, मुझे लगता है कि मैं/हे operation- फ़ाइल सबसे अधिक संभावना पढ़ने बाधा बनें। इसे समवर्ती दृष्टिकोण का उपयोग करके अनुकूलित किया जा सकता है। मैं एक साथ पढ़ी गई फ़ाइलों को पढ़ने और डेटा फ्रेम बनाने का सुझाव दूंगा। प्रत्येक थ्रेड नए बनाए गए डेटा फ्रेम को कतार में धक्का दे सकता है। मुख्य थ्रेड मॉनीटरिंग कतार कतार से डेटा फ्रेम उठा सकती है और इसे मर्ज कर सकती है मास्टर डेटा फ्रेम के साथ

उम्मीद है कि यह मदद करता है।

1

1 फ़ाइलों के लिए एक आउटपुट टेम्पलेट बनाएं (जैसे परिणाम डेटा फ्रेम में कॉलम ए, बीसी होना चाहिए)

2 प्रत्येक फ़ाइल को पढ़ें, इसे आउटपुट टेम्पलेट में बदलें (जो चरण 1 में स्थापित किया गया था) और temp_idxx.csv जैसी फ़ाइल को सहेजें, यह एक बड़े पैमाने पर फ़ाइल में समानांतर में किया जा सकता है :)

3 CONCATENATE इन temp_idxx.csv फ़ाइलें और हटाना temps

कि यह समानांतर में चलाया जा सकता है, और यह सब खाने के लिए नहीं होगा इस प्रक्रिया के

पेशेवरों मेमोरी विपक्ष आउटपुट प्रारूप बना रहे हैं और इसमें चिपके हुए हैं, और डिस्क स्पेस उपयोग

1

पीडी.read_csv का उपयोग कर फ़ाइलों को सीधे पांडा डेटाफ्रेम में पढ़ें। अपना सबसेट_डीएफ बनाने के लिए। फ़ाइल के अंत में लाइनों को छोड़ने के लिए skipfooter जैसे विधियों का उपयोग करें, जिन्हें आप जानते हैं कि आपको आवश्यकता नहीं है। कई और विधियां उपलब्ध हैं जो आपके द्वारा उपयोग किए जा रहे कुछ रेगेक्स लूप फ़ंक्शंस को प्रतिस्थापित कर सकती हैं, जैसे error_bad_lines और skip_blank_lines।

फिर आवश्यक डेटा को साफ़ करने के लिए पांडा द्वारा प्रदान किए गए टूल का उपयोग करें।

यह आपको खुले पढ़ने और केवल एक बार फ़ाइल पढ़ने की अनुमति देगा।

12

मल्टीप्रोसेसिंग हथौड़ा खींचने से पहले, आपका पहला कदम कुछ प्रोफाइलिंग करना चाहिए। कौन से फ़ंक्शंस लंबे समय से ले रहे हैं यह पहचानने के लिए जल्दी से देखने के लिए cProfile का उपयोग करें। दुर्भाग्यवश यदि आपकी लाइनें एक ही फ़ंक्शन कॉल में हैं, तो वे लाइब्रेरी कॉल के रूप में दिखाई देंगे। line_profiler बेहतर है लेकिन थोड़ा और सेटअप समय लेता है।

नोट। यदि ipython का उपयोग करते हैं, तो आप अपने स्टेटमेंट्स के साथ-साथ कार्यों के समय% timeit (टाइमिट मॉड्यूल के लिए जादू कमांड) और% prun (प्रोफाइल मॉड्यूल के लिए जादू कमांड) का उपयोग कर सकते हैं। एक Google खोज कुछ गाइड दिखाएगी।

पांडा एक अद्भुत पुस्तकालय है, लेकिन मैं इसे अत्याचारी परिणामों के साथ खराब तरीके से उपयोग करने का कभी-कभी शिकार रहा हूं। विशेष रूप से, संलग्न()/concat() संचालन से सावधान रहें। यह आपकी बाधा हो सकती है लेकिन आपको सुनिश्चित करने के लिए प्रोफाइल होना चाहिए। आमतौर पर, numpy.vstack() और numpy.hstack() ऑपरेशन तेज़ होते हैं यदि आपको इंडेक्स/कॉलम संरेखण करने की आवश्यकता नहीं है। आपके मामले में ऐसा लगता है कि आप सीरीज़ या 1-डी numpy ndarrays के साथ प्राप्त करने में सक्षम हो सकते हैं जो समय बचा सकता है।

बीटीडब्ल्यू, try पाइथन में ब्लॉक अमान्य स्थिति की जांच करने से अक्सर 10x या उससे अधिक धीमा होता है, इसलिए सुनिश्चित करें कि आपको प्रत्येक पंक्ति के लिए लूप में चिपकाते समय पूरी तरह से इसकी आवश्यकता है।यह शायद समय का दूसरा होगर है; मुझे लगता है कि आप match.group (1) विफलता के मामले में AttributeError की जांच करने के लिए प्रयास ब्लॉक को फंस गए हैं। मैं पहले एक वैध मैच की जांच करता हूं।

यहां तक ​​कि इन छोटे बदलावों को आपके प्रोग्राम के लिए मल्टीप्रोसेसिंग जैसी कठोर कोशिश करने से पहले काफी तेजी से चलाने के लिए पर्याप्त होना चाहिए। वे पाइथन पुस्तकालय बहुत ही अच्छे हैं लेकिन इससे निपटने के लिए चुनौतियों का एक नया सेट लाते हैं।

+1

यह स्पष्ट रूप से स्पष्ट है कि लाइन द्वारा 50 एमबी फाइल लाइन पढ़ना है जहां बाधा उत्पन्न हो रही है। यहां तक ​​कि 50 एमबी फाइल पर pandas.read_excel भी कुछ मिनट लगेंगे। – Nemo

2

जनरल अजगर विचार:

सबसे पहले समय माप के बारे में आप इस तरह के एक स्निपेट का उपयोग हो सकता है:

from time import time, sleep 


class Timer(object): 
    def __init__(self): 
     self.last = time() 


    def __call__(self): 
     old = self.last 
     self.last = time() 
     return self.last - old 

    @property 
    def elapsed(self): 
     return time() - self.last 



timer = Timer() 

sleep(2) 
print timer.elapsed 
print timer() 
sleep(1) 
print timer() 

तो फिर तुम चल बेंचमार्क सकता कोड कई बार, और diff लिए जाँच करें।

इस बारे में, मैं टिप्पणी इनलाइन:

with open(path, 'r') as file_obj: 
    line = True 
    while line: #iterate on realdines instead. 
     try: 
      line = file_obj.readline() 
      match = reg_ex.match(line) 
      index += match.group(1) 
      #if match: 
      # index.extend(match.group(1)) # or extend 

     except AttributeError: 
      pass 

आप पिछले कोड वाट नहीं वास्तव में pythonic, आप की कोशिश करने/छोड़कर कर सकते हैं। फिर न्यूनतम संभव लाइनों पर केवल प्रयास करने का प्रयास करें।

समान नोटिस कोड के दूसरे ब्लॉक पर लागू होते हैं।

यदि आपको एक ही फाइल को कई बार पढ़ने की आवश्यकता है। आप उन्हें स्ट्रिंगियो का उपयोग करके रैम में स्टोर कर सकते हैं या {path: content} dict रखना आसान बना सकते हैं जिसे आप केवल एक बार पढ़ते हैं।

पायथन रेगेक्स धीमा होने के लिए जाना जाता है, आपका डेटा बहुत आसान लगता है, आप अपनी इनपुटलाइन पर विभाजित और स्ट्रिप विधियों का उपयोग करने पर विचार कर सकते हैं।

striped=[l.split() for l in [c.strip() for c in file_desc.readlines()] if l] 

मेरा सुझाव है कि आप इस पढ़ने के लिए: https://gist.github.com/JeffPaine/6213790 correspondig वीडियो यहाँ है https://www.youtube.com/watch?v=OSGv2VnC0go

7

मैं इस में कई बार उपयोग किया है के रूप में यह बहु की एक विशेष आसान कार्यान्वयन है।

import pandas as pd 
from multiprocessing import Pool 

def reader(filename): 
    return pd.read_excel(filename) 

def main(): 
    pool = Pool(4) # number of cores you want to use 
    file_list = [file1.xlsx, file2.xlsx, file3.xlsx, ...] 
    df_list = pool.map(reader, file_list) #creates a list of the loaded df's 
    df = pd.concat(df_list) # concatenates all the df's into a single df 

if __name__ == '__main__': 
    main() 

इसका उपयोग करके आप बहुत अधिक काम किए बिना अपने कार्यक्रम की गति को काफी हद तक बढ़ा सकते हैं। इस रन भी तेजी से, CSV में के लिए अपनी फ़ाइलें बदलने पर विचार करने के लिए और का उपयोग कर पांडा ढंग से काम pandas.read_csv

: आप कितनी प्रोसेसर है पता नहीं है, तो आप अपने खोल ऊपर खींच रहा है और टाइपिंग

echo %NUMBER_OF_PROCESSORS% 

संपादित करें द्वारा जाँच कर सकते हैं

+0

पायथन-मूल सीएसवी मॉड्यूल '' 'को विभाजक के रूप में निर्दिष्ट करने की अनुमति देता है। –

1

आपका कोड आप जो भी वर्णन करते हैं वह नहीं करते हैं।

प्रश्न: 1. हर फ़ाइल पढ़ें और जांचें कि क्या लेबल कर रहे हैं। मुझे जो जानकारी चाहिए वह अक्सर पहले कुछ पंक्तियों में निहित होती है।

लेकिन आप पूरे फ़ाइल न केवल कुछ पंक्तियां पढ़ते हैं,। इस परिणाम को फ़ाइलों को पढ़ने में दो बार!

प्रश्न: 2. फ़ाइल को फिर से पढ़ें और डेटाफ्रेम को मानों के साथ भरें।

आप फिर से और फिर पाश में df['a'|'b'|'c'|'d'] के ऊपर लिख, जो बेकार है
मैं belive यह नहीं है कि आप क्या चाहते।
यह प्रश्न में दिए गए डेटा के लिए काम करता है, लेकिन यदि आपको एन मानों से निपटना है तो नहीं। एक अलग तर्क के साथ


प्रस्ताव:

data = {} 
for path in paths: 
    with open(path, 'r') as file_obj: 
     line = True 
     while line: 
      try: 
       line = file_obj.readline() 
       match = reg_ex.match(line) 
       if match.group(1) not in data: 
        data[ match.group(1) ] = [] 

       data[match.group(1)].append(match.group(2)) 
      except AttributeError: 
       pass 

print('data=%s' % data) 
df = pd.DataFrame.from_dict(data, orient='index').sort_index() 
df.rename(index=str, columns={0: "Number"}, inplace=True) 

आउटपुट:

data={'b': ['2'], 'a': ['1'], 'd': ['4'], 'c': ['3']} 
<class 'pandas.core.frame.DataFrame'> 
Index: 4 entries, a to d 
Data columns (total 1 columns): 
Number 4 non-null object 
dtypes: object(1) 
memory usage: 32.0+ bytes 
    Number 
a  1 
b  2 
c  3 
d  4 

टाइम टेबल:

   Code from Q: to_dict_from_dict 
    4 values 0:00:00.033071 0:00:00.022146 
1000 values 0:00:08.267750 0:00:05.536500 
10000 values 0:01:22.677500 0:00:55.365000 

अजगर के साथ परीक्षण किया गया: 3.4.2 - पांडा: 0.19.2 - पुन: 2.2.1

+0

हां, आप सही हैं। मेरा MWE अच्छा नहीं था। – bluprince13

+0

कृपया विस्तार करें ** MWE ** – stovfl

+0

जब मैंने इसे संशोधित करना शुरू किया तो यह बहुत जटिल हो गया। मुझे लगता है कि मैं इसे छोड़ दूंगा, लेकिन मैं इसे अपने स्पष्टीकरण में स्पष्ट कर दूंगा कि मैंने MWE को सरल रखने की कोशिश की है। – bluprince13

2

सबसे पहले, यदि आप कई बार में फ़ाइल पढ़ रहे हैं, ऐसा लगता है कि जैसा होगा टोंटी। फ़ाइल को 1 स्ट्रिंग ऑब्जेक्ट में पढ़ने का प्रयास करें और फिर इसे कई बार cStringIO का उपयोग करें।

दूसरा, आपने वास्तव में सभी फ़ाइलों में पढ़ने से पहले इंडेक्स बनाने का कोई कारण नहीं दिखाया है। यहां तक ​​कि यदि आप करते हैं, तो आप आईओ के लिए पांडों का उपयोग क्यों कर रहे हैं? ऐसा लगता है कि आप इसे नियमित पायथन डेटा संरचनाओं में बना सकते हैं (शायद __slots__ का उपयोग कर) और फिर इसे मास्टर डेटाफ़्रेम में डाल दें। यदि आपको फ़ाइल वाई पढ़ने से पहले फ़ाइल एक्स इंडेक्स की आवश्यकता नहीं है (जैसा कि आप दूसरे लूप का सुझाव देते हैं), तो आपको बस फ़ाइलों को एक बार लूप करने की आवश्यकता है।

तीसरा, आप तारों पर सरल split/strip उपयोग कर सकते हैं या तो अंतरिक्ष अलग टोकन बाहर निकलने के लिए, या यदि यह और अधिक जटिल है पायथन के मानक पुस्तकालय से CSV मॉड्यूल का उपयोग (वहाँ स्ट्रिंग, कोट और इस तरह कर रहे हैं)। जब तक आप यह नहीं दिखाते कि आप वास्तव में अपना डेटा कैसे बनाते हैं, तो उससे संबंधित एक फिक्स का सुझाव देना मुश्किल है।

क्या आप अब तक पता चला है सरल

for path in paths: 
    data = [] 
    with open(path, 'r') as file_obj: 
     for line in file_obj: 
      try: 
       d1, d2 = line.strip().split() 
      except ValueError: 
       pass 
      data.append(d1, int(d2))) 
    index, values = zip(*data) 
    subset_df = pd.DataFrame({"Number": pd.Series(values, index=index)}) 

यहाँ के साथ काफी जल्दी किया जा सकता है जब मैं पहले से आवंटित नहीं (उत्पन्न फ़ाइलों हैं डिस्क स्थान के साथ एक आभासी मशीन पर चलने के समय में अंतर है मोटे तौर पर आकार में 24MB):

import pandas as pd 
from random import randint 
from itertools import combinations 
from posix import fsync 


outfile = "indexValueInput" 

for suffix in ('1', '2'): 
    with open(outfile+"_" + suffix, 'w') as f: 
     for i, label in enumerate(combinations([chr(i) for i in range(ord('a'), ord('z')+1)], 8)) : 
      val = randint(1, 1000000) 
      print >>f, "%s %d" % (''.join(label), val) 
      if i > 3999999: 
       break 
     print >>f, "end" 
     fsync(f.fileno()) 

def readWithPandas(): 
    data = [] 
    with open(outfile + "_2", 'r') as file_obj: 
     for line in file_obj: 
      try: 
       d1, d2 = str.split(line.strip()) 
      except ValueError: 
       pass 
      data.append((d1, int(d2))) 
    index, values = zip(*data) 
    subset_df = pd.DataFrame({"Numbers": pd.Series(values, index=index)}) 

def readWithoutPandas(): 
    data = [] 
    with open(outfile+"_1", 'r') as file_obj: 
     for line in file_obj: 
      try: 
       d1, d2 = str.split(line.strip()) 
      except ValueError: 
       pass 
      data.append((d1, int(d2))) 
    index, values = zip(*data) 

def time_func(func, *args): 
    import time 
    print "timing function", str(func.func_name) 
    tStart = time.clock() 
    func(*args) 
    tEnd = time.clock() 
    print "%f seconds " % (tEnd - tStart) 

time_func(readWithoutPandas) 
time_func(readWithPandas) 

जिसके परिणामस्वरूप समय है:

timing function readWithoutPandas 
4.616853 seconds 
timing function readWithPandas 
4.931765 seconds 

आप इन इंडेक्स को अपने इंडेक्स बिल्डअप के साथ आज़मा सकते हैं और देख सकते हैं कि समय में क्या अंतर होगा। यह लगभग निश्चित है कि धीमी गति कई डिस्क पढ़ने से आता है। और चूंकि पांडों को एक शब्दकोश से अपना डेटाफ्रेम बनाने में कोई समय नहीं लगेगा, इसलिए आप पांडों को डेटा पास करने से पहले शुद्ध पायथन में अपनी अनुक्रमणिका कैसे बनाएं, यह पता लगाने से बेहतर होगा। लेकिन डेटा को पढ़ने और 1 डिस्क में इंडेक्स का निर्माण दोनों पढ़ें।

मुझे लगता है कि एक अन्य चेतावनी यह है कि यदि आप अपने कोड के अंदर से प्रिंट करते हैं, तो उम्मीद है कि इसमें काफी समय लगेगा। एक tty बौने को सादा पाठ लिखने में लगने वाला समय डिस्क पर पढ़ने/लिखने में लगने वाला समय होता है।

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