100 Language Processing Knock 2020 Chapitre 2: Commandes UNIX

L'autre jour, 100 Language Processing Knock 2020 a été publié. Je ne travaille moi-même sur le langage naturel que depuis un an, et je ne connais pas les détails, mais je vais résoudre tous les problèmes et les publier afin d'améliorer mes compétences techniques.

Tout doit être exécuté sur le notebook jupyter, et les restrictions de l'énoncé du problème peuvent être facilement rompues. Le code source est également sur github. Oui.

Le chapitre 1 est ici.

L'environnement est Python 3.8.2 et Ubuntu 18.04.

Je pense que ici est plus facile à comprendre en tant qu'article de commentaire. J'aimerais que les auteurs rédigent des articles de commentaire jusqu'au chapitre 10.

Chapitre 2: Commandes UNIX

popular-names.txt est un fichier qui stocke le «nom», le «sexe», le «nombre de personnes» et «l'année» d'un bébé né aux États-Unis dans un format délimité par des tabulations. Créez un programme qui effectue le traitement suivant et exécutez popular-names.txt en tant que fichier d'entrée. De plus, exécutez le même processus avec une commande UNIX et vérifiez le résultat de l'exécution du programme.

Veuillez télécharger l'ensemble de données requis depuis ici.

Le fichier téléchargé est placé sous «données».

10. Compter le nombre de lignes

Comptez le nombre de lignes. Utilisez la commande wc pour confirmation.

code


with open('data/popular-names.txt') as f:
    print(len(list(f)))

production


2780

Recherchez simplement la longueur de l'objet fichier. Étant donné que l'objet fichier est un itérateur, il doit être répertorié. Si l'entrée est un fichier suffisamment volumineux, il peut ne pas tenir dans la mémoire, mais dans ce cas, vous pouvez simplement le tourner avec l'instruction for et le compter.

code


wc -l < data/popular-names.txt

production


2780

Trouvez le nombre de lignes en spécifiant l'option l dans la commande wc. Si vous donnez un nom de fichier, divers extras seront affichés, alors donnez-le à partir de l'entrée standard.

11. Remplacez les onglets par des espaces

Remplacez chaque onglet par un espace. Utilisez la commande sed, la commande tr ou la commande expand pour confirmation.

code


with open('data/popular-names.txt') as f:
    for line in f:
        line = line.strip()
        line = line.replace('\t', ' ')
        print(line)

production(10 premières lignes)


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

Chaque chaîne obtenue en transformant l'objet fichier en itérateur a un caractère de saut de ligne à la fin, donc supprimez-la avec strip (rstrip ('\ n')peut être préférable). Remplacez simplement les onglets par des espaces et une sortie.

Il existe également une méthode de print (line, end = '') sans supprimer le caractère de saut de ligne avec strip.

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

La sortie est la même que celle de Python, je vais donc l'omettre. (Il en va de même par la suite)

Je ne me souviens pas de nombreuses commandes UNIX.

12. Enregistrez la première colonne dans col1.txt et la deuxième colonne dans col2.txt

Enregistrez la colonne extraite de chaque ligne sous col1.txt et la colonne extraite 2 sous col2.txt. Utilisez la commande cut pour confirmation.

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)

Je l'ai écrit docilement.

résultat(col1.10 premières lignes de txt)


Mary
Anna
Emma
Elizabeth
Minnie
Margaret
Ida
Alice
Bertha
Sarah

résultat(col2.10 premières lignes de 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

C'est facile avec la commande cut. ʻAwk '{print $ 1}' `est bien.

13. Fusionnez col1.txt et col2.txt

Combinez les col1.txt et col2.txt créés dans 12 pour créer un fichier texte dans lequel les première et deuxième colonnes du fichier d'origine sont disposées en tabulation. Utilisez la commande coller pour confirmation.

Tout ce que vous avez à faire est d'ouvrir les deux fichiers séparément, mais comme c'est un gros problème, utilisez contextlib.ExitStack pour l'implémenter afin de pouvoir gérer n'importe quel nombre de fichiers. Pour le gestionnaire de contexte → 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)

résultat(10 premières lignes)


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

C'est facile avec la commande coller.

14. Sortie de N lignes depuis le début

Recevoir le nombre naturel N au moyen d'un argument de ligne de commande et afficher uniquement les N premières lignes de l'entrée. Utilisez la commande head pour confirmation.

Personnellement, j'aime recevoir des arguments d'entrée et de ligne de commande standard avec ʻargparseetfileinput`, mais cette fois je veux pouvoir exécuter tout le code sur le notebook jupyter, donc j'utilise des arguments de ligne de commande ne pas. (Je ressens de la gentillesse envers "etc." dans l'énoncé du problème)

code


N = 5
with open('data/popular-names.txt') as f:
    lst = range(N)
    for _, line in zip(lst, f):
        print(line, end='')

production


Mary	F	7065	1880
Anna	F	2604	1880
Emma	F	2003	1880
Elizabeth	F	1939	1880
Minnie	F	1746	1880

Vous pouvez faire de même avec la commande head.

code


head -n 5 data/popular-names.txt

15. Sortez les N dernières lignes

Recevoir le nombre naturel N au moyen d'un argument de ligne de commande et n'afficher que les N dernières lignes de l'entrée. Utilisez la commande tail pour confirmation.

Je pense que c'est correct de mettre toutes les entrées standard dans la liste et d'extraire les 5 derniers éléments, mais si c'est un gros fichier, il peut ne pas tenir dans la mémoire, donc j'utiliserai la file d'attente.

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='')

production


Benjamin	M	13381	2018
Elijah	M	12886	2018
Lucas	M	12585	2018
Mason	M	12435	2018
Logan	M	12352	2018

Vous pouvez faire la même chose avec la commande tail.

code


tail -n 5 data/popular-names.txt

16. Divisez le fichier en N

Recevez le nombre naturel N au moyen d'arguments de ligne de commande et divisez le fichier d'entrée en N ligne par ligne. Réalisez le même traitement avec la commande de fractionnement.

Je pense que c'est parce qu'il n'y a pas beaucoup de situations où un fichier est divisé en N lignes par ligne, mais en fonction de l'implémentation de la commande de fractionnement, il peut ne pas y avoir N divisions par ligne. Ce peut être une extension GNU.

code(5 divisions)


split -d -nl/5 data/popular-names.txt result/shell5.

résultat(Vérifiez le nombre de lignes avec 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

Je l'ai également implémenté en python afin qu'il se comporte de la même manière que le code de cette extension GNU (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) #Omission
        with open(outprefix + idx, 'w') as f:
            f.write(''.join(lines))

split_file(5, 'data/popular-names.txt', 'result/python5.')

Tout d'abord, comptez le nombre total de caractères et décidez de la position de coupe (chunk_ends) afin que le nombre de caractères soit aussi uniforme que possible. Ensuite, il prend une ligne jusqu'à ce qu'il dépasse chaque élément de chunk_ends, et quand il dépasse, il le sort dans un fichier.

résultat(Vérifiez le nombre de lignes avec 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

résultat


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

J'ai obtenu le même résultat.

17. Différence dans la chaîne de caractères dans la première colonne

Recherchez le type de chaîne de caractères dans la première colonne (un ensemble de chaînes de caractères différentes). Utilisez les commandes cut, sort et uniq pour confirmation.

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)

résultat(10 premières lignes)


Abigail
Aiden
Alexander
Alexis
Alice
Amanda
Amelia
Amy
Andrew
Angela

La première colonne est ajoutée à l'ensemble dans l'ordre, triée et sortie. (* La version de python est 3.8.2.)

code


cut -f 1 data/popular-names.txt | sort -s | uniq 

Prenez uniquement la première colonne et triez pour supprimer les doublons. Si vous oubliez d'entrer le tri, ce sera étrange. De plus, l'option s est ajoutée pour assurer un tri stable selon python.

18. Triez chaque ligne dans l'ordre décroissant des nombres dans la troisième colonne

Disposez chaque ligne dans l'ordre inverse des nombres de la troisième colonne (Remarque: réorganisez le contenu de chaque ligne sans les changer) Utilisez la commande sort pour confirmation (ce problème ne doit pas nécessairement correspondre au résultat de l'exécution de la commande).

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)

production(10 premières lignes)


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

En spécifiant la clé de la fonction sort, vous pouvez spécifier les critères de tri.

code


sort -nrsk 3 data/popular-names.txt

Vous ne pouvez le faire qu'avec la commande sort. C'est facile.

19. Recherchez la fréquence d'apparition de la chaîne de caractères dans la première colonne de chaque ligne et organisez-les par ordre décroissant de fréquence d'apparition.

Trouvez la fréquence d'apparition de la première colonne de chaque ligne et affichez-les par ordre décroissant. Utilisez les commandes cut, uniq et sort pour confirmation.

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

production


James
William
John
Robert
Mary
Charles
Michael
Elizabeth
Joseph
Margaret

Soit passez la liste telle quelle à l'objet de Counter, soit passez-la petit à petit avec ʻupdate (). most_common ()` les organisera par ordre décroissant.

code


cut -f 1 data/popular-names.txt | sort | uniq -c | sort -nrsk1 | awk '{print $2}'

Si vous ajoutez l'option -c lorsque vous prenez ʻuniq`, il comptera combien il y en a. Enfin, triez par numéro pour obtenir le résultat souhaité.

Vient ensuite le chapitre 3

Traitement du langage 100 coups 2020 Chapitre 3: Expressions régulières

Recommended Posts

100 Language Processing Knock 2020 Chapitre 2: Commandes UNIX
100 Commandes de traitement du langage Knock UNIX apprises au chapitre 2
[Traitement du langage 100 coups 2020] Chapitre 2: Commandes UNIX
100 Language Processing Knock 2020 Chapitre 1
100 Traitement du langage Knock Chapitre 1
100 Language Processing Knock 2020 Chapitre 3
100 Language Processing Knock 2020 Chapitre 2
100 Language Processing Knock Chapitre 1 (Python)
100 Language Processing Knock Chapitre 2 (Python)
J'ai essayé de résoudre 100 traitements linguistiques Knock 2020 version [Chapitre 2: Commandes UNIX 10 à 14]
J'ai essayé de résoudre 100 traitements linguistiques Knock 2020 version [Chapitre 2: Commandes UNIX 15-19]
100 Language Processing Knock 2015 Chapitre 5 Analyse des dépendances (40-49)
100 traitements de langage avec Python
100 Language Processing Knock Chapitre 1 en Python
100 Language Processing Knock 2020 Chapitre 4: Analyse morphologique
100 Language Processing Knock 2020 Chapitre 9: RNN, CNN
100 coups de traitement linguistique (2020): 28
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 3
100 traitements de langage avec Python (chapitre 3)
100 Language Processing Knock: Chapitre 1 Mouvement préparatoire
100 Language Processing Knock 2020 Chapitre 6: Apprentissage automatique
100 Traitement du langage Knock Chapitre 4: Analyse morphologique
100 Language Processing Knock 2020 Chapitre 10: Traduction automatique (90-98)
100 Language Processing Knock: Chapitre 2 Principes de base des commandes UNIX (à l'aide de pandas)
100 Language Processing Knock 2020 Chapitre 5: Analyse des dépendances
100 Traitement du langage Knock 2020 Chapitre 7: Vecteur de mots
100 Language Processing Knock 2020 Chapitre 8: Neural Net
100 coups de traitement linguistique (2020): 38
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 1
100 traitement de la langue frapper 00 ~ 02
100 Language Processing Knock 2020 Chapitre 1: Mouvement préparatoire
100 Language Processing Knock Chapitre 1 par Python
100 Language Processing Knock 2020 Chapitre 3: Expressions régulières
100 Language Processing Knock 2015 Chapitre 4 Analyse morphologique (30-39)
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 2
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 4
100 points de traitement du langage naturel Chapitre 2 Bases des commandes UNIX (deuxième moitié)
100 points de traitement du langage naturel Chapitre 2 Bases des commandes UNIX (première moitié)
J'ai fait 100 traitements linguistiques Knock 2020 avec GiNZA v3.1 Chapitre 4
100 traitements de langage avec Python (chapitre 2, partie 2)
100 traitements de langage avec Python (chapitre 2, partie 1)
[Programmeur nouveau venu "100 language processing knock 2020"] Résoudre le chapitre 1
100 traitements linguistiques Knock 2020 [00 ~ 39 réponse]
100 langues de traitement knock 2020 [00-79 réponse]
100 traitements linguistiques Knock 2020 [00 ~ 69 réponse]
100 coups de traitement du langage amateur: 17
100 traitements linguistiques Knock 2020 [00 ~ 49 réponse]
100 Traitement du langage Knock-52: Stemming
100 coups de traitement du langage ~ Chapitre 1
100 coups de langue amateur: 07
Le traitement de 100 langues frappe le chapitre 2 (10 ~ 19)
100 coups de traitement du langage amateur: 09
100 coups en traitement du langage amateur: 47
Traitement 100 langues knock-53: Tokenisation
100 coups de traitement du langage amateur: 97
100 traitements linguistiques Knock 2020 [00 ~ 59 réponse]
100 coups de traitement du langage amateur: 67
100 Traitement du langage Knock Expressions régulières apprises au chapitre 3
100 coups de traitement du langage avec Python 2015
100 traitement du langage Knock-51: découpage de mots
100 Language Processing Knock-58: Extraction de Taple