2017-03-22 2 views
1

큰 열의 CSV를 특정 제약 조건이 입력되지 않았으므로 초기의 누락 된 추가 제약 조건으로 읽으려고합니다. 모두은 필수 열뿐 아니라 데이터 프레임에 포함될 열을 필요로합니다. pandas.read_csv에서 읽을 열의 하위 집합을 지정하려면 usecols 인수를 사용할 수있는 것 같습니다. 그러나 읽을 열의 데이터 프레임에 어떤 열이 있는지 확인할 수있는 유일한 확실한 방법은 다음과 같습니다. 실제로 파일을 읽습니다.팬더에 필수 열 제한을 적용하십시오.

import pandas as pd 
from io import StringIO 

class MissingColumnsError(ValueError): 
    pass 

def cols_enforced_reader(*args, cols_must_exist=None, **kwargs): 
    if cols_must_exist is not None: 
     # Read the first line of the DataFrame and check the columns 
     new_kwargs = kwargs.copy() 
     new_kwargs['iterator'] = True 
     new_kwargs['chunksize'] = 1 

     if len(args): 
      filepath_or_buffer = args[0] 
      args = args[1:] 
     else: 
      filepath_or_buffer = new_kwargs.get('filepath_or_buffer', None) 

     df_iterator = pd.read_csv(filepath_or_buffer, *args, **new_kwargs) 

     c = next(df_iterator) 
     if not all(col in c.columns for col in cols_must_exist): 
      raise MissingColumnsError('Some required columns were missing!') 

     seek = getattr(filepath_or_buffer, 'seek', None) 
     if seek is not None: 
      if filepath_or_buffer.seekable(): 
       filepath_or_buffer.seek(0) 

    return pd.read_csv(filepath_or_buffer, *args, **kwargs) 

in_csv = """col1,col2,col3\n0,1,2\n3,4,5\n6,7,8""" 

# Should succeed 
df = cols_enforced_reader(StringIO(in_csv), cols_must_exist=['col1']) 
print('First call succeeded as expected.') 

# Should fail 
try: 
    df = cols_enforced_reader(StringIO(in_csv), cols_must_exist=['col7']) 
except MissingColumnsError: 
    print('Second call failed as expected.') 

이 : 나는 반복자로 dataframe을 읽는 작업 첫 번째 패스 버전을 만들었

후 정상적인 인수를 사용하여 파일을 읽고, 열이 있는지 확인, 첫 번째 줄을 얻는다 나에게 약간 지저분한 느낌이 들며 filepath_or_buffer (검색 할 수없는 스트림, 예를 들어 0에서 시작하지 않아야하는 버퍼)의 가능한 모든 입력을 실제로 처리하지 못합니다. 분명히 내가 여기있는 특정 유스 케이스에 맞게 조정할 수 있지만이 작업을 수행하는 더 우아한 방법이 있는지 궁금합니다. 일반 .

답변

1

하나의 행을 읽고 필요한 모든 열이 그 위에 있는지 테스트 할 수 있습니까? 예를 들어 :

import pandas as pd 

required_cols = ['col1', 'col2'] 
cols = pd.read_csv('input.csv', nrows=1).columns 

if all(req in cols for req in required_cols): 
    print pd.read_csv('input.csv') 
else: 
    print "Columns missing" 

는 스트림을 통해이 작업을 수행하려면 다른 방법이 csv.reader()를 통해 그것을 읽는 것,이 itertools.tee()와 호환됩니다

import pandas as pd 
from itertools import tee 
import csv 

required_cols = ['col1', 'col2'] 

with open('input.csv') as f_input: 
    csv_input = csv.reader(f_input) 
    csv_stream1, csv_stream2 = tee(csv_input, 2) 
    header = next(csv_stream1) 

    if all(req in header for req in required_cols): 
     df = pd.DataFrame(list(csv_stream2)[1:], columns=header) 
     print(df) 
    else: 
     print("Columns missing") 
+0

이 더 많거나 적은 무엇 내 질문에 일하고있어,하지만 그것은 여전히 ​​CSVs 버퍼와 경로가 잘 재생되지 않습니다 두 번, 파일을 읽고 필요합니다. 이상적으로는 먼저 열을 읽은 다음 그 열을 검사하여 오류를 던지거나 예상대로 계속 진행하는 무언가를 사용합니다. – Paul

+0

스트림을 가져 와서 ['itertools.tee()'] (https://docs.python.org/3.6/library/itertools.html?highlight=tee#itertools.tee)를 사용하여 복제 할 것을 제안하려고했습니다. 나는 팬더가 그걸 가지고 놀지 않는다는 것을 기억하는 것 같습니다. –

+0

그래,이 질문에 대한 답은 실제로 "아니, 우아하게 할 수 없다"고 생각합니다. csvreader가있는 버전은 pandas.read_csv에 대한 모든 인수를 무시한다는 단점이 있습니다. 내 버전과 첫 번째 버전의 조합과 더 많은 엣지 케이스 검사가이 작업을 수행하는 일반적인 기능을 만드는 유일한 방법 일 것이라고 생각합니다. – Paul

관련 문제