একটি বিশাল .csv ফাইল পড়া হচ্ছে


107

আমি বর্তমানে পাইথন ২.7-তে 1 মিলিয়ন সারি এবং 200 কলাম (ফাইল 100 মিমি থেকে 1.6 জিবি পর্যন্ত) এর সাথে .csv ফাইল থেকে ডেটা পড়ার চেষ্টা করছি। আমি 300,000 সারির নিচে ফাইলগুলির জন্য এটি (খুব ধীরে ধীরে) করতে পারি, তবে একবার উপরে গেলে আমি স্মৃতি ত্রুটি পাই। আমার কোডটি এর মতো দেখাচ্ছে:

def getdata(filename, criteria):
    data=[]
    for criterion in criteria:
        data.append(getstuff(filename, criteron))
    return data

def getstuff(filename, criterion):
    import csv
    data=[]
    with open(filename, "rb") as csvfile:
        datareader=csv.reader(csvfile)
        for row in datareader: 
            if row[3]=="column header":
                data.append(row)
            elif len(data)<2 and row[3]!=criterion:
                pass
            elif row[3]==criterion:
                data.append(row)
            else:
                return data

গেসটফ ফাংশনের অন্য ধারাটির কারণ হ'ল মানদণ্ডে মাপসই সমস্ত উপাদান সিএসভি ফাইলে একসাথে তালিকাভুক্ত হবে, সুতরাং সময় বাঁচানোর জন্য লুপটি ছেড়ে যাওয়ার পরে আমি লুপটি ছেড়ে যাই leave

আমার প্রশ্নগুলি হ'ল:

  1. বড় ফাইলগুলির সাথে এটি কাজ করতে আমি কীভাবে পরিচালনা করতে পারি?

  2. আমি কীভাবে আরও দ্রুত এটি তৈরি করতে পারি?

আমার কম্পিউটারে 8 জিবি র‌্যাম রয়েছে, যা 64 বিট উইন্ডোজ 7 চালাচ্ছে, এবং প্রসেসরটি 3.40 গিগাহার্টজ (আপনার কোন তথ্য প্রয়োজন তা নির্দিষ্ট নয়)।


1
আমি সচেতন যে এখানে বেশ কয়েকটি অনুরূপ আপাতদৃষ্টিতে প্রশ্ন রয়েছে তবে এগুলির কোনওটিই আমার সমস্যার পক্ষে যথেষ্ট সাহায্য করার পক্ষে যথেষ্ট সুনির্দিষ্ট বলে মনে হয় নি। আমি যদি মিস করেছি এমন কিছু থাকে তবে দুঃখিত।
চার্লস ডিলন

2
আপনার পড়ার ডেটাটি মেমোরিতে রাখার পরিবর্তে কোনও ডাটাবেজে (যেমন স্ক্লাইট) সংরক্ষণ করা উচিত। এরপরে আপনি ডিবিতে ফিল্টারিংয়ের মতো আরও প্রসেসিং চালাতে পারেন
মাইকেল বুটসচার

উত্তর:


158

আপনি একটি তালিকাতে সমস্ত সারি পড়ছেন, তারপরে সেই তালিকাটি প্রক্রিয়া করছেন। এটা করবেন না

আপনার সারিগুলি তৈরি করার সাথে সাথে প্রক্রিয়া করুন। আপনার যদি প্রথমে ডেটা ফিল্টার করতে হয় তবে একটি জেনারেটর ফাংশন ব্যবহার করুন:

import csv

def getstuff(filename, criterion):
    with open(filename, "rb") as csvfile:
        datareader = csv.reader(csvfile)
        yield next(datareader)  # yield the header row
        count = 0
        for row in datareader:
            if row[3] == criterion:
                yield row
                count += 1
            elif count:
                # done when having read a consecutive series of rows 
                return

আমি আপনার ফিল্টার পরীক্ষাও সরল করে দিয়েছি; যুক্তি একই কিন্তু আরও সংক্ষিপ্ত।

যেহেতু আপনি কেবল মানদণ্ডের সাথে সারিগুলির একক ক্রম মেলে, আপনি এটিও ব্যবহার করতে পারেন:

import csv
from itertools import dropwhile, takewhile

def getstuff(filename, criterion):
    with open(filename, "rb") as csvfile:
        datareader = csv.reader(csvfile)
        yield next(datareader)  # yield the header row
        # first row, plus any subsequent rows that match, then stop
        # reading altogether
        # Python 2: use `for row in takewhile(...): yield row` instead
        # instead of `yield from takewhile(...)`.
        yield from takewhile(
            lambda r: r[3] == criterion,
            dropwhile(lambda r: r[3] != criterion, datareader))
        return

আপনি এখন getstuff()সরাসরি লুপ করতে পারেন । এতেও করুন getdata():

def getdata(filename, criteria):
    for criterion in criteria:
        for row in getstuff(filename, criterion):
            yield row

এখন getdata()আপনার কোডে সরাসরি লুপ করুন :

for row in getdata(somefilename, sequence_of_criteria):
    # process row

মাপদণ্ডের জন্য আপনার হাজার হাজার লাইনের পরিবর্তে আপনি এখন কেবলমাত্র একটি সারি মেমোরিতে রেখেছেন।

yieldএকটি ফাংশনটিকে একটি জেনারেটর ফাংশন করে তোলে , যার অর্থ এটি যতক্ষণ না আপনি তার উপর লুপিং শুরু না করেন এটি কোনও কাজ করবে না।


এই কৌশলটি ব্যবহার করার সময় আপনি কি একই মেমরির দক্ষতা পান csv.DictReader? কারণ একটি 2.5 জিবি। সিএসভি ফাইলের আমার পরীক্ষাগুলি দেখায় যে csv.readerপাইথন প্রক্রিয়াটি পুরো 2.5 গিগাবাইটের মেমরির ব্যবহারের পরিবর্তে পাইথন প্রক্রিয়াটির পরিবর্তে এটি ব্যবহার করার সময় সারি দিয়ে সারিটি পুনরাবৃত্তি করার চেষ্টা করে ।
ব্যবহারকারী5359531

@ user5359531 যা আপনাকে কোথাও কোথাও অভিধানের বিষয়বস্তুতে রেফারেন্স রাখার নির্দেশ করবে would ডিকট্রিডার নিজে থেকে রেফারেন্স ধরে রাখে না তাই সমস্যা অন্য কোথাও রয়েছে।
মার্টিজন পিটারস

39

যদিও মার্তিজিনের উত্তরটি সবচেয়ে ভাল। নতুনদের জন্য বড় সিএসভি ফাইলগুলি প্রক্রিয়া করার আরও স্বজ্ঞাত উপায়। এটি আপনাকে একসাথে সারি বা খণ্ডগুলি গোষ্ঠীগুলি প্রক্রিয়া করতে দেয়।

import pandas as pd
chunksize = 10 ** 8
for chunk in pd.read_csv(filename, chunksize=chunksize):
    process(chunk)

9
পান্ডাস ব্যবহার কেন এটি আরও স্বজ্ঞাত করে তোলে?
wwii

25
4 লাইনের কোডটি আমার মতো নবাগতদের পক্ষে সর্বদা ভাল।
mmann1123

3
নিয়মিত পাইথন কোডটি ঠিক তত সংক্ষিপ্ত, এবং আপনাকে প্রতি লাইনে প্রক্রিয়া করতে দেয়। জেনারেটরের ফাংশন কেবলমাত্র ফিল্টার করার জন্য রয়েছে; পান্ডাসে আপনি কীভাবে একই ফিল্টারিং করতে যাবেন?
মার্টিজন পিটারস

1
এটা সত্যিই দারুন! পান্ডাস ব্যবহার করে বড় সিএসভি ফাইল লোড এবং প্রক্রিয়াকরণের আমার সমস্যা সমাধান করুন। ধন্যবাদ!
এলসা লি

1
কিছু সারিগুলির সামগ্রী একাধিক লাইনে ছড়িয়ে গেলেও এটি খুব ভালভাবে কাজ করে!
ডিলসন বিক্রয়

19

আমি ন্যায্য পরিমাণ কম্পন বিশ্লেষণ করি এবং বড় ডেটা সেটগুলি দেখি (দশক এবং কয়েক লক্ষ লক্ষ পয়েন্ট)। আমার পরীক্ষাটি পান্ডাস.ড্রেড_সিএসভি () ফাংশনটি numpy.genfromtxt () এর চেয়ে 20 গুণ দ্রুত হতে দেখায়। এবং জিনফ্র্যামটেক্সট () ফাংশনটি numpy.loadtxt () এর চেয়ে 3 গুণ বেশি দ্রুত। মনে হচ্ছে বড় ডেটা সেট করার জন্য আপনার পান্ডার দরকার

আমি কোড এবং ডেটা সেট আমি একটি ব্লগ আলোচনা এই পরীক্ষামূলক ব্যবহার করা পোস্ট কম্পন বিশ্লেষণের জন্য ম্যাটল্যাব বনাম পাইথন


3
ওপির প্রাথমিক ইস্যুটি গতির এক নয়, এটি ছিল স্মৃতিশক্তি ক্লান্তি। ফাইলটি প্রক্রিয়াকরণের জন্য একটি পৃথক ফাংশন ব্যবহার করা স্ট্রিম প্রসেসর ব্যবহার না করে এটিকে তালিকায় পড়ার উত্সাহ সরিয়ে দেয় না।
পাইডসাইনার

6

আমার জন্য যা কাজ করেছে তা হ'ল সুপারহাস্ট

import pandas as pd
import dask.dataframe as dd
import time
t=time.clock()
df_train = dd.read_csv('../data/train.csv', usecols=[col1, col2])
df_train=df_train.compute()
print("load train: " , time.clock()-t)

আর একটি কার্যকরী সমাধান হ'ল:

import pandas as pd 
from tqdm import tqdm

PATH = '../data/train.csv'
chunksize = 500000 
traintypes = {
'col1':'category',
'col2':'str'}

cols = list(traintypes.keys())

df_list = [] # list to hold the batch dataframe

for df_chunk in tqdm(pd.read_csv(PATH, usecols=cols, dtype=traintypes, chunksize=chunksize)):
    # Can process each chunk of dataframe here
    # clean_data(), feature_engineer(),fit()

    # Alternatively, append the chunk to list and merge all
    df_list.append(df_chunk) 

# Merge all dataframes into one dataframe
X = pd.concat(df_list)

# Delete the dataframe list to release memory
del df_list
del df_chunk

না df_train=df_train.compute()আপনার প্রথম দ্রবণে লাইন মেমরিতে পুরো ডেটা সেটটি ... যা সে কি করতে না চাচ্ছে লোড?
স্যাম ডিলার্ড

3

এই প্রশ্নের অবতারণ কারও জন্য। ' চুনসাইজ ' এবং ' ইউজকোলস ' দিয়ে পান্ডা ব্যবহার করা আমাকে প্রস্তাবিত বিকল্পগুলির চেয়ে দ্রুত একটি বিশাল জিপ ফাইল পড়তে সহায়তা করে।

import pandas as pd

sample_cols_to_keep =['col_1', 'col_2', 'col_3', 'col_4','col_5']

# First setup dataframe iterator, ‘usecols’ parameter filters the columns, and 'chunksize' sets the number of rows per chunk in the csv. (you can change these parameters as you wish)
df_iter = pd.read_csv('../data/huge_csv_file.csv.gz', compression='gzip', chunksize=20000, usecols=sample_cols_to_keep) 

# this list will store the filtered dataframes for later concatenation 
df_lst = [] 

# Iterate over the file based on the criteria and append to the list
for df_ in df_iter: 
        tmp_df = (df_.rename(columns={col: col.lower() for col in df_.columns}) # filter eg. rows where 'col_1' value grater than one
                                  .pipe(lambda x:  x[x.col_1 > 0] ))
        df_lst += [tmp_df.copy()] 

# And finally combine filtered df_lst into the final lareger output say 'df_final' dataframe 
df_final = pd.concat(df_lst)

1

পাইথন 3 এর আরও একটি সমাধান এখানে দেওয়া হয়েছে:

import csv
with open(filename, "r") as csvfile:
    datareader = csv.reader(csvfile)
    count = 0
    for row in datareader:
        if row[3] in ("column header", criterion):
            doSomething(row)
            count += 1
        elif count > 2:
            break

এখানে datareaderএকটি জেনারেটর ফাংশন।


সুতরাং, এটি সলিউশন হিসাবে দক্ষতার সাথে কাজ করে যা ফলন অপারেটর ব্যবহার করে। : দুঃখিত, এটা হয় না। কলব্যাক ফাংশন কলটি আরও ওভারহেড যুক্ত করে, বিশেষত যেহেতু আপনাকে স্পষ্টভাবে এবং পৃথকভাবে রাষ্ট্র পরিচালনা করতে হবে।
মার্টিজন পিটারস

@ মার্তিজন পিটার্স ধন্যবাদ উত্তর আপডেট।
habষভ অগ্রহরি

0

আপনি পান্ডাস ব্যবহার করেন তাহলে এবং উপস্থিত RAM- র প্রচুর (মেমরিতে পুরো ফাইলটি পড়ার যথেষ্ট) থাকতে ব্যবহার করার চেষ্টা করুন pd.read_csvসঙ্গে low_memory=False, যেমন:

import pandas as pd
data = pd.read_csv('file.csv', low_memory=False)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.