Knock 100-Sprachverarbeitung, veröffentlicht auf der Webseite des Inui-Okazaki-Labors der Tohoku-Universität zum Training der Verarbeitung natürlicher Sprache und von Python. Ich werde nlp100 /) herausfordern. Ich habe vor, den darin implementierten Code und die Techniken, die unterdrückt werden sollten, zu notieren. Der Code wird auch auf GitHub veröffentlicht.
Dies ist eine Fortsetzung von Kapitel 1.
Nur hier denke ich, wäre es gut, eine kleine Erklärung der UNIX-Befehle sowie von Python einzufügen.
Detaillierte Optionen für UNIX-Befehle finden Sie im Befehl man
oder auf der ITpro-Website. Sie werden es richtig lernen!
hightemp.txt ist eine Datei, in der die Aufzeichnung der höchsten Temperatur in Japan im tabulatorgetrennten Format "Präfektur", "Punkt", "℃" und "Tag" gespeichert wird. Erstellen Sie ein Programm, das die folgende Verarbeitung ausführt, und führen Sie hightemp.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.
Zählen Sie die Anzahl der Zeilen. Verwenden Sie zur Bestätigung den Befehl wc.
10.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 10.py
import sys
f = open(sys.argv[1])
lines = f.readlines()
print(len(lines))
f.close()
Da in der Problemstellung "hightemp.txt als Eingabedatei" steht, habe ich sie so entworfen, dass sie Befehlszeilenargumente mit sys.argv
annehmen kann.
Zum Zeitpunkt der Ausführung ist es auf "$ python 10.py high temp.txt" gesetzt, also in diesem Fall "sys.argv [0] ==" 10.py "," sys.argv [1] == "hightemp.txt" Dies bedeutet, dass die Zeichenfolge gespeichert ist.
In Bezug auf das Lesen von Dateien
f = open (Dateiname)
hoge = f.read() / f.readline() / f.readlines()
f.close()
Ich werde mit dem Fluss gehen. Die drei Arten von Funktionen, die in 2 \ angezeigt werden, verhalten sich wie folgt. Bitte bei Bedarf richtig verwenden.
read()
readline()
readlines()
len ()
) ermittelte.with
Zum Lesen (Schreiben) einer Datei gibt es eine Schreibmethode, die zusätzlich zu der oben beschriebenen Schreibmethode "close ()" "with" verwendet. Es scheint, dass dies empfohlen wird, um zu verhindern, dass vergessen wird, "close ()" hinzuzufügen, und um zu vergessen, Ausnahmen zu behandeln, die bei der Verwendung von "with" häufig vorkommen.
Das folgende Programm ist eine Testumschreibung von 10.py
using with
.
Bei Verwendung der with-Syntax
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 10.py
import sys
with open(sys.argv[1]) as f:
lines = f.readlines()
print(len(lines))
Verwenden Sie danach im Prinzip "with", um Dateien zu lesen und zu schreiben. Nur wenn Sie nicht mit with
schreiben können (gibt es das?), Programmieren Sie auf die alte Art und Weise.
$ wc -l hightemp.txt
24 hightemp.txt
Der Befehl wc
zeigt die Anzahl der Zeilen, Wörter und Bytes in der Datei an.
Wenn keine Option angegeben ist, wird sie in der folgenden Reihenfolge ausgegeben.
$ wc hightemp.txt
24 98 813 hightemp.txt
Die Optionen sind "-l" für die Anzahl der Zeilen, "-w" für die Anzahl der Wörter und "-c" für die Anzahl der Bytes.
Ersetzen Sie jede Registerkarte durch ein Leerzeichen. Verwenden Sie zur Bestätigung den Befehl sed, den Befehl tr oder den Befehl expand.
11.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 11.py
import sys
with open(sys.argv[1]) as f:
str = f.read()
print(str.replace("\t", " "))
Im Gegensatz zu der vorherigen, die sich auf Zeilen konzentrierte, möchte ich dieses Mal nur Zeichen auf einmal ersetzen, also verwende ich einfach "read ()".
Die im vorherigen Kapitel beschriebene Funktion replace ()
ersetzt das Tabulatorzeichen (\ t
) durch ein Leerzeichen.
~~ Ich mag die zusätzlichen Zeilenumbrüche am Ende des Ausgabeergebnisses nicht, aber das ist ziemlich süß ...? ~~
Standardmäßig hat print ()
am Ende einen Zeilenumbruch. Um dies zu vermeiden, können Sie in Python 2 am Ende ein Komma hinzufügen, z. B. "print" hogehoge ",". In Python 3 können Sie das Zeichen angeben, das am Ende mit end
hinzugefügt werden soll, z. B. print (" hogehoge ", end =" ")
, sodass Sie""
angeben können.
//sed version (Beachten Sie, dass dies von der Umgebung abhängt)
$ sed -e s/$'\t'/" "/g hightemp.txt
// tr version
$ cat hightemp.txt | tr "\t" " "
// expand version
$ expand -t 1 hightemp.txt
//Das Ergebnis ist das gleiche
Präfektur Kochi Egawasaki 41 2013-08-12
40 Kumagai, Präfektur Saitama.9 2007-08-16
40 Tajimi, Präfektur Gifu.9 2007-08-16
(Weggelassen...)
Otsuki, Yamanashi 39.9 1990-07-19
39 Tsuruoka, Präfektur Yamagata.9 1978-08-03
Präfektur Aichi Nagoya 39.9 1942-08-02
sed
ist ein praktischer Befehl, der verschiedene Zeichen bearbeiten kann. Für begrenzte Zwecke (Zeichenersetzung) wie dieses Mal ist es jedoch ratsam, den Befehl ( tr
) für diesen Zweck zu verwenden.
Im Gegenteil, "Erweitern" hat zu begrenzte Verwendungsmöglichkeiten, sodass Sie möglicherweise keine Chance haben, es zu berühren.
sed
-e
angeben und die Verarbeitung beschreiben, die Sie danach ausführen möchten, wird das Ergebnis in die Standardausgabe ausgegeben. Die Notation ist zwar eindeutig, den Vim-Benutzern jedoch möglicherweise bekannt.tr
expand
-t
angegeben werden.Speichern Sie die extrahierte Spalte jeder Zeile als col1.txt und die extrahierte Spalte 2 als col2.txt. Verwenden Sie zur Bestätigung den Befehl cut.
12.py
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# 12.py
import sys
def write_col(source_lines, colunm_number, filename):
col = []
for line in source_lines:
col.append(line.split()[colunm_number] + "\n")
with open(filename, "w") as writer:
writer.writelines(col)
with open(sys.argv[1]) as f:
lines = f.readlines()
write_col(lines, 0, "col1.txt")
write_col(lines, 1, "col2.txt")
Ich habe es zu einer Funktion gemacht, weil es eine ähnliche Verarbeitung ausführt. Schreibt die im 2. Argument der im 1. Argument empfangene Liste angegebene Zeile als Dateinamen des 3. Arguments. Wenn Sie "append ()" ausführen, wird ein Zeilenvorschubzeichen hinzugefügt, um das Erscheinungsbild zu verbessern.
Ich benutze keine neue Technologie, daher kann ich so viel kommentieren, aber es ist mir peinlich, dass die Algorithmen je nach Programm unterschiedlich sind ... Details werden später beschrieben, aber es wird so veröffentlicht, wie es zur Reflexion ist.
$ cut -f 1 hightemp.txt
Präfektur Kochi
Saitama
Präfektur Gifu
(Weggelassen...)
Präfektur Yamanashi
Präfektur Yamagata
Präfektur Aichi
$ cut -f 2 hightemp.txt
Egawazaki
Kumagai
Tajimi
(Weggelassen...)
Otsuki
Tsuruoka
Nagoya
Wie bei Python geben wir Felder (Zeilen) mit -f
an. Beachten Sie, dass es in Python auf Null basiert (Zeile 0, Zeile 1 ...), während es in UNIX-Befehlen auf Eins basiert (Zeile 1, Zeile 2 ...).
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.
13.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 13.py
with open("col1.txt") as f1, open("col2.txt") as f2:
lines1, lines2 = f1.readlines(), f2.readlines()
with open("merge.txt", "w") as writer:
for col1, col2 in zip(lines1, lines2):
writer.write("\t".join([col1.rstrip(), col2]))
Ich gewöhne mich an Python und habe die erste Hälfte des Leseteils mit ein wenig Vertrautheit geschrieben. Es ist stark, so schreiben zu können.
Für den Schreibteil in der zweiten Hälfte habe ich versucht, mit zip ()
als Rezension von Kapitel 1 zu schreiben. Im Gegensatz zu 12. bleiben diesmal beide Zeilenvorschubzeichen am Ende von "col1, col2", sodass das Zeilenvorschubzeichen am Ende von "col1" durch "rstrip ()" entfernt wird.
Hier ist eine Überprüfung und in der Einschlussnotation umgeschrieben.
Bei Umschreibung durch Einschlussnotation
#Wenn es in Klammern steht, wird es auch dann richtig interpretiert, wenn im Code ein Zeilenumbruch auftritt
with open("merge.txt", "w") as writer:
writer.write(
"\n".join(
["\t".join([col1.rstrip(), col2.rstrip()])
for col1, col2 in zip(lines1, lines2)]
)
)
Da verschiedene Notationen herauskamen, habe ich die Ausführungszeit jeder Methode mit "timeit" gemessen und verglichen.
Ausführungszeitmessprogramm mit timeit
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 13_timeit.py
import timeit
#Vorverarbeitung; col1,col2.Lesen Sie txt
s0 = """
with open("col1.txt") as f1, open("col2.txt") as f2:
lines1, lines2 = f1.readlines(), f2.readlines()
"""
#naive Umsetzung;Fügen Sie Zeichenfolgen hinzu
s1 = """
merged_txt = ""
for i in xrange(len(lines1)):
merged_txt = merged_txt + lines1[i].rstrip() + "\t" + lines2[i]
with open("merge.txt", "w") as writer:
writer.write(merged_txt)
"""
#Implementierung mit zip
s2 = """
with open("merge.txt", "w") as writer:
for col1, col2 in zip(lines1, lines2):
writer.write("\t".join([col1.rstrip(), col2]))
"""
#Einschlussnotation(connotation)Implementierung durch
# "\\n"Wenn Sie nicht schreiben, erhalten Sie SyntaxError ... warum?
s3 = """
with open("merge.txt", "w") as writer:
writer.write(
"\\n".join(
["\t".join([col1.rstrip(), col2.rstrip()])
for col1, col2 in zip(lines1, lines2)]
)
)
"""
print("naive:", timeit.repeat(stmt=s1, setup=s0, number=100000))
print("zip:", timeit.repeat(stmt=s2, setup=s0, number=100000))
print("connotation:", timeit.repeat(stmt=s3, setup=s0, number=100000))
Dies ist die Berechnungszeit (Sekunden), wenn 100.000 Runden der Schleife dreimal (Standard) mit drei Arten von Methoden ausgeführt werden. Gemäß dem offiziellen Dokument sollte die Ausführungszeit anhand des Minimalwerts bewertet werden, nicht anhand des Durchschnitts- oder Maximalwerts.
Ausführungsergebnis
$ python 13_timeit.py
('naive:', [32.61601686477661, 47.96871089935303, 33.15881299972534])
('zip:', [49.846755027770996, 45.05450105667114, 58.70397615432739])
('connotation:', [46.472286224365234, 52.708040952682495, 46.71139121055603])
Infolgedessen war die Methode zum einfachen Hinzufügen von Zeichenfolgen allein in Bezug auf die Ausführungszeit die beste. Auch wenn die Reihenfolge geändert wird. Im Allgemeinen scheint eine Beschleunigung mit der Einschlussnotation zu erwarten zu sein, aber was ist die Grenze zwischen Beschleunigung und Nicht-Beschleunigung?
$ paste col1.txt col2.txt
Präfektur Kochi Egawazaki
Kumagai, Präfektur Saitama
Tajimi, Präfektur Gifu
(Weggelassen...)
Präfektur Yamanashi Otsuki
Tsuruoka, Präfektur Yamagata
Präfektur Aichi Nagoya
Der Befehl "Einfügen" verkettet Dateien horizontal.
Tab ist das Standardtrennzeichen, kann jedoch mit der Option -d
angegeben werden.
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.
14.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 14.py
# Usage: python 14.py [filename] [number of lines]
import sys
with open(sys.argv[1]) as f:
lines = f.readlines()
for line in lines[:int(sys.argv[2])]:
print line,
Zuerst habe ich die folgende Implementierung mit xrange ()
verwendet, aber
xrange()Implementierung mit
#Unterlassung
for i in xrange(int(sys.argv[2])):
print lines[i],
Wenn Sie dies tun, erhalten Sie einen "IndexError", wenn Sie eine Zahl angeben, die die Anzahl der Zeilen in der Datei überschreitet. Daher halte ich es für ratsam, Slices zu implementieren. Ich denke, das Problem ist, dass der Eingabewert nicht überprüft wird und die Fehlerbehandlung überhaupt nicht geschrieben wird ... In Bezug auf die Ausgabe haben wir, wie in 11. erläutert, am Ende der Anweisung "print" "," hinzugefügt, um unnötige Zeilenumbrüche zu entfernen.
$ head -3 hightemp.txt
Präfektur Kochi Egawasaki 41 2013-08-12
40 Kumagai, Präfektur Saitama.9 2007-08-16
40 Tajimi, Präfektur Gifu.9 2007-08-16
Dies ist auch einfach. Sie können optional die Anzahl der Zeilen angeben.
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.
15.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 15.py
import sys
with open(sys.argv[1]) as f:
lines = f.readlines()
for line in lines[len(lines) - int(sys.argv[2]):]:
print line,
Es ist fast das gleiche wie die vorherigen 14. Obwohl die Slice-Spezifikation etwas kompliziert ist.
$ tail -3 hightemp.txt
Otsuki, Yamanashi 39.9 1990-07-19
39 Tsuruoka, Präfektur Yamagata.9 1978-08-03
Präfektur Aichi Nagoya 39.9 1942-08-02
Fast das gleiche wie "Kopf".
Da es lang geworden ist, habe ich den Artikel über Kapitel 2 geteilt. Fahren Sie mit Kapitel 2, Teil 2 fort.
Recommended Posts