[Kapitel 2] Einführung in Python mit 100 Klopfen Sprachverarbeitung

Dieser Artikel ist eine Fortsetzung meines Buches Einführung in Python mit 100 Language Processing Knock. Für diejenigen, die die Grundlagen von Python (und Unix-Befehlen) während der Arbeit an 100 Knock Chapter 2 erlernen möchten.

Wenn Sie Nummer 12 erreichen können, sind die Grundlagen von Python fast in Ordnung.

Danach werden Sie wahrscheinlich das Gefühl haben, sich ein wenig detailliertes Wissen anzueignen. Laden Sie zunächst die in der Problembeschreibung angegebene Datei mit einer geeigneten Methode herunter.

$ wget https://nlp100.github.io/data/popular-names.txt

Ergänzung zur Problemstellung

In der Verarbeitung natürlicher Sprache gibt es viele Situationen, in denen Sie eine große Textdatei Zeile für Zeile verarbeiten möchten, ebenso wie das Problem in diesem Kapitel.

TSV (Tab-Separated Values) und CSV (Comma-Separated Values) werden häufig verwendet, um eine Struktur auszudrücken, in der eine Zeile aus Daten besteht und Spalten in Elemente unterteilt sind. Die in diesem Kapitel behandelten Dateien sind durch Tabulatoren getrennt, es handelt sich also um TSV.

(Obwohl es verwirrend ist, werden diese Formate manchmal gemeinsam als CSV (Character-Separated Values) bezeichnet.)

Beantworten Sie die Beispielrichtlinie

Die Probleme in diesem Kapitel verwenden pandas und die Standardbibliothek csv. Sie können es lösen, aber ich habe nicht so viel Bedürfnis, deshalb werde ich die einfachste Methode erklären. Der Codierungsstil des Antwortbeispiels folgt übrigens PEP8. Zum Beispiel sollte der Variablenname / Funktionsname "snake_case" sein und der Einzug sollte 4 Leerzeichen halber Breite sein.

Informationen zu Unix-Befehlen

Wenn Sie mit Optionen, Pipes, Weiterleitungen und "weniger" nicht vertraut sind, lesen Sie bitte die Verse 1 und 3 von Qiita-Artikel hier. Überprüfen Sie dann den Inhalt der heruntergeladenen Datei mit "$ less popular-names.txt".

Der Befehlsname wird in der Problemanweisung angegeben, sodass Sie ihn verwenden können, indem Sie "--help" vollständig verwenden, ohne es zu wissen. Die meisten Unix-Befehle in diesem Kapitel sind jedoch häufig. Denken Sie also daran, wenn Sie können.

Datei lesen

In C haben wir Dateizeiger verwendet, aber in Python verwenden wir einen praktischen Datentyp namens Dateiobjekte. Dateiobjekte sind iterierbar. Wenn Sie also eine Textdatei Zeile für Zeile lesen möchten, schreiben Sie:

with open('popular-names.txt') as f:
    for line in f:
        print(line, end='')

Die with-Syntax ist eine großartige Möglichkeit, beim Verlassen eines Blocks "f = open (" popular-names.txt ")" und "f.close ()" auszuführen. In der offiziellen Dokumentation heißt es auch, dass es sich um eine ** gute Praxis ** handelt. Verwenden Sie sie daher unbedingt.

In jeder Schleife der for-Anweisung wird der Inhalt jeder Zeile "line" zugewiesen.

Um mehrere Dateien gleichzeitig zu verwenden, verwenden Sie Kommas wie "mit open ('test1') als f1, open ('test2') als f2".

Verwenden Sie sys.stdin, wenn Sie die Standardeingabe Zeile für Zeile lesen möchten. Dies ist auch ein Dateiobjekt. Alle Probleme in diesem Kapitel können auf die oben beschriebene Weise gelöst werden, es ist jedoch etwas bequemer, Standardeingaben zu verwenden.

import sys

for line in sys.stdin:
    print(line, end='')
    

(Da die Standardeingabe von Anfang an "open ()" ist, denken Sie bitte, dass "with" nicht erforderlich ist.)

(Einige Unix-Befehle akzeptieren Standardeingabe- und Dateinamen, dies ist jedoch mit Python → Referenzartikel etwas mühsam. 010e7e3410ea4e1486cb)))

10. Zählen der Anzahl der Zeilen

Zählen Sie die Anzahl der Zeilen. Verwenden Sie zur Bestätigung den Befehl wc.

Speichern Sie das Python-Skript, nehmen Sie popular-names.txt von der Standardeingabe und führen Sie es aus.

Unten finden Sie ein Beispiel für die Antwort.

q10.py


import sys

i = 0
for line in sys.stdin:
    i += 1
print(i)

$ python q10.py < popular-names.txt
2780

Sie können C i ++ in Python nicht verwenden, verwenden Sie also den kumulativen Zuweisungsoperator + =.

(Vermeiden Sie f.read (). Splitlines (), f.readlines (), list (f), wenn die Dateigröße groß ist oder wenn Sie eine komplizierte Verarbeitung durchführen möchten.)

Ich werde auch auf eine etwas elegante Methode eingehen. Es nutzt die Tatsache aus, dass sys.stdin iterierbar ist und dass der Python for-Block keinen Bereich bildet.

import sys


i = 0
for i, _ in enumerate(sys.stdin, start=1):
    pass

print(i)

Die eingebaute Funktion enumerate (), die die Anzahl der Schleifen zählt, ist nützlich. Es ist eine Python-Konvention, nicht verwendete Rückgabewerte mit _ zu empfangen. Die pass-Anweisung wird verwendet, wenn Sie nichts tun möchten, sondern etwas grammatikalisch schreiben müssen.

Verwenden Sie zur Bestätigung den Befehl wc (* Wortanzahl *). Wenn Sie es normal verwenden, wird es auf verschiedene Arten angezeigt. Geben Sie daher die Optionen "-l, --lines" an.

$ wc -l popular-names.txt
2780 popular-names.txt

11. Ersetzen Sie die Registerkarten durch Leerzeichen

Ersetzen Sie jede Registerkarte durch ein Leerzeichen. Verwenden Sie zur Bestätigung den Befehl sed, den Befehl tr oder den Befehl expand.

Verwenden wir "str.replace (alt, neu)". Diese Methode ersetzt die Teilzeichenfolge "alt" in der Zeichenfolge durch "neu" und gibt sie zurück. Das Tabulatorzeichen ist "\ t" wie in C.

Unten finden Sie ein Beispiel für die Antwort.

q11.py


import sys


for line in sys.stdin:
    print(line.replace('\t', ' '), end='')

Da es viele Zeilen gibt, überprüfen Sie das Ergebnis mit python q11.py <popular-names.txt | less usw.

Es sind drei Unix-Befehle aufgelistet, aber sed -es / \ t / / g'popular-names.txt ist am beliebtesten. Auf Twitter sehe ich manchmal Leute, die ihre Tippfehler auf diese Weise mit Rissen korrigieren. sed steht für Stream EDitor und ist ein vielseitiger Befehl.

Persönlich ist der Teil "s / \ t / / g" problematisch, daher frage ich mich, ob ich "tr" \ t "" <popular-names.txt "verwende ...

Sed ist jedoch ein Befehl, den Sie kennen sollten, und Sie können sed -n 10p verwenden, um die 10. Zeile zu extrahieren, sed -n 10, 20p, um die 10. bis 20. Zeile zu extrahieren und so weiter. Praktisch.

Datei schreiben

In der nächsten Frage erfahren Sie, wie Sie Dateien schreiben. Verwenden Sie open (Dateiname, 'w), um eine Textdatei im Schreibmodus zu öffnen.

with open('test', 'w') as fo:
    # fo.write('hoge')
    print('hoge', file=fo)

Sie können beim Schreiben die Methode "write ()" verwenden, aber es ist etwas unpraktisch, das Hinzufügen eines Zeilenumbruchs zu vergessen. Ich denke, es ist besser, das optionale Argument "file" von "print ()" zu verwenden.

12. Speichern Sie die erste Spalte in col1.txt und die zweite Spalte in col2.txt

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.

Unten finden Sie ein Beispiel für die Antwort.

q12.py


import sys


with open('col1.txt', 'w') as fo1,\
     open('col2.txt', 'w') as fo2:
    for line in sys.stdin:
        cols = line.rstrip('\n').split('\t')
        print(cols[0], file=fo1)
        print(cols[1], file=fo2)

Es wäre schön gewesen, die beiden open () zusammen in eine Zeile zu schreiben, aber mit dem Backslash\wird davon ausgegangen, dass die Anweisung auch dann fortgesetzt wird, wenn die Zeile unterbrochen wird.

Sie können "open ()" verwenden, um "popular-names.txt" zu lesen, aber ich möchte nicht, dass die "with" -Anweisung länger ist, daher verwende ich die Standardeingabemethode.

Der Teil von line.rstrip ('\ n'). Split ('\ t') wird als Methodenkette bezeichnet, und die Methoden werden in der Reihenfolge von links ausgeführt. In diesem Problem ändert sich das Ergebnis nicht ohne "rstrip ()", sondern soll verhindern, dass "cols [-1]" das Zeilenvorschubzeichen enthält. Es ist ein üblicher Vorgang beim Lesen von Text.

Unix-Befehle sind in Ordnung, wenn Sie die Optionen -f, --fields in cut angeben. Sie können den Befehl zweimal ausführen, aber Sie können ihn sofort mit && ausführen.

!cut -f1 popular-names.txt > col1.txt && cut -f2 popular-names.txt > col2.txt

13. Führen Sie col1.txt und col2.txt zusammen

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.

Das ist einfach, nicht wahr? Unten finden Sie ein Beispiel für die Antwort.

q13.py


with open('col1.txt') as fi1,\
     open('col2.txt') as fi2:
    for col1, col2 in zip(fi1, fi2):
        col1 = col1.rstrip()
        col2 = col2.rstrip()
        print(f'{col1}\t{col2}')

Writing q13.py

Hier kommt die eingebaute Funktion zip () ins Spiel. rstrip () entfernt alle Zeilenumbrüche und Leerzeichen, wenn das Argument weggelassen wird.

(Da es 3 oder mehr Eingabedateien gibt, ist es besser, den Rückgabewert von "zip ()" als eine Variable und "join ()" zu erhalten. Außerdem ist das Verhalten näher am Befehl "Einfügen". Es ist schwer zu versuchen. Bitte lesen Sie diesen Artikel.)

Der Unix-Befehl ist mit paste col1.txt col2.txt in Ordnung.

14. Geben Sie N Zeilen von Anfang an aus

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.

Befehlszeilenargumente können mit sys.argv abgerufen werden, die Verwendung von argparse ist jedoch etwas bequemer. Informationen zur Verwendung finden Sie im Official Great Tutorial von Anfang an bis zu den "Short Options" ...

Slices können nicht verwendet werden, da Dateiobjekte keinen Sequenztyp sind. Zählen wir die Anzahl der Zeilen auf andere Weise.

Unten finden Sie ein Beispiel für die Antwort.

q14.py


import argparse
import sys


def arg_lines():
    parser = argparse.ArgumentParser()
    parser.add_argument('-n', '--lines', default=1, type=int)
    args = parser.parse_args()
    return args.lines


def head(N):
    for i, line in enumerate(sys.stdin):
        if i < N:
            print(line, end='')
        else:
            break


if __name__ == '__main__':
    head(arg_lines())
$ python q14.py -n 10 < popular-names.txt

Der "argparse" -Teil wird unabhängig in eine Funktion umgewandelt, damit er im nächsten Problem wiederverwendet werden kann. if __name__ == '__ main __': verhindert, dass der Hauptprozess zum Zeitpunkt des Imports willkürlich ausgeführt wird.

(Laut, es ist nicht gut, einen langen Prozess unter if __name__ == '__ main __' zu schreiben: weil alle Variablen global sind. Python hat langsamen Zugriff auf globale Variablen, daher ist die Leistung schlecht. Es gibt auch einen Nachteil, dass es ausfällt. Tatsächlich wird es etwas schneller, wenn der Code, der solide geschrieben wurde, erstellt wird, ohne ihn zu einer Funktion zu machen.)

break ist eine Steueranweisung, die im for-Block verwendet wird und die for-Anweisung sofort beendet. Denken Sie daran, mit "Weiter" (sofort zur nächsten Schleife übergehen).

Die Funktion head () kann etwas eleganter geschrieben werden.

import sys
from itertools import islice

def head(N):
    for line in islice(sys.stdin, N):
        print(line, end='')

Unix-Befehle können head -n 5 popular-names.txt usw. sein. Wenn Sie die Option weglassen, wird sie mit dem Standardwert (wahrscheinlich 10) ausgeführt.

Zum Zeitpunkt der Erklärung von Nr. 11 schrieb ich, dass die Anzahl der Zeilen lang ist. Geben Sie sie daher bitte mit einer Pipe an "less" weiter. Wenn Sie jedoch nur die erste überprüfen möchten, war "head" ausreichend.

Wenn Sie diese Befehle an eine Pipe übergeben, wird am Ende ein "Broken Pipe Error" angezeigt. Wenn Sie dies verhindern wollenhead popular-names.txt | python q11.pyWie zuerstheadOder,python q11.py < popular-names.txt 2>/dev/null | headVerwerfen wir die Fehlerausgabe wie folgt.

15. Geben Sie die letzten N Zeilen aus

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.

Python-Dateiobjekte (Rückgabewerte von sys.stdin und open ()) können den Dateizeiger nur von Anfang an (im Prinzip) vorrücken. Es ist verschwenderisch, die Anzahl der Zeilen einmal zu zählen und die Datei dann erneut zu öffnen. Es ist eine Verschwendung von Speicher, "readlines ()" zu machen und den Rücken zu schneiden ...

Sie können dies intelligent tun, wenn Sie die First-In- und Last-Out-Datenstruktur mit dem Namen * queue * kennen. Mit anderen Worten, Sie können den Inhalt der Datei Zeile für Zeile in eine Warteschlange der Länge N stellen. Dann werden die Elemente, die sich über die Länge der Warteschlange hinaus erstrecken, ohne Erlaubnis ausgegeben, sodass am Ende nur die letzten N Zeilen in der Warteschlange verbleiben.

Verwenden Sie die deque im Modul Sammlungen, um Warteschlangen in Python zu implementieren. Oder besser gesagt, die offizielle Dokumentation enthält ein Beispiel für "tail ()" im "Deque-Rezept", was fast die Antwort auf diese Frage ist.

Unten finden Sie ein Beispiel für die Antwort.

q15.py


from collections import deque
import sys

from q14 import arg_lines


def tail(N):
    buf = deque(sys.stdin, N)
    print(''.join(buf))


if __name__ == '__main__':
    tail(arg_lines())

Die "Deque" kann sowohl mit der "for" -Anweisung als auch mit der Liste gedreht werden. Bisher wurde die Liste mit einer "for" -Anweisung in "print ()" umgewandelt, aber es ist schneller, "join ()" und "print ()" gleichzeitig zu verbinden ([Reference](https: //). qiita.com/hi-asano/items/aa2976466739f280b887#%E3%81%8A%E3%81%BE%E3%81%91-%E5%95%8F%E9%A1%8C3-print)). Für Nummer 14 war "print (". Join (islice (sys.stdin, N)), end = ") ausreichend.

Unix-Befehle sind mit tail -n 5 in Ordnung.

Unten wird sich der Schwierigkeitsgrad etwas erhöhen, aber ich möchte, dass Sie es verstehen.

Iterable und Iterator

Im vorherigen Artikel habe ich erklärt, dass "das, was mit einer for-Anweisung gedreht werden kann, als iterabel bezeichnet wird". Hier können die bisher aufgetretenen iterierbaren Datentypen (+ α) wie folgt klassifiziert werden. Es ist nicht erforderlich, sich die Details zu merken, aber es kann einfacher sein zu sehen, wie sie aussehen, wenn Sie in Zukunft auf neue Datentypen stoßen.

Lassen Sie uns nun über ** Iterator ** sprechen (mit dem wir früher geschummelt und umgegangen sind). Datentypen wie Listen sind umständlich, wenn sie groß sind, da alle Elemente gleichzeitig im Speicher gespeichert werden. Es gibt auch viel Verschwendung, wenn Sie nicht "len ()" oder index verwenden müssen und es nur mit Argumenten wie "for" -Anweisung oder "str.join ()" verwenden müssen. Es ist Zeitverschwendung, die späteren Elemente zu generieren, insbesondere wenn Sie nicht zum letzten Element schleifen müssen. Iteratoren haben solche Nachteile beseitigt. Da der Iterator nur ein Element in einer Schleife zurückgibt, hat er den Vorteil, dass er effizient mit Speicher umgehen kann. Sie können keine Slices verwenden, aber Sie können so etwas mit itertools.islice () tun. Sobald die Schleife vollständig gedreht ist, kann nichts mehr getan werden. Aufgrund dieser Einschränkungen wird es ausschließlich in for-Anweisungen und -Funktionen verwendet, die iterables als Argumente verwenden.

Datentypen, die nicht nur for-Anweisungen, sondern auch in-Operationen und len () unterstützen, werden als Sammlungen oder Container bezeichnet (obwohl sie in der offiziellen Dokumentation als Container bezeichnet werden, abstrakte Basisklasse Per Definition sind Sammlungen strenger).

Indizes und Slices können für alle Sequenztypen verwendet werden.

Zusätzlich zu "deque" definiert das Modul "collection" nützliche Datentypen wie "Counter" und "defaultdict". Beachten Sie dies ebenfalls. Kann in zukünftigen Ausgaben verwendet werden.

Listeneinschlussnotation und Generatorausdruck

Es gibt Zeiten, in denen Sie eine Operation für alle Elemente eines iterierbaren Objekts einzeln ausführen möchten oder wenn Sie nur die Elemente extrahieren möchten, die die Bedingungen erfüllen. Einschlussnotation und Generatorausdrücke können eine solche Verarbeitung auf prägnante Weise beschreiben. Nehmen wir das Beispiel von 100 Klopfen 03 "Umfangsverhältnis".

tokens = 'Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.'.split()

#Listeneinschlussnotation
stripped_list = [len(token.rstrip('.,')) for token in tokens]
print(stripped_list)
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

Zunächst aus der Liste Einschlussnotation. Früher war es "append ()" in der "for" -Anweisung, aber in der Listeneinschlussnotation schreiben Sie zuerst, was Sie "append ()" möchten, und fügen Sie danach die "for" -Anweisung mit "[]" hinzu. Umschließen. Es mag etwas schwierig sein, damit klarzukommen, aber diese Art des Schreibens funktioniert schneller (Referenz. A1% 8C1-% E3% 83% AA% E3% 82% B9% E3% 83% 88% E7% 94% 9F% E6% 88% 90)) Verwenden Sie es positiv.

Als nächstes kommt die Generatorformel. Der Rückgabewert des Generatortyps wird als Generatortyp bezeichnet und ist eine Art Iterator. Der Iterator kann nur verwendet werden, indem er erneut mit der Anweisung "for" gedreht oder an eine andere Funktion übergeben wird. Wenn überhaupt, ist letzteres die häufigere Verwendung.

#Generatortyp
stripped_iter = (len(token.rstrip('.,')) for token in tokens)

for token in stripped_iter:
    print(token, end=' ')
3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 
' '.join(str(len(token.rstrip('.,'))) for token in tokens)
'3 1 4 1 5 9 2 6 5 3 5 8 9 7 9'

Wie Sie sehen können, hat der Generatorausdruck gerade die Listeneinschlussnotation "[]" in "()" geändert. Das () kann jedoch weggelassen werden, wenn es an das Argument der Funktion übergeben wird.

Das Übergeben eines Generatorausdrucks an eine Funktion hat den Vorteil, dass Zwischenvariablen reduziert werden. Im Vergleich zum Übergeben einer Liste (einschließlich Notation) kann die Speichernutzung reduziert werden, und Generatorausdrücke sind häufig schneller.

(In seltenen Fällen gibt es Funktionen, mit denen eine Liste schneller übergeben werden kann, und dieses join () scheint eine der Ausnahmen zu sein ...)

Generatorfunktion

Das Problem mit Generatorausdrücken besteht darin, dass sie schwer zu schreiben sind, wenn Sie eine komplizierte Verarbeitung durchführen möchten. Daher möchten Sie möglicherweise eine Funktion definieren, die einen Iterator zurückgibt. Am einfachsten ist es, die Anweisung "ield "zu verwenden, und die auf diese Weise definierte Anweisung wird als Generatorfunktion bezeichnet. Natürlich ist das von der Generatorfunktion erzeugte Objekt auch ein Generatortyp.

Um eine Generatorfunktion zu definieren, platzieren Sie den "Yield Return Value" "in der Mitte" (oder am Ende) des Funktionsbetriebs. Der große Unterschied besteht darin, dass "return" die Verarbeitung der Funktion dort beendet und die lokalen Variablen in der Funktion verschwinden.

def tokens2lengths(tokens):
    for token in tokens:
        yield len(token.rstrip('.,'))

for token in tokens2lengths(tokens):
    print(token, end=' ')
3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 

Wofür bist du dankbar? Das könnte der Fall sein ... Sie werden die Generatorfunktion in diesen beiden Kapiteln nicht verwenden ... Es wird gesagt, dass die Beschreibung von rekursiven Funktionen einfacher sein wird, aber die rekursiven Funktionen selbst sind nicht viel geschrieben ... Persönlich benutze ich es in den folgenden Fällen. Angenommen, Sie haben Ihre eigene Funktion "Prozess".

for elem in lis:
    if elem is not None:
        outstr = process(elem)
        print(outstr)

Dieser Code macht die Funktionsaufrufzeit nicht zum Narren, da die Anzahl der Elemente in lis zunimmt. Wenn ein Prozess in eine Generatorfunktion umgewandelt wird, ist er daher etwas schneller. Sie können auch den bedingten Ausdruck aufnehmen, und die Hauptfunktion wird aktualisiert.

for outstr in iter_process(lis):
    print(outstr)

Die Geschichte, die nicht die Hauptgeschichte ist, ist lang geworden. Lassen Sie uns das folgende Problem lösen.

Sehr detaillierte Laufzeitschwankung

Die Dokumentation besagt, dass sich ein Generator normalerweise auf eine Generatorfunktion bezieht und das von der Generatorfunktion erzeugte Objekt als Generatoriterator bezeichnet wird. Wenn Sie jedoch die Funktion type () verwenden, um den Rückgabetyp der Generatorfunktion (und des Generatorausdrucks) zu überprüfen, wird Generator angezeigt. Aus diesem Grund habe ich das Gefühl, dass der offizielle Generator-Iterator in inoffiziellen Dokumenten häufig als Generator bezeichnet wird.

16. Teilen Sie die Datei in N.

Empfangen Sie die natürliche Zahl N beispielsweise über Befehlszeilenargumente und teilen Sie die Eingabedatei zeilenweise in N. Erzielen Sie die gleiche Verarbeitung mit dem Befehl split.

Es ist ein schwieriges Problem. Es gibt verschiedene mögliche Methoden, aber es scheint, dass die einzige Möglichkeit, die Einschränkung zu überwinden, den Inhalt der Datei nicht sofort im Speicher abzulegen, darin besteht, zuerst die Gesamtzahl der Zeilen zu zählen und sie dann zu teilen. Sie können die Datei erneut öffnen oder f.seek (0) (dh auf die ersten 0 Bytes verweisen) verwenden, um den Referenzpunkt des Dateiobjekts an den Anfang zurückzusetzen.

Und ** N-Aufteilung, um so gleichmäßig wie möglich zu sein, ist ärgerlich. Wenn Sie beispielsweise 14 Zeilen in 4 Zeilen unterteilen möchten, möchten Sie sie in "4 Zeilen, 4 Zeilen, 3 Zeilen, 3 Zeilen" unterteilen. Lass uns darüber nachdenken.

Wenn Sie das können, lesen und schreiben Sie einfach 4 Zeilen. Es gibt eine Methode namens "fi.readline ()", die nur eine Zeile liest, aber das könnte die Wende sein. Sie sollten wahrscheinlich in eine separate Datei schreiben.

Unten finden Sie ein Beispiel für die Antwort.

q16.py


import argparse
import sys


def main():
    parser = argparse.ArgumentParser(
        description='Output pieces of FILE to FILE1, FILE2, ...;')
    parser.add_argument('file')
    parser.add_argument('-n', '--number', type=int,
                        help='split FILE into n pieces')
    args = parser.parse_args()
    file_split(args.file, args.number)

    
def file_split(filename, N):
    with open(filename) as fi:
        n_lines = sum(1 for _ in fi)
        fi.seek(0)
        for nth, width in enumerate((n_lines+i)//N for i in range(N)):
            with open(f'{filename}.split{nth}', 'w') as fo:
                for _ in range(width):
                    fo.write(fi.readline())


if __name__ == '__main__':
    main()
$ python q16.py -n 3 popular-names.txt
$ wc -l popular-names.txt.split*
  926 popular-names.txt.split0
  927 popular-names.txt.split1
  927 popular-names.txt.split2
 2780 total

Sie müssen sich keine Gedanken darüber machen, wie Sie "argparse" verwenden. Um die Anzahl der Zeilen zu zählen, verwenden wir diesmal die integrierte Funktion "sum ()", die die Summe der Elemente der Iterable berechnet.

Und wie man die ganzen Zahlen gleichmäßig verteilt. Angenommen, der Quotient ist "q" und der Rest ist "r", wenn "m" -Elemente in "n" Personen unterteilt werden. In diesem Fall verteilen Sie "q" -Stücke normal an "(nr)" Personen, und fügen Sie einen Rest zu den verbleibenden "r" -Personen hinzu und verteilen Sie sie nach "(q + 1)" - Teilen, um sie gleichmäßig zu machen. Ich werde.

Es ist der Teil von ((n_lines + i) // N für i im Bereich (N)), der es elegant geschrieben hat. Sie können den Dezimalpunkt mit // abschneiden und teilen. Siehe Qiita-Artikel hier, um zu sehen, warum dies gleichmäßig aufgeteilt ist.

Wenn Sie sich nicht für die Reihenfolge der Zeilen interessieren, können Sie "tee ()" und "islice ()" von "itertools" verwenden. Wenn Sie sich nicht für den Speicher interessieren, ist es möglicherweise einfacher, zip_longest () zu verwenden.

Der Unix-Befehl sollte "split -n l / 5 -d popular-names.txt popular-names.txt" lauten, funktioniert jedoch möglicherweise nicht, je nach "split" in Ihrer Umgebung.

Das letztere Problem ist einfach.

17. Unterschied in der Zeichenfolge in der ersten Spalte

Suchen Sie den Typ der Zeichenfolge in der ersten Spalte (eine Reihe verschiedener Zeichenfolgen). Verwenden Sie zur Bestätigung die Befehle sort und uniq.

Sie fügen einfach die erste Zeile zum Set hinzu. Nur die Listeneinschlussnotation wurde oben erläutert, es gibt jedoch auch eine Einschlussnotation und eine Wörterbucheinschlussnotation.

Unten finden Sie ein Beispiel für die Antwort.

q17.py


import sys


names = {line.split('\t')[0] for line in sys.stdin}
print('\n'.join(names))

Beachten Sie, dass der Aggregattyp bei jeder Ausführung seine Reihenfolge ändert. Wenn Ihnen das nicht gefällt, verwenden Sie den Wörterbuchtyp (CPython-Implementierung 3.6 oder höher, offiziell 3.7 oder höher, der Wörterbuchtyp ist in der Reihenfolge der Schlüsseladdition).

Unix-Befehlecut -f1 popular-names.txt | sort | uniqWird sein.uniqUm Duplikate in benachbarten Zeilen zu entfernen, gehen Sie wie folgt vorsortWird benötigt.

Lambda Ausdruck und Sortierung

Ich werde es für das nächste Problem verwenden, also werde ich dem Lambda-Ausdruck folgen. Lambda-Ausdrücke werden verwendet, um kleine Funktionen zu definieren. Wenn Sie beispielsweise "Lambda a, b: a + b" schreiben, gibt diese Funktion die Summe von zwei weiteren Zahlen zurück. Es kann wie eine normale Funktion aufgerufen werden, wird jedoch hauptsächlich als optionales Argument der Funktion sort () verwendet. Derzeit kann es an eine andere Funktion übergeben oder als Rückgabewert einer selbst erstellten Funktion verwendet werden.

Für "sort ()" ist das offizielle Sort HOW TO eine gute Ressource. Es reicht aus, bis zu "Aufsteigend und Absteigend" zu lesen.

18. Sortieren Sie jede Zeile in absteigender Reihenfolge der Zahlen in der dritten Spalte

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).

(Was ist eine Spalte ... Ich habe immer gesagt, dass ich in einer Zeile war ...) Unten ist ein Beispiel für die Antwort.

q18.py


import sys


sorted_list = sorted(sys.stdin, key=lambda x: int(x.split('\t')[2]), reverse=True)
print(''.join(sorted_list))

Beachten Sie, dass die Zahlen in der dritten Spalte Zeichenfolgen bleiben, sofern Sie sie nicht in einen numerischen Typ umwandeln. Das Casting kann mit eingebauten Funktionen erfolgen.

Der Unix-Befehl lautet sort -k3 -nr popular-names.txt. Dies bedeutet, dass das dritte Element als Zahl betrachtet und in aufsteigender Reihenfolge sortiert wird.

Unix sort ist sehr gut und führt sogar große Dateien aus, ohne dass zu wenig Speicherplatz zur Verfügung steht. Es ist auch relativ einfach zu beschleunigen (mit dem Gebietsschema herumspielen, am Ende teilen und zusammenführen usw.).

19. Ermitteln Sie die Häufigkeit des Auftretens der Zeichenfolge in der ersten Spalte jeder Zeile und ordnen Sie sie in absteigender Reihenfolge der Häufigkeit des Auftretens an.

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.

Hier wurden die versteckten Zeilen von collection.Counter wiederhergestellt! Wenn Sie die Dokumentation lesen, sollte es kein Problem geben. Denken Sie daran, dass "Counter" eine Unterklasse von "dict" ist.

Unten finden Sie ein Beispiel für die Antwort.

q19.py


from collections import Counter
import sys


col1_freq = Counter(line.split('\t')[0] for line in sys.stdin)
for elem, num in col1_freq.most_common():
    print(num, elem)

Unix-Befehlecut -f1 popular-names.txt | sort | uniq -c | sort -nrist. Wenn die Rohre einzeln verbunden werdenheadIch denke, es ist eine gute Idee, die Zwischenausgabe mit zu überprüfen.

Zusammenfassung

Weiter ist Kapitel 3

JSON-Dateien können mit dem [json-Modul] gelesen werden (https://docs.python.org/ja/3/library/json.html). Weitere Informationen zu regulären Ausdrücken finden Sie im offiziellen Regular Expression HOW TO. Ich werde eine Fortsetzung schreiben, wenn es LGTM oder Kommentare gibt.

(4/30 Nachschrift) Die Erklärung zu Kapitel 3 wurde veröffentlicht. → https://qiita.com/hi-asano/items/8e303425052781d95f09

Recommended Posts

[Kapitel 5] Einführung in Python mit 100 Klopfen Sprachverarbeitung
[Kapitel 3] Einführung in Python mit 100 Klopfen Sprachverarbeitung
[Kapitel 2] Einführung in Python mit 100 Klopfen Sprachverarbeitung
[Kapitel 4] Einführung in Python mit 100 Klopfen Sprachverarbeitung
[Kapitel 6] Einführung in Scicit-Learn mit 100 Klopfen Sprachverarbeitung
100 Sprachverarbeitungsklopfen mit Python (Kapitel 1)
100 Sprachverarbeitungsklopfen mit Python (Kapitel 2, Teil 2)
100 Sprachverarbeitungsklopfen ~ Kapitel 1
Einführung in die Python-Sprache
Erste Schritte mit Python mit 100 Klopfen bei der Sprachverarbeitung
100 Sprachverarbeitungsklopfen mit Python 2015
100 Sprachverarbeitung Knock Kapitel 1 (Python)
100 Sprachverarbeitung Knock Kapitel 2 (Python)
Rehabilitation von Python- und NLP-Kenntnissen ab "100 Language Processing Knock 2015" (Kapitel 1)
[Sprachverarbeitung 100 Schläge 2020] Zusammenfassung der Antwortbeispiele von Python
Einführung in die verteilte Parallelverarbeitung von Python durch Ray
Ich habe versucht, die 2020-Version von 100 Sprachverarbeitungsproblemen zu lösen [Kapitel 3: Reguläre Ausdrücke 20 bis 24]
Ich habe versucht, die 2020-Version von 100 Sprachverarbeitungsproblemen zu lösen [Kapitel 1: Vorbereitungsbewegung 00-04]
Ich habe versucht, die 2020-Version von 100 Sprachverarbeitungsproblemen zu lösen [Kapitel 1: Vorbereitungsbewegung 05-09]
100 Klicks in der Verarbeitung natürlicher Sprache Kapitel 4 Kommentar
[Sprachverarbeitung 100 Schläge 2020] Kapitel 6: Maschinelles Lernen
100 Sprachverarbeitung Knock Kapitel 1 in Python
100 Sprachverarbeitungsklopfen 2020: Kapitel 4 (morphologische Analyse)
[Sprachverarbeitung 100 Schläge 2020] Kapitel 5: Abhängigkeitsanalyse
[Einführung in Python3 Tag 13] Kapitel 7 Zeichenfolgen (7.1-7.1.1.1)
[Einführung in Python3 Tag 14] Kapitel 7 Zeichenfolgen (7.1.1.1 bis 7.1.1.4)
[Sprachverarbeitung 100 Schläge 2020] Kapitel 1: Vorbereitende Bewegung
Die Bildverarbeitung mit Python 100 klopft an die Binärisierung Nr. 3
[Sprachverarbeitung 100 Schläge 2020] Kapitel 7: Wortvektor
[Einführung in Python3 Tag 15] Kapitel 7 Zeichenfolgen (7.1.2-7.1.2.2)
10 Funktionen von "Sprache mit Batterie" Python
[Sprachverarbeitung 100 Schläge 2020] Kapitel 8: Neuronales Netz
[Sprachverarbeitung 100 Schläge 2020] Kapitel 2: UNIX-Befehle
[Sprachverarbeitung 100 Schläge 2020] Kapitel 9: RNN, CNN
100 Bildverarbeitung mit Python Knock # 2 Graustufen
100 Sprachverarbeitung Knock Kapitel 1 von Python
[Sprachverarbeitung 100 Schläge 2020] Kapitel 4: Morphologische Analyse
[Einführung in Python3 Tag 21] Kapitel 10 System (10.1 bis 10.5)
Sprachverarbeitung 100 Schläge-48: Extraktion des Weges von der Nase zur Wurzel
[Raspi4; Einführung in den Sound] Stabile Aufzeichnung der Toneingabe mit Python ♪
Rehabilitation von Python- und NLP-Kenntnissen ab "Knock 100 Language Processing 2015" (Kapitel 2, zweite Hälfte)
Rehabilitation von Python- und NLP-Kenntnissen ab "100 Language Processing Knock 2015" (Kapitel 2, erste Hälfte)
100 Sprachverarbeitungsklopfen 03 ~ 05
100 Sprachverarbeitungsklopfen (2020): 40
Grundlagen der binärisierten Bildverarbeitung durch Python
100 Sprachverarbeitungsklopfen (2020): 32
Zusammenfassung von Kapitel 2 der Einführung in Entwurfsmuster, die in Java gelernt wurden
IPynb-Bewertungssystem mit TA von Introduction to Programming (Python)
Ich habe mit GiNZA v3.1 Kapitel 4 100 Sprachverarbeitungsklopfen 2020 durchgeführt
100 Sprachverarbeitungsklopfen (2020): 47
[Einführung in Python3, Tag 17] Kapitel 8 Datenziele (8.1-8.2.5)
Kapitel 4 Zusammenfassung der Einführung in Entwurfsmuster, die in Java gelernt wurden
100 Sprachverarbeitungsklopfen (2020): 22
100 Sprachverarbeitung Knock-22: Extraktion des Kategorienamens
100 Sprachverarbeitungsklopfen (2020): 26
100 Sprachverarbeitungsklopfen (2020): 34
[Einführung in Python3, Tag 17] Kapitel 8 Datenziele (8.3-8.3.6.1)
100 Sprachverarbeitungsklopfen (2020): 42
Einführung in das Auffüllen von Python-Bildern Auffüllen von Bildern mit ImageDataGenerator
Sprachverarbeitung 100 Schläge Kapitel 4: Morphologische Analyse 31. Verben
Zusammenfassung von Kapitel 3 der Einführung in Entwurfsmuster, die in Java gelernt wurden