2013-10-06 1 views
0

안녕하세요. CSV 파일을 읽는 프로그램을 작성하고 있습니다. 독자 개체를 크래킹하고 next()를 호출하면 헤더 행이 생깁니다.하지만 다시 호출 할 때 file.seek을 수행하고있는 CSV의 믿을수있는 행이 있지만 대하여 StopIteration 오류를 제공 (0) 다음은 fine.Anyone는 '당신에게StopIteration csv 데이터를 읽는 동안 파이썬 코드에서 오류가 발생했습니다.

with open(file,'r') as f: 
    reader = csv.reader(f) 
    header = next(reader) 
    result = [] 
    for colname in header[2:]: 
      col_index = header.index(colname)  
    #   f.seek(0) 
      next(reader) 
+0

예 os와 관련있다 – maverick

+1

부수적으로, bar에서 foo는 절대하지 말아야한다 : index = bar.index (foo)'. 이것은 느리고 복잡하며 잠재적으로 버그가 있습니다 (두 열의 이름이 같은 경우 어떻게됩니까?). 그냥 'for index, foo in enumerate (bar) :'를 수행하십시오. – abarnert

답변

2

아래에 주어진 코드의 렸어요 스냅 샷이 설명하시기 바랍니다 노력하고 있습니다 각 열에 대해 한 번만 next을 호출하십시오 (첫 두 개는 제외). 예를 들어 열이 10 개인 경우 8 행을 읽으려고 시도합니다.

20 개의 행이있는 경우 예외가 발생하지 않지만 마지막 12 개의 행은 무시하므로 원치 않는 것일 수 있습니다. 반면에 행이 5 개인 경우 6 행을 읽으 려 할 때 증가 할 것입니다.

f.seek(0)이 예외를 방지하는 이유는 각 next 앞에 파일을 다시 시작하기 때문에 파일의 다른 모든 내용은 무시하고 계속해서 머리말 행을 반복해서 읽습니다. 그것은 아무것도 모으지는 않지만 유용하지 않습니다.

with open(file,'r') as f: 
    reader = csv.reader(f) 
    header = next(reader) 
    result = [] 
    for row in reader: 
     for col_index, colname in enumerate(header)[2:]: 
      value = row[col_index] 
      result.append(do_something_with(value, colname)) 

이 정확히 한 번 모든 행을 읽고, 각 열 있지만 각 행의 첫 번째 두 사람과 함께 무언가를 : 당신은 아마 원하는 무엇

이 같은 것입니다.


의견에서 실제로 원하는 것은 각 열의 최대 값을 찾는 것입니다. 따라서 열을 반복 할 필요가 있습니다. 그런 다음 각 열 내에서 행을 반복해야합니다.

csv.reader은 반복자이므로 한 번만 반복 할 수 있습니다. 방금이에게 확실한 방법을한다면, 그것은 작동하지 않습니다

maxes = {} 
with open(file) as f: 
    reader = csv.reader(f) 
    header = next(reader) 
    for col_index, colname in enumerate(header)[2:]: 
     maxes[colname] = max(reader, key=operator.itemgetter(col_index)) 

첫 번째 열은 좋은 헤더를 읽은 후 남은 어떤 읽습니다. 다음 열은 전체 파일을 읽은 후 남은 내용을 읽습니다. 이는 아무 것도 아닙니다.


그럼 어떻게 해결할 수 있습니까?

한 가지 방법은 외부 루프를 통해 반복자 매번 다시 작성하는 것입니다 :

maxes = {} 
with open(file) as f: 
    reader = csv.reader(f) 
    header = next(reader) 
for col_index, colname in enumerate(header)[2:]: 
    with open(file) as f: 
     reader = csv.reader(f) 
     next(reader) 
     maxes[colname] = max(reader, key=lambda row: float(row[col_index])) 

이 문제는 당신이 전체 파일을 N 시간을 읽기, 디스크에있는 파일을 읽는 것입니다 아마 프로그램이하는 가장 느린 것 일 것입니다.


은 당신이 f.seek(0)와 함께 할 시도했던 것은 파일 객체와 csv.reader 객체가 어떻게 작동하는지에 따라 달라집니다 트릭이다. 파일 객체는 반복자이지만 처음부터 다시 설정하거나 (또는 ​​위치를 저장하고 나중에 되돌릴 수있는 방법) 특별한 점이 있습니다. 그리고 csv.reader 객체는 기본적으로 파일 객체를 둘러싼 간단한 래퍼이므로 파일을 다시 설정하면 판독기도 재설정됩니다. (이것이 작동하는 것은 확실하지 않지만, csv의 작동 방식을 알고 있다면 실제로 안전하다는 것을 확신 할 수 있습니다.) 따라서 :

maxes = {} 
with open(file) as f: 
    reader = csv.reader(f) 
    header = next(reader) 
    for col_index, colname in enumerate(header)[2:]: 
     f.seek(0) 
     next(reader) 
     maxes[colname] = max(reader, key=lambda row: float(row[col_index])) 

이렇게하면 파일을 닫을 때마다 절약 할 수 있지만 비용이 많이 드는 부분은 아닙니다. 당신은 여전히 ​​디스크를 계속 읽고 있습니다. 이제 코드를 읽는 사람은 파일 객체를 반복자로 사용하지만 리셋하는 트릭을 이해해야합니다. 그렇지 않으면 코드 작동 방식을 알 수 없습니다.


그래서 어떻게 피할 수 있습니까?

일반적으로 반복기를 여러 번 통과해야하는 경우 두 가지 옵션이 있습니다. 간단한 해결책은 목록 등 재사용 가능한 반복자에 반복자를 복사하는 것입니다 :

maxes = {} 
with open(file) as f: 
    reader = csv.reader(f) 
    header = next(reader) 
    rows = list(reader) 
for col_index, colname in enumerate(header)[2:]: 
    maxes[colname] = max(rows, key=lambda row: float(row[col_index])) 

이는 훨씬 간단 이전 코드보다, 그것은 훨씬 더 빨리도합니다. 파일이 거대하지 않은 한. 모든 행을 목록에 저장하면 전체 파일을 한 번에 메모리로 읽게됩니다. 크기가 너무 커서 프로그램이 실패합니다. 또는, 가상 메모리를 사용하는 경우에만 프로그램이 루프를 통과 할 때마다 스왑 파일을 스 래싱하고 모든 것을 크롤링 속도를 느리게 할 때마다 프로그램이 메모리의 내부 및 외부로 스왑합니다.


또 다른 대안은 한 번만 수행하면되므로 작업을 재구성하는 것입니다. 즉, 바깥 쪽 행에 루프를 놓고 안쪽 열에는 루프를 놓아야합니다. 당신은 간단하게 할 수

with open(file) as f: 
    reader = csv.reader(f) 
    header = next(reader) 
    maxes = {colname: float('-inf') for colname in header[2:]} 
    for row in reader: 
     for col_index, colname in enumerate(header)[2:]: 
      maxes[colname] = max(maxes[colname], float(row[col_index])) 

이 더욱-예를 들어, 대신 Counter을 사용 : 그것은 그것은 디자인을 조금 재검토가 필요하며, 그것은 그냥 간단한 max 기능을 사용할 수 없습니다 의미하지만, 트레이드 오프는 아마 가치가있다 일반 dictreader 대신 DictReader인데, 이미 간단하고 읽기 쉽고 효율적입니다.

+0

안녕하세요 Abarnert, ur reply.What 주셔서 고맙습니다. 나는 모든 열에 대해 최대 값을 찾아야 만합니다. 그래서 모든 열에 대해 max() 생성기 식을 사용하고있었습니다. – maverick

+0

@maverick : 오케이, 대답을 업데이트하겠습니다. – abarnert

+0

@maverick : 앞으로는 실제로하고 싶은 것을 보여주고 문제를 재현 할 수있는 충분한 정보를 제공하는보다 완전한 예제를 제공해주십시오. – abarnert

-1

왜 작성하지 않은 :

header = next(reader) 

을 마지막 줄에서뿐만 아니라? 이것이 당신의 문제인지 나는 모른다. 그러나 나는 거기에서 시작할 것이다.

관련 문제