bestsource

대용량 .csv 파일 읽기

bestsource 2023. 7. 18. 21:50
반응형

대용량 .csv 파일 읽기

현재 Python 2.7의 .csv 파일에서 최대 100만 개의 행과 200개의 열(파일 범위는 100mb에서 1.6gb)의 데이터를 읽으려고 합니다.행 수가 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

getstuff 함수에 else 절이 있는 이유는 csv 파일에 기준에 맞는 모든 요소가 함께 나열되기 때문에 시간을 절약하기 위해 통과할 때 루프를 탈퇴합니다.

제 질문은 다음과 같습니다.

  1. 어떻게 하면 더 큰 파일에서 이 작업을 수행할 수 있을까요?

  2. 제가 더 빨리 할 수 있는 방법이 있나요?

내 컴퓨터에는 64비트 Windows 7(윈도우 7)을 실행하는 8GB RAM이 있고 프로세서는 3.40GHz(필요한 정보가 확실하지 않음)입니다.

모든 행을 목록으로 읽은 다음 해당 목록을 처리하는 중입니다.그러지 마세요.

행을 생성할 때 행을 처리합니다.데이터를 먼저 필터링해야 하는 경우 제너레이터 기능을 사용합니다.

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 파일을 보다 직관적으로 처리할 수 있는 방법이 있습니다.이렇게 하면 행 그룹 또는 청크를 한 번에 처리할 수 있습니다.

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

저는 상당한 양의 진동 분석을 수행하고 대용량 데이터 세트(수천만 개, 수억 개의 포인트)를 살펴봅니다.테스트 결과 panda.read_csv() 기능이 tatts()의 numpy.gen보다 20배 더 빠릅니다.그리고 genfrom tex() 기능은 numpy.load tex()보다 3배 빠릅니다.대용량 데이터 세트를 위해서는 팬더가 필요한 것 같습니다.

저는 이번 테스트에서 사용한 코드와 데이터 세트를 MATLAB 대 Python의 진동 분석에 대해 논의하는 블로그에 게시했습니다.

이 질문에 도달한 사람을 위해.'chunksize'와 'usecols'가 있는 판다를 사용하는 은 다른 제안된 옵션보다 큰 zip 파일을 더 빨리 읽는 데 도움이 되었습니다.

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)

나에게 효과가 있었던 것과 매우 빠른 것은

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

다음은 Python3를 위한 다른 솔루션입니다.

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는 제너레이터 함수입니다.

만약 당신이 팬더를 사용하고 있고 RAM이 많다면 (전체 파일을 메모리에 읽기에 충분합니다)low_memory=False항목:

import pandas as pd
data = pd.read_csv('file.csv', low_memory=False)

언급URL : https://stackoverflow.com/questions/17444679/reading-a-huge-csv-file

반응형