言語処理100本ノックの2020年版があったのでやっていく。
準備
お手軽にGoogle Colab( https://colab.research.google.com/?hl=ja )でやっていく。まずは必要なデータをダウンロードする。
!wget https://nlp100.github.io/data/popular-names.txt
!head popular-names.txt
# 出力
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
10. 行数のカウント
行数をカウントせよ.確認にはwcコマンドを用いよ.
with open("popular-names.txt") as f:
lines = f.readlines()
print(len(lines))
!echo ---
!cat popular-names.txt | wc -l
# 出力
2780
---
2780
11. タブをスペースに置換
タブ1文字につきスペース1文字に置換せよ.確認にはsedコマンド,trコマンド,もしくはexpandコマンドを用いよ.
with open("popular-names.txt") as fin, open('output11.txt', 'w') as fout:
while True:
line = fin.readline()
if line == "":
break
l = line.replace("\t", " ")
fout.write(l)
!head output11.txt
!echo ---
# sed
!cat popular-names.txt | sed 's/\t/ /g' | head
!echo ---
# tr
!cat popular-names.txt | tr '\t' ' ' | head
!echo ---
# expand
!cat popular-names.txt | expand -t 1 | head
# 出力
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
---
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
---
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
---
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
データの前処理ぐらいはコマンドでやってもいいかもと思えるぐらい、コマンド便利
12. 1列目をcol1.txtに,2列目をcol2.txtに保存
各行の1列目だけを抜き出したものをcol1.txtに,2列目だけを抜き出したものをcol2.txtとしてファイルに保存せよ.確認にはcutコマンドを用いよ.
with open("popular-names.txt") as fin, open("col1.txt", "w") as fout1, open("col2.txt", "w") as fout2:
while True:
line = fin.readline()
if line == "":
break
tmp = line.split("\t")
fout1.write(tmp[0]+"\n")
fout2.write(tmp[1]+"\n")
!head col1.txt
!head col2.txt
!echo ---
!cat output-expand.txt | cut -f 1 -d " " | head
!cat output-expand.txt | cut -f 2 -d " " | head
# 出力
Mary
Anna
Emma
Elizabeth
Minnie
Margaret
Ida
Alice
Bertha
Sarah
F
F
F
F
F
F
F
F
F
F
---
Mary
Anna
Emma
Elizabeth
Minnie
Margaret
Ida
Alice
Bertha
Sarah
F
F
F
F
F
F
F
F
F
F
with句でファイルを複数開くことができる
13. col1.txtとcol2.txtをマージ
12で作ったcol1.txtとcol2.txtを結合し,元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ.確認にはpasteコマンドを用いよ.
with open("col1.txt") as fin1, open("col2.txt") as fin2, open("output12.txt", "w") as fout:
while True:
line1 = fin1.readline().strip()
line2 = fin2.readline()
if line1 == "" or line2 == "":
break
fout.write(line1 + "\t" + line2)
!cat output12.txt | head
!echo ---
!paste col1.txt col2.txt | head
# 出力
Mary F
Anna F
Emma F
Elizabeth F
Minnie F
Margaret F
Ida F
Alice F
Bertha F
Sarah F
---
Mary F
Anna F
Emma F
Elizabeth F
Minnie F
Margaret F
Ida F
Alice F
Bertha F
Sarah F
14. 先頭からN行を出力
自然数Nをコマンドライン引数などの手段で受け取り,入力のうち先頭のN行だけを表示せよ.確認にはheadコマンドを用いよ.
N = 10
with open("popular-names.txt") as f:
n = 0
while True:
line = f.readline().strip()
if n >= N or line == "":
break
print(line)
n += 1
!echo ---
!n=10; head -n $n popular-names.txt
# 出力
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
---
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
15. 末尾のN行を出力
自然数Nをコマンドライン引数などの手段で受け取り,入力のうち末尾のN行だけを表示せよ.確認にはtailコマンドを用いよ.
N = 10
with open("popular-names.txt") as f:
lines = f.readlines()
total = len(lines)
n = 0
while True:
if n >= N or total - 1 - n < 0:
break
line = lines[total - 1 - n].strip()
print(line)
n += 1
!echo ---
!n=10; tail -n $n popular-names.txt
# 出力
Logan M 12352 2018
Mason M 12435 2018
Lucas M 12585 2018
Elijah M 12886 2018
Benjamin M 13381 2018
Oliver M 13389 2018
James M 13525 2018
William M 14516 2018
Noah M 18267 2018
Liam M 19837 2018
---
Liam M 19837 2018
Noah M 18267 2018
William M 14516 2018
James M 13525 2018
Oliver M 13389 2018
Benjamin M 13381 2018
Elijah M 12886 2018
Lucas M 12585 2018
Mason M 12435 2018
Logan M 12352 2018
全部読み込んで後ろから表示すれば良いが、効率を考えると後ろからファイルを読みたくなる。次のリンクに実装例があるので、必要になったときは参考にしたい。
16. ファイルをN分割する
自然数Nをコマンドライン引数などの手段で受け取り,入力のファイルを行単位でN分割せよ.同様の処理をsplitコマンドで実現せよ.
N = 3
with open("popular-names.txt") as f:
lines = f.readlines()
total = len(lines)
a = -(-total // N) # 切り上げ
n = 0
f = open("output16-0.txt", "w")
fcnt = 0
for line in lines:
if n >= a:
n = 0
f.close()
fcnt += 1
f = open("output16-" + str(fcnt) + ".txt", "w")
f.write(line)
n += 1
f.close()
!N=3; cnt=`cat popular-names.txt | wc -l`; a=$((cnt/N+1)); split -l $a popular-names.txt output16-chk
!ls -l
# 出力
-rw-r--r-- 1 root root 17739 Feb 26 11:13 output16-0.txt
-rw-r--r-- 1 root root 18428 Feb 26 11:13 output16-1.txt
-rw-r--r-- 1 root root 18859 Feb 26 11:13 output16-2.txt
-rw-r--r-- 1 root root 17739 Feb 26 11:13 output16-chkaa
-rw-r--r-- 1 root root 18428 Feb 26 11:13 output16-chkab
-rw-r--r-- 1 root root 18859 Feb 26 11:13 output16-chkac
切り上げを実装する際にmath.ceilを利用すると思うが、整数除算を利用することでも行ける。ついでに計算効率がいいらしい。
17. 1列目の文字列の異なり
1列目の文字列の種類(異なる文字列の集合)を求めよ.確認にはcut, sort, uniqコマンドを用いよ.
with open("popular-names.txt") as f:
lines = f.readlines()
m = {}
for line in lines:
tmp = line.split("\t")
m[tmp[0]] = 1
for key in sorted(m.keys()):
print(key)
!echo ---
!cat popular-names.txt | cut -f 1 | sort | uniq
# 出力
Abigail
Aiden
Alexander
Alexis
Alice
Amanda
Amelia
Amy
~~省略~~
---
Abigail
Aiden
Alexander
Alexis
Alice
Amanda
Amelia
Amy
18. 各行を3コラム目の数値の降順にソート
各行を3コラム目の数値の逆順で整列せよ(注意: 各行の内容は変更せずに並び替えよ).確認にはsortコマンドを用いよ(この問題はコマンドで実行した時の結果と合わなくてもよい).
with open("popular-names.txt") as f:
lines = f.readlines()
sortsecond = lambda val: int(val[0])
m = []
for line in lines:
v = line.split("\t")[2]
m.append([v, line.strip()])
m.sort(key=sortsecond, reverse=True)
for e in m:
print(e[1])
!echo ---
!cat popular-names.txt | sort -n -r -t $'\t' -k 3 | head
# 出力
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
~~省略~~
---
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
19. 各行の1コラム目の文字列の出現頻度を求め,出現頻度の高い順に並べる
各行の1列目の文字列の出現頻度を求め,その高い順に並べて表示せよ.確認にはcut, uniq, sortコマンドを用いよ.
with open("popular-names.txt") as f:
lines = f.readlines()
sortsecond = lambda val: int(val[0])
m = {}
for line in lines:
n = line.split("\t")[0]
if n not in m:
m[n] = 0
m[n] += 1
sortedList = sorted(m.items(), key=lambda x:x[1], reverse=True)
for e in sortedList:
print(e)
!echo ---
!cat popular-names.txt | cut -f 1 | sort | uniq -c | sort -n -r
# 出力
('James', 118)
('William', 111)
('John', 108)
('Robert', 108)
('Mary', 92)
('Charles', 75)
('Michael', 74)
('Elizabeth', 73)
('Joseph', 70)
('Margaret', 60)
('George', 58)
('Thomas', 58)
('David', 57)
('Richard', 51)
('Helen', 45)
('Frank', 43)
('Christopher', 43)
('Anna', 41)
('Edward', 40)
('Ruth', 39)
('Patricia', 38)
('Matthew', 37)
('Dorothy', 36)
('Emma', 35)
('Barbara', 32)
('Daniel', 31)
('Joshua', 31)
('Sarah', 26)
('Linda', 26)
('Jennifer', 26)
('Emily', 26)
('Jessica', 25)
('Jacob', 25)
('Mildred', 24)
('Betty', 24)
('Susan', 24)
('Henry', 23)
('Ashley', 23)
('Nancy', 22)
('Andrew', 21)
('Florence', 20)
('Marie', 20)
('Donald', 20)
('Amanda', 20)
('Samantha', 19)
('Karen', 18)
('Lisa', 18)
('Melissa', 18)
('Madison', 18)
('Olivia', 18)
('Stephanie', 17)
('Abigail', 17)
('Ethel', 16)
('Sandra', 16)
('Mark', 16)
('Frances', 15)
('Carol', 15)
('Angela', 15)
('Michelle', 15)
('Heather', 15)
('Ethan', 15)
('Isabella', 15)
('Shirley', 14)
('Kimberly', 14)
('Amy', 14)
('Ava', 14)
('Virginia', 13)
('Deborah', 13)
('Brian', 13)
('Jason', 13)
('Nicole', 13)
('Hannah', 13)
('Sophia', 13)
('Minnie', 12)
('Bertha', 12)
('Donna', 12)
('Cynthia', 11)
('Alice', 10)
('Doris', 10)
('Ronald', 10)
('Brittany', 10)
('Nicholas', 10)
('Mia', 10)
('Noah', 10)
('Joan', 9)
('Debra', 9)
('Tyler', 9)
('Ida', 8)
('Clara', 8)
('Judith', 8)
('Taylor', 8)
('Alexis', 8)
('Alexander', 8)
('Mason', 8)
('Harry', 7)
('Sharon', 7)
('Steven', 7)
('Tammy', 7)
('Brandon', 7)
('Liam', 7)
('Anthony', 6)
('Annie', 5)
('Gary', 5)
('Jeffrey', 5)
('Jayden', 5)
('Charlotte', 5)
('Lillian', 4)
('Kathleen', 4)
('Justin', 4)
('Austin', 4)
('Chloe', 4)
('Benjamin', 4)
('Evelyn', 3)
('Megan', 3)
('Aiden', 3)
('Harper', 3)
('Elijah', 3)
('Bessie', 2)
('Larry', 2)
('Rebecca', 2)
('Lauren', 2)
('Amelia', 2)
('Logan', 2)
('Oliver', 2)
('Walter', 1)
('Carolyn', 1)
('Pamela', 1)
('Lori', 1)
('Laura', 1)
('Tracy', 1)
('Julie', 1)
('Scott', 1)
('Kelly', 1)
('Crystal', 1)
('Rachel', 1)
('Lucas', 1)
---
118 James
111 William
108 Robert
108 John
92 Mary
75 Charles
74 Michael
73 Elizabeth
70 Joseph
60 Margaret
58 Thomas
58 George
57 David
51 Richard
45 Helen
43 Frank
43 Christopher
41 Anna
40 Edward
39 Ruth
38 Patricia
37 Matthew
36 Dorothy
35 Emma
32 Barbara
31 Joshua
31 Daniel
26 Sarah
26 Linda
26 Jennifer
26 Emily
25 Jessica
25 Jacob
24 Susan
24 Mildred
24 Betty
23 Henry
23 Ashley
22 Nancy
21 Andrew
20 Marie
20 Florence
20 Donald
20 Amanda
19 Samantha
18 Olivia
18 Melissa
18 Madison
18 Lisa
18 Karen
17 Stephanie
17 Abigail
16 Sandra
16 Mark
16 Ethel
15 Michelle
15 Isabella
15 Heather
15 Frances
15 Ethan
15 Carol
15 Angela
14 Shirley
14 Kimberly
14 Ava
14 Amy
13 Virginia
13 Sophia
13 Nicole
13 Jason
13 Hannah
13 Deborah
13 Brian
12 Minnie
12 Donna
12 Bertha
11 Cynthia
10 Ronald
10 Noah
10 Nicholas
10 Mia
10 Doris
10 Brittany
10 Alice
9 Tyler
9 Joan
9 Debra
8 Taylor
8 Mason
8 Judith
8 Ida
8 Clara
8 Alexis
8 Alexander
7 Tammy
7 Steven
7 Sharon
7 Liam
7 Harry
7 Brandon
6 Anthony
5 Jeffrey
5 Jayden
5 Gary
5 Charlotte
5 Annie
4 Lillian
4 Kathleen
4 Justin
4 Chloe
4 Benjamin
4 Austin
3 Megan
3 Harper
3 Evelyn
3 Elijah
3 Aiden
2 Rebecca
2 Oliver
2 Logan
2 Lauren
2 Larry
2 Bessie
2 Amelia
1 Walter
1 Tracy
1 Scott
1 Rachel
1 Pamela
1 Lucas
1 Lori
1 Laura
1 Kelly
1 Julie
1 Crystal
1 Carolyn
まとめ
UnixコマンドをPythonで実装してみるという課題でした。Pythonの実習だと思うが、Unixコマンドが意外と短い記述でファイル処理できることを発見してしまった。コマンドの方が計算効率もいいと思うので、使い分けできるようになりたい。
コメント