言語処理100本ノック 2020 (Rev2) No.10~19

言語処理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 1880Anna F 2604 1880Emma F 2003 1880Elizabeth F 1939 1880Minnie F 1746 1880Margaret F 1578 1880Ida F 1472 1880Alice F 1414 1880Bertha F 1320 1880Sarah F 1288 188010. 行数のカウント
行数をカウントせよ.確認にはwcコマンドを用いよ.
with open("popular-names.txt") as f: lines = f.readlines() print(len(lines))
!echo ---!cat popular-names.txt | wc -l
# 出力2780---278011. タブをスペースに置換
タブ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 1880Anna F 2604 1880Emma F 2003 1880Elizabeth F 1939 1880Minnie F 1746 1880Margaret F 1578 1880Ida F 1472 1880Alice F 1414 1880Bertha F 1320 1880Sarah F 1288 1880---Mary F 7065 1880Anna F 2604 1880Emma F 2003 1880Elizabeth F 1939 1880Minnie F 1746 1880Margaret F 1578 1880Ida F 1472 1880Alice F 1414 1880Bertha F 1320 1880Sarah F 1288 1880---Mary F 7065 1880Anna F 2604 1880Emma F 2003 1880Elizabeth F 1939 1880Minnie F 1746 1880Margaret F 1578 1880Ida F 1472 1880Alice F 1414 1880Bertha F 1320 1880Sarah F 1288 1880---Mary F 7065 1880Anna F 2604 1880Emma F 2003 1880Elizabeth F 1939 1880Minnie F 1746 1880Margaret F 1578 1880Ida F 1472 1880Alice F 1414 1880Bertha F 1320 1880Sarah 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
# 出力MaryAnnaEmmaElizabethMinnieMargaretIdaAliceBerthaSarahFFFFFFFFFF---MaryAnnaEmmaElizabethMinnieMargaretIdaAliceBerthaSarahFFFFFFFFFFwith句でファイルを複数開くことができる
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 FAnna FEmma FElizabeth FMinnie FMargaret FIda FAlice FBertha FSarah F---Mary FAnna FEmma FElizabeth FMinnie FMargaret FIda FAlice FBertha FSarah F14. 先頭からN行を出力
自然数Nをコマンドライン引数などの手段で受け取り,入力のうち先頭のN行だけを表示せよ.確認にはheadコマンドを用いよ.
N = 10with 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 1880Anna F 2604 1880Emma F 2003 1880Elizabeth F 1939 1880Minnie F 1746 1880Margaret F 1578 1880Ida F 1472 1880Alice F 1414 1880Bertha F 1320 1880Sarah F 1288 1880---Mary F 7065 1880Anna F 2604 1880Emma F 2003 1880Elizabeth F 1939 1880Minnie F 1746 1880Margaret F 1578 1880Ida F 1472 1880Alice F 1414 1880Bertha F 1320 1880Sarah F 1288 188015. 末尾のN行を出力
自然数Nをコマンドライン引数などの手段で受け取り,入力のうち末尾のN行だけを表示せよ.確認にはtailコマンドを用いよ.
N = 10with 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 2018Mason M 12435 2018Lucas M 12585 2018Elijah M 12886 2018Benjamin M 13381 2018Oliver M 13389 2018James M 13525 2018William M 14516 2018Noah M 18267 2018Liam M 19837 2018---Liam M 19837 2018Noah M 18267 2018William M 14516 2018James M 13525 2018Oliver M 13389 2018Benjamin M 13381 2018Elijah M 12886 2018Lucas M 12585 2018Mason M 12435 2018Logan M 12352 2018全部読み込んで後ろから表示すれば良いが、効率を考えると後ろからファイルを読みたくなる。次のリンクに実装例があるので、必要になったときは参考にしたい。
16. ファイルをN分割する
自然数Nをコマンドライン引数などの手段で受け取り,入力のファイルを行単位でN分割せよ.同様の処理をsplitコマンドで実現せよ.
N = 3with open("popular-names.txt") as f: lines = f.readlines()
total = len(lines)a = -(-total // N) # 切り上げn = 0f = open("output16-0.txt", "w")fcnt = 0for line in lines: if n >= a: n = 0 f.close() fcnt += 1 f = open("output16-" + str(fcnt) + ".txt", "w") f.write(line) n += 1f.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
# 出力AbigailAidenAlexanderAlexisAliceAmandaAmeliaAmy~~省略~~---AbigailAidenAlexanderAlexisAliceAmandaAmeliaAmy18. 各行を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 1947Linda F 96211 1948James M 94757 1947Michael M 92704 1957Robert M 91640 1947Linda F 91016 1949Michael M 90656 1956Michael M 90517 1958James M 88584 1948Michael M 88528 1954~~省略~~---Linda F 99689 1947Linda F 96211 1948James M 94757 1947Michael M 92704 1957Robert M 91640 1947Linda F 91016 1949Michael M 90656 1956Michael M 90517 1958James M 88584 1948Michael M 88528 195419. 各行の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コマンドが意外と短い記述でファイル処理できることを発見してしまった。コマンドの方が計算効率もいいと思うので、使い分けできるようになりたい。
スポンサーリンク
スポンサーリンク
