Neulich wurde 100 Language Processing Knock 2020 veröffentlicht. Ich selbst arbeite erst seit einem Jahr an natürlicher Sprache und kenne die Details nicht, aber ich werde alle Probleme lösen und veröffentlichen, um meine technischen Fähigkeiten zu verbessern.
Alle müssen auf dem Jupyter-Notizbuch ausgeführt werden, und die Einschränkungen der Problemstellung können bequem verletzt werden. Der Quellcode ist auch auf Github. Ja.
Kapitel 1 ist hier.
Die Umgebung ist Python 3.8.2 und Ubuntu 18.04.
Ich denke, dass hier als Kommentarartikel leichter zu verstehen ist. Ich möchte, dass die Autoren Kommentarartikel bis Kapitel 10 schreiben.
popular-names.txt ist eine Datei, in der "Name", "Geschlecht", "Anzahl der Personen" und "Jahr" eines in den USA geborenen Babys in einem durch Tabulatoren getrennten Format gespeichert werden. Erstellen Sie ein Programm, das die folgende Verarbeitung ausführt, und führen Sie popular-names.txt als Eingabedatei aus. Führen Sie außerdem denselben Prozess mit einem UNIX-Befehl aus und überprüfen Sie das Ausführungsergebnis des Programms.
Bitte laden Sie den erforderlichen Datensatz von [hier] herunter (https://nlp100.github.io/ja/ch02.html).
Die heruntergeladene Datei wird unter "Daten" abgelegt.
Zählen Sie die Anzahl der Zeilen. Verwenden Sie zur Bestätigung den Befehl wc.
Code
with open('data/popular-names.txt') as f:
print(len(list(f)))
Ausgabe
2780
Finden Sie einfach die Länge des Dateiobjekts. Da das Dateiobjekt ein Iterator ist, muss es aufgelistet werden. Wenn die Eingabe eine ausreichend große Datei ist, passt sie möglicherweise nicht in den Speicher. In einem solchen Fall können Sie sie jedoch einfach mit der for-Anweisung drehen und zählen.
Code
wc -l < data/popular-names.txt
Ausgabe
2780
Ermitteln Sie die Anzahl der Zeilen, indem Sie die Option l im Befehl wc
angeben. Wenn Sie einen Dateinamen angeben, werden verschiedene Extras angezeigt. Geben Sie ihn daher über die Standardeingabe an.
Ersetzen Sie jede Registerkarte durch ein Leerzeichen. Verwenden Sie zur Bestätigung den Befehl sed, den Befehl tr oder den Befehl expand.
Code
with open('data/popular-names.txt') as f:
for line in f:
line = line.strip()
line = line.replace('\t', ' ')
print(line)
Ausgabe(Erste 10 Zeilen)
Mary F 7065 1880
Anna F 2604 1880
Emma F 2003 1880
Elizabeth F 1939 1880
Minnie F 1746 1880
Margaret F 1578 1880
Ida F 1472 1880
Alice F 1414 1880
Bertha F 1320 1880
Sarah F 1288 1880
Jede Zeichenfolge, die durch Drehen des Dateiobjekts als Iterator erhalten wird, hat am Ende ein Zeilenvorschubzeichen. Entfernen Sie sie daher mit "strip" ("rstrip (" \ n ")" kann vorzuziehen sein). Ersetzen Sie einfach die Tabulatoren durch Leerzeichen und geben Sie sie aus.
Es gibt auch eine Methode zum Drucken (line, end = ''), ohne das Zeilenvorschubzeichen mit 'strip' zu entfernen.
Code
awk '{gsub("\t", " ", $0); print $0}' data/popular-names.txt
perl -pe 's/\t/ /g' data/popular-names.txt
sed 's/\t/ /g' data/popular-names.txt
expand -t 1 data/popular-names.txt
tr '\t' ' ' < data/popular-names.txt
Die Ausgabe ist die gleiche wie die von Python, daher werde ich sie weglassen. (Gleiches gilt danach)
Ich kann mich nicht an viele UNIX-Befehle erinnern.
Speichern Sie nur die erste Spalte jeder Zeile als col1.txt und die zweite Spalte als col2.txt. Verwenden Sie zur Bestätigung den Befehl cut.
Code
with open('data/popular-names.txt') as f, \
open('result/col1.txt', 'w') as g, \
open('result/col2.txt', 'w') as h:
for line in f:
line = line.strip()
pref, city, _, _ = line.split('\t')
print(pref, file=g)
print(city, file=h)
Ich habe es gehorsam geschrieben.
Ergebnis(col1.Die ersten 10 Zeilen von txt)
Mary
Anna
Emma
Elizabeth
Minnie
Margaret
Ida
Alice
Bertha
Sarah
Ergebnis(col2.Die ersten 10 Zeilen von txt)
F
F
F
F
F
F
F
F
F
F
Code
cut -f 1 data/popular-names.txt > col1.txt
cut -f 2 data/popular-names.txt > col2.txt
Mit dem Befehl cut
ist das ganz einfach. Sie können auch "awk" {print $ 1} "verwenden.
Kombinieren Sie die in 12 erstellten Spalten col1.txt und col2.txt, um eine Textdatei zu erstellen, in der die erste und die zweite Spalte der Originaldatei tabulatorgetrennt angeordnet sind. Verwenden Sie zur Bestätigung den Befehl Einfügen.
Alles, was Sie tun müssen, ist, die beiden Dateien getrennt zu öffnen. Da dies jedoch eine große Sache ist, verwenden Sie contextlib.ExitStack
, um es zu implementieren, damit Sie eine beliebige Anzahl von Dateien verarbeiten können.
Für Kontextmanager → https://docs.python.org/ja/3/library/stdtypes.html#typecontextmanager
Code
from contextlib import ExitStack
Code
files = ['result/col1.txt', 'result/col2.txt']
with ExitStack() as stack:
files = [stack.enter_context(open(filename)) for filename in files]
for lines in zip(*files):
x = [line.strip() for line in lines]
x = '\t'.join(x)
print(x)
Ergebnis(Erste 10 Zeilen)
Mary F
Anna F
Emma F
Elizabeth F
Minnie F
Margaret F
Ida F
Alice F
Bertha F
Sarah F
Code
paste result/col1.txt result/col2.txt
Mit dem Befehl Einfügen ist das ganz einfach.
Empfangen Sie die natürliche Zahl N beispielsweise über ein Befehlszeilenargument und zeigen Sie nur die ersten N Zeilen der Eingabe an. Verwenden Sie zur Bestätigung den Befehl head.
Persönlich möchte ich Standardeingabe- und Befehlszeilenargumente mit "argparse" und "fileinput" erhalten, aber dieses Mal möchte ich den gesamten Code auf dem Jupyter-Notizbuch ausführen können, daher verwende ich Befehlszeilenargumente nicht. (Ich fühle Freundlichkeit zu "etc." in der Problemstellung)
Code
N = 5
with open('data/popular-names.txt') as f:
lst = range(N)
for _, line in zip(lst, f):
print(line, end='')
Ausgabe
Mary F 7065 1880
Anna F 2604 1880
Emma F 2003 1880
Elizabeth F 1939 1880
Minnie F 1746 1880
Sie können dasselbe mit dem Befehl head
tun.
Code
head -n 5 data/popular-names.txt
Empfangen Sie die natürliche Zahl N beispielsweise über ein Befehlszeilenargument und zeigen Sie nur die letzten N Zeilen der Eingabe an. Verwenden Sie zur Bestätigung den Befehl tail.
Ich denke, es ist in Ordnung, alle Standardeingaben in die Liste aufzunehmen und die letzten 5 Elemente zu extrahieren, aber wenn es sich um eine große Datei handelt, passt sie möglicherweise nicht in den Speicher, sodass ich die Warteschlange verwenden werde.
Code
from collections import deque
Code
N = 5
queue = deque([], 5)
with open('data/popular-names.txt') as f:
for line in f:
queue.append(line)
for line in queue:
print(line, end='')
Ausgabe
Benjamin M 13381 2018
Elijah M 12886 2018
Lucas M 12585 2018
Mason M 12435 2018
Logan M 12352 2018
Sie können dasselbe mit dem Befehl tail
tun.
Code
tail -n 5 data/popular-names.txt
Empfangen Sie die natürliche Zahl N mithilfe von Befehlszeilenargumenten und teilen Sie die Eingabedatei zeilenweise in N. Erzielen Sie die gleiche Verarbeitung mit dem Befehl split.
Ich denke, das liegt daran, dass es nicht viele Situationen gibt, in denen eine Datei zeilenweise in N Zeilen unterteilt wird, aber abhängig von der Implementierung des Befehls split gibt es möglicherweise keine N Unterteilungen in einer Zeile. Es kann sich um eine GNU-Erweiterung handeln.
Code(5 Abteilungen)
split -d -nl/5 data/popular-names.txt result/shell5.
Ergebnis(Überprüfen Sie die Anzahl der Zeilen mit wc)
587 2348 11007 result/shell5.00
554 2216 11010 result/shell5.01
556 2224 11006 result/shell5.02
540 2160 11007 result/shell5.03
543 2172 10996 result/shell5.04
2780 11120 55026 total
Ich habe es auch in Python implementiert, damit es sich genauso verhält wie der Code für diese GNU-Erweiterung (https://github.com/coreutils/coreutils/blob/master/src/split.c).
Code
def split_string_list(N, lst):
chunk_size = sum([len(x) for x in lst]) // N
chunk_ends = [chunk_size * (n + 1) - 1 for n in range(N)]
i = 0
acc = 0
out = []
for chunk_end in chunk_ends:
tmp = []
while acc < chunk_end:
tmp.append(lst[i])
acc += len(lst[i])
i += 1
out.append(tmp)
return out
def split_file(N, filepath, outprefix):
with open(filepath) as f:
lst = list(f)
lst = split_string_list(N, lst)
for i, lines in enumerate(lst):
idx = str(i).zfill(2) #Unterlassung
with open(outprefix + idx, 'w') as f:
f.write(''.join(lines))
split_file(5, 'data/popular-names.txt', 'result/python5.')
Zählen Sie zuerst die Gesamtzahl der Zeichen und bestimmen Sie die Schnittposition (chunk_ends
), damit die Anzahl der Zeichen so einheitlich wie möglich ist.
Dann dauert es eine Zeile, bis jedes Element von chunk_ends überschritten wird, und wenn es überschritten wird, wird es in eine Datei ausgegeben.
Ergebnis(Überprüfen Sie die Anzahl der Zeilen mit wc)
587 2348 11007 result/python5.00
554 2216 11010 result/python5.01
556 2224 11006 result/python5.02
540 2160 11007 result/python5.03
543 2172 10996 result/python5.04
2780 11120 55026 total
Ergebnis
diff result/python5.00 result/shell5.00
diff result/python5.01 result/shell5.01
diff result/python5.02 result/shell5.02
diff result/python5.03 result/shell5.03
diff result/python5.04 result/shell5.04
Ich habe das gleiche Ergebnis erzielt.
Suchen Sie den Typ der Zeichenfolge in der ersten Spalte (eine Reihe verschiedener Zeichenfolgen). Verwenden Sie zur Bestätigung die Befehle cut, sort und uniq.
Code
names = set()
with open('data/popular-names.txt') as f:
for line in f:
name = line.split('\t')[0]
names.add(name)
names = sorted(names)
for name in names:
print(name)
Ergebnis(Erste 10 Zeilen)
Abigail
Aiden
Alexander
Alexis
Alice
Amanda
Amelia
Amy
Andrew
Angela
Die erste Spalte wird der Reihe in der Reihenfolge hinzugefügt, sortiert und ausgegeben. (* Die Version von Python ist 3.8.2.)
Code
cut -f 1 data/popular-names.txt | sort -s | uniq
Nehmen Sie nur die erste Spalte und sortieren Sie, um Duplikate zu entfernen. Wenn Sie vergessen, die Sortierung einzugeben, ist dies seltsam. Zusätzlich wird die Option s hinzugefügt, um eine stabile Sortierung nach Python zu gewährleisten.
Ordnen Sie jede Zeile in umgekehrter Reihenfolge der Zahlen in der dritten Spalte an (Hinweis: Ordnen Sie den Inhalt jeder Zeile neu an, ohne ihn zu ändern). Verwenden Sie den Befehl sort zur Bestätigung (dieses Problem muss nicht mit dem Ergebnis der Ausführung des Befehls übereinstimmen).
Code
with open('data/popular-names.txt') as f:
lst = [line.strip() for line in f]
lst.sort(key = lambda x : -int(x.split('\t')[2]))
for line in lst[:10]:
print(line)
Ausgabe(Erste 10 Zeilen)
Linda F 99689 1947
Linda F 96211 1948
James M 94757 1947
Michael M 92704 1957
Robert M 91640 1947
Linda F 91016 1949
Michael M 90656 1956
Michael M 90517 1958
James M 88584 1948
Michael M 88528 1954
Durch Angabe des Schlüssels der Funktion "Sortieren" können Sie die Kriterien für das Sortieren angeben.
Code
sort -nrsk 3 data/popular-names.txt
Sie können dies nur mit dem Befehl sort
tun. Es ist einfach.
Ermitteln Sie die Häufigkeit des Auftretens der ersten Spalte jeder Zeile und zeigen Sie sie in absteigender Reihenfolge an. Verwenden Sie zur Bestätigung die Befehle cut, uniq und sort.
Verwenden Sie collection.Counter
.
Code
from collections import Counter
Code
cnt = Counter()
with open('data/popular-names.txt') as f:
for line in f:
name = line.split('\t')[0]
cnt.update([name])
lst = cnt.most_common()
lst.sort(key=lambda x:(-x[1], x[0]))
for name, num in lst[:10]:
print(name)
Ausgabe
James
William
John
Robert
Mary
Charles
Michael
Elizabeth
Joseph
Margaret
Übergeben Sie die Liste entweder unverändert an das Objekt "Counter" oder übergeben Sie sie nach und nach mit "update ()". most_common ()
ordnet sie in absteigender Reihenfolge an.
Code
cut -f 1 data/popular-names.txt | sort | uniq -c | sort -nrsk1 | awk '{print $2}'
Wenn Sie die Option "-c" hinzufügen, wenn Sie "uniq" nehmen, wird gezählt, wie viele es gibt. Zum Schluss sortieren Sie nach Zahlen, um das gewünschte Ergebnis zu erhalten.
Sprachverarbeitung 100 Schläge 2020 Kapitel 3: Reguläre Ausdrücke
Recommended Posts