2013-01-10 4 views
5

파이썬에서 중복 제거에 대한 질문이 있습니다. 나는 많은 게시물을 읽었지만 아직 해결할 수 없었다.파이썬 중복 제거

가 입력

편집 :

ID, Source, 1.A, 1.B, 1.C, 1.D 
1, ESPN, 5,7,,,M 
1, NY Times,,10,12,W 
1, ESPN, 10,,Q,,M 

출력이되어야합니다 :

ID, Source, 1.A, 1.B, 1.C, 1.D, duplicate_flag 
1, ESPN, 5,7,,,M, duplicate 
1, NY Times,,10,12,W, duplicate 
1, ESPN, 10,,Q,,M, duplicate 
1, NY Times, 5 (or 10 doesn't matter which one),7, 10, 12, W, not_duplicate 

이, ID가 있다면 나는 다음과 같은 CSV 파일이 같은 경우, 소스가 "NY Times"인 행에서 값을 취합니다. r "NY Times"가 빈 값을 갖고 "ESPN"소스의 중복 행에 해당 셀의 값이있는 경우 "ESPN"소스가있는 행의 값을 가져옵니다. 출력을 위해 원본 2 줄을 중복으로 표시하고 세 번째 줄을 만듭니다. 내가 원하는 때문에

def main(): 
     with open(input_csv, "rb") as infile: 
      input_fields = ("ID", "Source", "1.A", "1.B", "1.C", "1.D") 
      reader = csv.DictReader(infile, fieldnames = input_fields) 
      with open(output_csv, "wb") as outfile: 
       output_fields = ("ID", "Source", "1.A", "1.B", "1.C", "1.D", "d_flag") 
       writer = csv.DictWriter(outfile, fieldnames = output_fields) 
       writer.writerow(dict((h,h) for h in output_fields)) 
       next(reader) 
       first_row = next(reader) 
       for next_row in reader: 
        #stuff 

하는 프로그램에 실행하는 : 나는 다른 열 머리글과 다양한 CSV 파일에이 스크립트를 실행해야하기 때문에

내가 뭔가를 할 수없는, 조금 더를 명확히하기 위해 처음 두 열은 테이블에있는 다른 열과는 독립적입니다. 즉, "ID"와 "소스"는 모든 입력 파일에 있지만 나머지 열은 파일에 따라 달라집니다.

제공 할 수있는 도움을 주시면 감사하겠습니다. 참고로, "출처"는 NY Times, ESPN 또는 월스트리트 저널이 될 수 있습니다. 중복되는 경우 우선 순위는 다음과 같습니다. 가능한 경우 NY Times를 가져오고, 그렇지 않으면 ESPN을 가져 가거나 월스트리트 저널을 가져옵니다. 이것은 모든 입력 파일에 적용됩니다.

답변

2

아래 코드는 모든 레코드를 식별자가 키이고 값이 소스 이름을 전체 데이터 행에 매핑하는 사전 인 큰 사전으로 읽습니다. 그런 다음 사전을 반복하고 요청한 결과를 제공합니다.

import csv 

header = None 
idfld = None 
sourcefld = None 

record_table = {} 

with open('input.csv', 'rb') as csvfile: 
    reader = csv.reader(csvfile) 
    for row in reader: 
     row = [x.strip() for x in row] 

     if header is None: 
      header = row 
      for i, fld in enumerate(header): 
       if fld == 'ID': 
        idfld = i 
       elif fld == 'Source': 
        sourcefld = i 
      continue 

     key = row[idfld] 
     sourcename = row[sourcefld] 

     if key not in record_table: 
      record_table[key] = {sourcename: row, "all_rows": [row]} 
     else: 
      if sourcename in record_table[key]: 
       cur_row = record_table[key][sourcename] 
       for i, fld in enumerate(row): 
        if cur_row[i] == '': 
         record_table[key][sourcename][i] = fld 
      else: 
       record_table[key][sourcename] = row 
      record_table[key]["all_rows"].append(row) 

print ', '.join(header) + ', duplicate_flag' 

for recordid in record_table: 
    rowdict = record_table[recordid] 

    final_row = [''] * len(header) 

    rowcount = len(rowdict) 

    for sourcetype in ['NY Times', 'ESPN', 'Wall Street Journal']: 
     if sourcetype in rowdict: 
      row = rowdict[sourcetype] 
      for i, fld in enumerate(row): 
       if final_row[i] != '': 
        continue 
       if fld != '': 
        final_row[i] = fld 

    if rowcount > 1: 
     for row in rowdict["all_rows"]: 
      print ', '.join(row) + ', duplicate' 

    print ', '.join(final_row) + ', not_duplicate' 
+0

위대한 답변을 주셔서 감사합니다. 그것은 데이터에 아주 잘 작동합니다. 응답 지연으로 인해 유감스럽게 생각합니다. 코드가 작동하여 실제로 작동하는지 이해할 수 있도록 노력했습니다. 나는 하나의 문제에 부딪쳤다 : 만약 주어진 행이 동일한 "ID"와 "Source"값을 가지고 있다면, 현재 스크립트는 그 특정한 "ID"와 "Source"조합으로 마지막 행을 취하게 될 것이다. 모든 원본 줄이 출력 ("duplicate"태그가있는 경우)에 복사되고 "not_duplicate"행이이 주석에 언급 된 문제를 피하기 위해 채워지도록 코드를 조정할 수 있습니까? – user7186

+0

위의 게시물에 샘플 데이터 포인트를 추가하여보다 쉽게 ​​볼 수 있습니다. 다시 한번 고마워요! 이것은 정말로 도움이되고 나는 그것을 재 입력하는 좋은 양을 배웠습니다. – user7186

+0

위의 새 예제에서는 "ID"= 1 및 "SOURCE"= ESPN 인 두 행이 있습니다. "NY Times"행에 주어진 열에 값이없고 "ESPN"행의 두 열에 값이있는 경우 어떤 ESPN 행을 가져 왔는지에 상관없이 모든 행에서 일관성을 유지합니다 파일. 그러나 "NY Times"행에 특정 열에 대한 값이없고 "ESPN"행 (ESPN A)에 해당 열의 값이 없으면 다른 "ESPN"행 (ESPN B)에서 가져옵니다. . 그리고 ESPN A에 값이 있지만 ESPN B가없고 "NY Times"행에없는 경우 ESPN A를 가져옵니다. – user7186