2013-01-10 23 views
5

Ich habe eine Frage zu Duplikaten in Python zu entfernen. Ich habe eine Reihe von Beiträgen gelesen, konnte sie aber noch nicht lösen. Ich habe folgende CSV-Datei:Python Duplikate entfernen

EDIT

Eingang:

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 

ausgegeben werden soll:

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 

In Worten, wenn die ID ist die nimm auch Werte aus der Zeile mit Quelle "NY Times", wenn der r Wenn "NY Times" einen leeren Wert hat und die doppelte Zeile aus der Quelle "ESPN" einen Wert für diese Zelle hat, nehmen Sie den Wert aus der Zeile mit der Quelle "ESPN". Markieren Sie für die Ausgabe die ursprünglichen zwei Zeilen als Duplikate und erstellen Sie eine dritte Zeile.

Um ein wenig weiter zu klären, da ich dieses Skript auf vielen verschiedenen csv-Dateien mit unterschiedlichen Spaltenüberschriften laufen muß, kann ich nicht wie etwas tun:

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 

Weil ich das Programm will laufen die ersten beiden Spalten unabhängig von den anderen Spalten in der Tabelle. Mit anderen Worten, "ID" und "Source" sind in jeder Eingabedatei, aber der Rest der Spalten ändert sich abhängig von der Datei.

Würde schätzen jede Hilfe, die Sie anbieten können! FYI, "Quelle" kann nur sein: NY Times, ESPN oder Wall Street Journal und die Reihenfolge der Priorität für Duplikate ist: Nimm NY Times, wenn verfügbar, ansonsten nimm ESPN, ansonsten das Wall Street Journal. Dies gilt für jede Eingabedatei.

Antwort

2

Der Code unten liest alle Datensätze in einem großen Wörterbuch, dessen Schlüssel ihre Identifikatoren sind und deren Werte Wörterbücher Mapping Quellennamen gesamten Datenzeilen sind. Dann durchläuft es das Wörterbuch und gibt Ihnen die Ausgabe, nach der Sie gefragt haben.

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

Danke für die tolle Antwort. Es funktioniert sehr gut auf den Daten. Entschuldigung für die verspätete Antwort. Ich wollte den Code selbst durcharbeiten, um sicherzustellen, dass ich wirklich verstanden habe, warum das funktioniert. Ich stieß auf ein Problem: Wenn eine gegebene Zeile die gleichen "ID" - und "Source" -Werte hat, dann nimmt das aktuelle Skript nur die letzte vorkommende Zeile mit dieser bestimmten "ID" - und "Source" -Kombination. Gibt es eine Möglichkeit, den Code so zu optimieren, dass alle Originalzeilen in die Ausgabe kopiert werden (ggf. mit dem Tag "duplicate") UND die Zeile "not_duplicate" ausgefüllt wird, um das in diesem Kommentar erwähnte Problem zu vermeiden? – user7186

+0

Ich füge einen Beispieldatenpunkt zum obigen Beitrag als Bearbeitung hinzu, damit Sie das leichter sehen können. Nochmals vielen Dank! Das ist sehr hilfreich und ich habe eine Menge gelernt, um es neu zu tippen. – user7186

+0

Im neuen Beispiel oben gibt es zwei Zeilen mit "ID" = 1 und "SOURCE" = ESPN. Wenn es keinen Wert für eine gegebene Spalte in der Zeile "NY Times" gibt und es einen Wert in beiden Spalten der "ESPN" -Zeilen gibt, spielt es keine Rolle, aus welcher ESPN-Zeile wir stammen, nur dass wir konsistent sind Dateien. Wenn jedoch die „New York Times“ row keinen Wert für eine bestimmte Spalte und eine „ESPN“ row (ESPN A) keinen Wert für die Spalte entweder hat, nimmt von dem anderen „ESPN“ row (ESPN B) . Und wenn ESPN A einen Wert hat, aber ESPN B nicht der Fall, und die „New York Times“ Zeile nicht, nehmen Sie von ESPN A. – user7186