Ich habe eine Textdatei mit einer Größe von ca. 25 GB. Ich möchte die doppelten Zeilen basierend auf dem Wert in der zweiten Spalte löschen. Wenn in einer Datei Duplikate gefunden werden, möchte ich alle Zeilen mit diesem Wert in der Spalte löschen und nur eine Zeile mit dem höchsten Wert in der vierten Spalte behalten. Die Datei liegt im CSV-Format vor und ist bereits sortiert.
storm_id,Cell_id,Windspeed,Storm_Surge,-1
2,10482422,45,0.06,-1
2,10482422,45,0.18,-1
2,10482422,45,0.4,-1
2,10482423,45,0.15,-1
2,10482423,45,0.43,-1
2,10482424,45,0.18,-1
2,10482424,45,0.49,-1
2,10482425,45,0.21,-1
2,10482425,45,0.52,-1
2,10482426,45,0.27,-1
2,10482426,45,0.64,-1
2,10482427,45,0.09,-1
2,10482427,45,0.34,-1
2,10482427,45,0.73,-1
Im obigen Beispiel möchte ich nur einen maximalen Anstiegswert für jeden, Cell_Id
indem ich andere doppelte Zeilen lösche
Die erwartete Ausgabe ist:
2,10482422,45,0.4,-1
2,10482423,45,0.43,-1
2,10482424,45,0.49,-1
2,10482425,45,0.52,-1
2,10482426,45,0.64,-1
2,10482427,45,0.73,-1
Antwort1
Da die Eingabe bereits nach der zweiten Spalte gruppiert/sortiert zu sein scheint, sollte dies recht einfach sein undnichterfordern, den gesamten Datensatz im Speicher zu behalten und zu sortieren, nur zwei Datensätze gleichzeitig. 1
Ich dachte zuerst an eine Awk-Lösung, fand sie aber zu umständlich für den Umgang mit Arrays und nicht leeren Feldtrennzeichen. Dann entschied ich mich für ein eher kurzes Python-Programm:
#!/usr/bin/python3
import sys
DELIMITER = ','
def remove_duplicates(records):
prev = None
for r in records:
r = (int(r[0]), int(r[1]), int(r[2]), float(r[3]), int(r[4]))
if prev is None:
prev = r
elif r[1] != prev[1]:
yield prev
prev = r
elif r[3] > prev[3]:
prev = r
if prev is not None:
yield prev
def main():
for r in remove_duplicates(
l.rstrip('\n').rsplit(DELIMITER) for l in sys.stdin
):
print(*r, sep=',')
if __name__ == '__main__':
main()
Auf meinem System hat es einen Durchsatz von ~250.000 Datensätzen oder 5 MB pro CPU-Sekunde.
Verwendung
python3 remove-duplicates.py < input.txt > output.txt
Das Programm kann mit Spaltenüberschriften nicht umgehen, deshalb müssen Sie diese entfernen:
tail -n +2 < input.txt | python3 remove-duplicates.py > output.txt
Wenn Sie sie wieder zum Ergebnis hinzufügen möchten:
{ read -r header && printf '%s\n' "$header" && python3 remove-duplicates.py; } < input.txt > output.txt
1 Dies ist ein großer Vorteil gegenüberWaltinatorsUndStahltreiber Ansätze für Datensätze, die nicht in den Hauptspeicher passen.
Antwort2
Wenn Sie sie sortiert hätten inabnehmendReihenfolge des 4. Feldes, Sie hätten einfach das erste Vorkommen jedes 2. Feldwertes mithilfe eines assoziativen Arrays oder Hashs nehmen können, z. B. awk -F, '!seen[$2]++' file
oderperl -F, -ne 'print $_ unless $seen{$F[1]}++'
Bei den Werten in aufsteigender Reihenfolge ist es etwas schwieriger, dies in einem effizienten Einzeldurchgang zu tun. Sie können dies (mit ein wenig Einrichtung) tun, indem Sie bei jeder Änderung des Schlüsselwerts die vorherige Zeile drucken:
awk -F, '
NR==1 {print; next} # print the header line
NR==2 {key=$2; next} # initialize the comparison
$2 != key {
print lastval; key = $2 # print the last (largest) value of the previous key group
}
{lastval = $0} # save the current line
END {print lastval} # clean up
' file
storm_id,Cell_id,Windspeed,Storm_Surge,-1
2,10482422,45,0.4,-1
2,10482423,45,0.43,-1
2,10482424,45,0.49,-1
2,10482425,45,0.52,-1
2,10482426,45,0.64,-1
2,10482427,45,0.73,-1
Antwort3
Wenn Sie nicht zu viele eindeutige Cell_ids haben, können Sie die bereits gesehenen in einem assoziativen Perl-Array nachverfolgen. Wenn Sie zu viele haben (und mein Perl-Skript nicht genügend Speicher hat), schreiben Sie ein C
Programm, um eindeutige in einem Bitfeld zu speichern. Hier ist das Perl.
#!/usr/bin/perl -w
use strict;
my %seen = (); # key=Cell_ID, value=1
my @cols=(); # for splitting input
while( <> ) { # read STDIN
@cols = split ',',$_;
next if ( defined $seen{$cols[1]}); # skip if we already saw this Cell_Id
$seen{$cols[1]} = 1;
print;
}
Hier ist mein Test:
walt@bat:~(0)$ cat u.dat
storm_id,Cell_id,Windspeed,Storm_Surge,-1
2,10482422,45,0.06,-1
2,10482422,45,0.18,-1
2,10482422,45,0.4,-1
2,10482423,45,0.15,-1
2,10482423,45,0.43,-1
2,10482424,45,0.18,-1
2,10482424,45,0.49,-1
2,10482425,45,0.21,-1
2,10482425,45,0.52,-1
2,10482426,45,0.27,-1
2,10482426,45,0.64,-1
2,10482427,45,0.09,-1
2,10482427,45,0.34,-1
2,10482427,45,0.73,-1
walt@bat:~(0)$ perl ./unique.pl u.dat
storm_id,Cell_id,Windspeed,Storm_Surge,-1
2,10482422,45,0.06,-1
2,10482423,45,0.15,-1
2,10482424,45,0.18,-1
2,10482425,45,0.21,-1
2,10482426,45,0.27,-1
2,10482427,45,0.09,-1