LoginSignup
0
1

More than 5 years have passed since last update.

言語処理100本ノック 2章(10~19)

Last updated at Posted at 2017-03-15

2章です
コードはgithubにあげるようにしました。

今回の範囲で使うテキストファイルは以下

hightemp.txt
高知県   江川崎   41  2013-08-12
埼玉県   熊谷  40.9    2007-08-16
岐阜県   多治見   40.9    2007-08-16
山形県   山形  40.8    1933-07-25
山梨県   甲府  40.7    2013-08-10
和歌山県    かつらぎ    40.6    1994-08-08
静岡県   天竜  40.6    1994-08-04
山梨県   勝沼  40.5    2013-08-10
埼玉県   越谷  40.4    2007-08-16
群馬県   館林  40.3    2007-08-16
群馬県   上里見   40.3    1998-07-04
愛知県   愛西  40.3    1994-08-05
千葉県   牛久  40.2    2004-07-20
静岡県   佐久間   40.2    2001-07-24
愛媛県   宇和島   40.2    1927-07-22
山形県   酒田  40.1    1978-08-03
岐阜県   美濃  40  2007-08-16
群馬県   前橋  40  2001-07-24
千葉県   茂原  39.9    2013-08-11
埼玉県   鳩山  39.9    1997-07-05
大阪府   豊中  39.9    1994-08-08
山梨県   大月  39.9    1990-07-19
山形県   鶴岡  39.9    1978-08-03
愛知県   名古屋   39.9    1942-08-02

10. 行数のカウント

行数をカウントせよ.確認にはwcコマンドを用いよ.

10.py
# リスト内包表記使ってみる
num_lines = len([line for line in open('./hightemp.txt')])
print(num_lines)

# 結果確認用
import subprocess
output = subprocess.check_output(['wc','-l','./hightemp.txt'])
print(output)

コード実行結果とコマンド実行結果
10実行結果
$ python 10.py
24
b'24 ./hightemp.txt\n'

1章終わったあとに他の人のコード見たらfor文短い!と思って
調べてたらリスト内包表記なんてあるんですね

11. タブをスペースに置換

タブ1文字につきスペース1文字に置換せよ.確認にはsedコマンド,trコマンド,もしくはexpandコマンドを用いよ.

11.py
# リスト内包表記で各行のタブを1文字スペースに変換
space_text = [line.expandtabs(1) for line in open('./hightemp.txt')]
[print(line) for line in space_text]

# 確認用コマンド
# $ cat ./hightemp.txt | tr '\t' ' '
$ python 11.py 
高知県 江川崎 41 2013-08-12

埼玉県 熊谷 40.9 2007-08-16

岐阜県 多治見 40.9 2007-08-16

山形県 山形 40.8 1933-07-25

山梨県 甲府 40.7 2013-08-10

和歌山県 かつらぎ 40.6 1994-08-08

静岡県 天竜 40.6 1994-08-04

山梨県 勝沼 40.5 2013-08-10

埼玉県 越谷 40.4 2007-08-16

群馬県 館林 40.3 2007-08-16

群馬県 上里見 40.3 1998-07-04

愛知県 愛西 40.3 1994-08-05

千葉県 牛久 40.2 2004-07-20

静岡県 佐久間 40.2 2001-07-24

愛媛県 宇和島 40.2 1927-07-22

山形県 酒田 40.1 1978-08-03

岐阜県 美濃 40 2007-08-16

群馬県 前橋 40 2001-07-24

千葉県 茂原 39.9 2013-08-11

埼玉県 鳩山 39.9 1997-07-05

大阪府 豊中 39.9 1994-08-08

山梨県 大月 39.9 1990-07-19

山形県 鶴岡 39.9 1978-08-03

愛知県 名古屋 39.9 1942-08-02

$ cat ./hightemp.txt | tr '\t' ' '
高知県 江川崎 41 2013-08-12
埼玉県 熊谷 40.9 2007-08-16
岐阜県 多治見 40.9 2007-08-16
山形県 山形 40.8 1933-07-25
山梨県 甲府 40.7 2013-08-10
和歌山県 かつらぎ 40.6 1994-08-08
静岡県 天竜 40.6 1994-08-04
山梨県 勝沼 40.5 2013-08-10
埼玉県 越谷 40.4 2007-08-16
群馬県 館林 40.3 2007-08-16
群馬県 上里見 40.3 1998-07-04
愛知県 愛西 40.3 1994-08-05
千葉県 牛久 40.2 2004-07-20
静岡県 佐久間 40.2 2001-07-24
愛媛県 宇和島 40.2 1927-07-22
山形県 酒田 40.1 1978-08-03
岐阜県 美濃 40 2007-08-16
群馬県 前橋 40 2001-07-24
千葉県 茂原 39.9 2013-08-11
埼玉県 鳩山 39.9 1997-07-05
大阪府 豊中 39.9 1994-08-08
山梨県 大月 39.9 1990-07-19
山形県 鶴岡 39.9 1978-08-03
愛知県 名古屋 39.9 1942-08-02

改行入ってしまっているのが少し気になる

12. 1列目をcol1.txtに,2列目をcol2.txtに保存

各行の1列目だけを抜き出したものをcol1.txtに,2列目だけを抜き出したものをcol2.txtとしてファイルに保存せよ.確認にはcutコマンドを用いよ.

12.py
# リスト内包表記で各行をタブでスライスして、1列目と2列目をリスト化
col1 = [line.split('\t')[0] for line in open('./hightemp.txt')]
col2 = [line.split('\t')[1] for line in open('./hightemp.txt')]

# 書き込みモードでファイルオープン
f1 = open('./col1.txt','w')
f2 = open('./col2.txt','w')

# 改行コードでjoin
f1.write('\n'.join(col1))
f2.write('\n'.join(col2))

# 確認用コマンド
# $ cat ./hightemp.txt  | cut -f 1
# $ cat ./hightemp.txt  | cut -f 2
$ python 12.py ← col1.txt,col2.txtが作られる
$ cat ./hightemp.txt  | cut -f 1
高知県
埼玉県
岐阜県
山形県
山梨県
和歌山県
静岡県
山梨県
埼玉県
群馬県
群馬県
愛知県
千葉県
静岡県
愛媛県
山形県
岐阜県
群馬県
千葉県
埼玉県
大阪府
山梨県
山形県
愛知県

$ cat ./hightemp.txt  | cut -f 2
江川崎
熊谷
多治見
山形
甲府
かつらぎ
天竜
勝沼
越谷
館林
上里見
愛西
牛久
佐久間
宇和島
酒田
美濃
前橋
茂原
鳩山
豊中
大月
鶴岡
名古屋
col1.txt
高知県
埼玉県
岐阜県
山形県
山梨県
和歌山県
静岡県
山梨県
埼玉県
群馬県
群馬県
愛知県
千葉県
静岡県
愛媛県
山形県
岐阜県
群馬県
千葉県
埼玉県
大阪府
山梨県
山形県
愛知県
col2.txt
江川崎
熊谷
多治見
山形
甲府
かつらぎ
天竜
勝沼
越谷
館林
上里見
愛西
牛久
佐久間
宇和島
酒田
美濃
前橋
茂原
鳩山
豊中
大月
鶴岡
名古屋

13. col1.txtとcol2.txtをマージ

12で作ったcol1.txtとcol2.txtを結合し,元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ.確認にはpasteコマンドを用いよ.

13.py
# とりあえず読み込み
col1 = [line for line in open('./col1.txt')]
col2 = [line for line in open('./col2.txt')]

new_file = open('./new_file.txt','w')

# zipで2つのリストを連結して処理
# 2つのリストをタブで連結、改行コードを削除を1行として
# 最後に改行いれて次の行へ
for col in zip(col1, col2):
    new_file.write('\t'.join(col).replace('\n',''))
    new_file.write('\n')

# 確認用コマンド
# $ paste ./col1.txt ./col2.txt
$ python 13.py
$ cat new_file.txt 
高知県   江川崎
埼玉県   熊谷
岐阜県   多治見
山形県   山形
山梨県   甲府
和歌山県    かつらぎ
静岡県   天竜
山梨県   勝沼
埼玉県   越谷
群馬県   館林
群馬県   上里見
愛知県   愛西
千葉県   牛久
静岡県   佐久間
愛媛県   宇和島
山形県   酒田
岐阜県   美濃
群馬県   前橋
千葉県   茂原
埼玉県   鳩山
大阪府   豊中
山梨県   大月
山形県   鶴岡
愛知県   名古屋

$ paste ./col1.txt ./col2.txt
高知県   江川崎
埼玉県   熊谷
岐阜県   多治見
山形県   山形
山梨県   甲府
和歌山県    かつらぎ
静岡県   天竜
山梨県   勝沼
埼玉県   越谷
群馬県   館林
群馬県   上里見
愛知県   愛西
千葉県   牛久
静岡県   佐久間
愛媛県   宇和島
山形県   酒田
岐阜県   美濃
群馬県   前橋
千葉県   茂原
埼玉県   鳩山
大阪府   豊中
山梨県   大月
山形県   鶴岡
愛知県   名古屋

14. 先頭からN行を出力

自然数Nをコマンドライン引数などの手段で受け取り,入力のうち先頭のN行だけを表示せよ.確認にはheadコマンドを用いよ.

14.py
# input()で標準入力受け付けれる
# int()でinteger型に変換
input = int(input())

lines = [line for line in open('./hightemp.txt')]

print(''.join(lines[:input]))

# 確認用コマンド
# $ head ./hightemp.txt -n
$ python 14.py 
4 ← 標準入力
高知県   江川崎   41  2013-08-12
埼玉県   熊谷  40.9    2007-08-16
岐阜県   多治見   40.9    2007-08-16
山形県   山形  40.8    1933-07-25

$ head ./hightemp.txt -n 4
高知県   江川崎   41  2013-08-12
埼玉県   熊谷  40.9    2007-08-16
岐阜県   多治見   40.9    2007-08-16
山形県   山形  40.8    1933-07-25

15. 末尾のN行を出力

自然数Nをコマンドライン引数などの手段で受け取り,入力のうち末尾のN行だけを表示せよ.確認にはtailコマンドを用いよ.

15.py
# 14と同じ感じ
input = int(input())

lines = [line for line in open('./hightemp.txt')]

# スライスおさらい
# 負の数与えると末尾からの順番で扱える
print(''.join(lines[-input:]))

# 確認用コマンド
# $ tail ./hightemp.txt -n
$ python 15.py 
3 ← 標準入力
山梨県   大月  39.9    1990-07-19
山形県   鶴岡  39.9    1978-08-03
愛知県   名古屋   39.9    1942-08-02

$ tail ./hightemp.txt -n 3
山梨県   大月  39.9    1990-07-19
山形県   鶴岡  39.9    1978-08-03
愛知県   名古屋   39.9    1942-08-02

16. ファイルをN分割する

自然数Nをコマンドライン引数などの手段で受け取り,入力のファイルを行単位でN分割せよ.同様の処理をsplitコマンドで実現せよ.

16.py
input = int(input())

lines = [line for line in open('./hightemp.txt')]

sublist = [''.join(lines[i:i+input]) for i in range(0,len(lines),input)]

# python結果確認用
for i in sublist:
    print(i)

# 確認用コマンド
# $ split -l N ./hightemp.txt 
$ python 16.py
9 ← 標準入力
高知県   江川崎   41  2013-08-12
埼玉県   熊谷  40.9    2007-08-16
岐阜県   多治見   40.9    2007-08-16
山形県   山形  40.8    1933-07-25
山梨県   甲府  40.7    2013-08-10
和歌山県    かつらぎ    40.6    1994-08-08
静岡県   天竜  40.6    1994-08-04
山梨県   勝沼  40.5    2013-08-10
埼玉県   越谷  40.4    2007-08-16

群馬県   館林  40.3    2007-08-16
群馬県   上里見   40.3    1998-07-04
愛知県   愛西  40.3    1994-08-05
千葉県   牛久  40.2    2004-07-20
静岡県   佐久間   40.2    2001-07-24
愛媛県   宇和島   40.2    1927-07-22
山形県   酒田  40.1    1978-08-03
岐阜県   美濃  40  2007-08-16
群馬県   前橋  40  2001-07-24

千葉県   茂原  39.9    2013-08-11
埼玉県   鳩山  39.9    1997-07-05
大阪府   豊中  39.9    1994-08-08
山梨県   大月  39.9    1990-07-19
山形県   鶴岡  39.9    1978-08-03
愛知県   名古屋   39.9    1942-08-02

$ split -l 9 ./hightemp.txt 

$ ls
10.py  12.py  14.py  16.py  18.py  col1.txt  hightemp.txt  xaa  xac
11.py  13.py  15.py  17.py  19.py  col2.txt  new_file.txt  xab

$ cat xaa
高知県   江川崎   41  2013-08-12
埼玉県   熊谷  40.9    2007-08-16
岐阜県   多治見   40.9    2007-08-16
山形県   山形  40.8    1933-07-25
山梨県   甲府  40.7    2013-08-10
和歌山県    かつらぎ    40.6    1994-08-08
静岡県   天竜  40.6    1994-08-04
山梨県   勝沼  40.5    2013-08-10
埼玉県   越谷  40.4    2007-08-16

17. 1列目の文字列の異なり

1列目の文字列の種類(異なる文字列の集合)を求めよ.確認にはsort, uniqコマンドを用いよ.

17.py
# 1列目のデータを取り出し
col1 = [line.split('\t')[0] for line in open('./hightemp.txt')]
output = []

# 別リストに追加していく、重複した値は入れない
for c in col1:
    if c not in output:
        output.append(c)

print(output)

# $ cat hightemp.txt | cut -f 1 | sort -k1  | uniq
$ python 17.py 
['高知県', '埼玉県', '岐阜県', '山形県', '山梨県', '和歌山県', '静岡県', '群馬県', '愛知県', '千葉県', '愛媛県', '大阪府']

$ cat hightemp.txt | cut -f 1 | sort -k1  | uniq
愛知県
愛媛県
岐阜県
群馬県
高知県
埼玉県
山形県
山梨県
静岡県
千葉県
大阪府
和歌山県

18. 各行を3コラム目の数値の降順にソート

各行を3コラム目の数値の逆順で整列せよ(注意: 各行の内容は変更せずに並び替えよ).確認にはsortコマンドを用いよ(この問題はコマンドで実行した時の結果と合わなくてもよい).

18.py
# 3列目のリストと、行ごとのリストをとる
values = [line.split('\t')[2] for line in open('./hightemp.txt')]
keys = [line for line in open('./hightemp.txt')]

dic = dict(zip(keys,values))

# 3列目の値でソート
sort_dic = sorted(dic.items(), key=lambda x:x[1])

for k,v in sort_dic:
    print(k)

# 確認用コマンド
# $ cat hightemp.txt |  sort -k3
$ python 18.py 
千葉県   茂原  39.9    2013-08-11

埼玉県   鳩山  39.9    1997-07-05

大阪府   豊中  39.9    1994-08-08

山梨県   大月  39.9    1990-07-19

山形県   鶴岡  39.9    1978-08-03

愛知県   名古屋   39.9    1942-08-02

岐阜県   美濃  40  2007-08-16

群馬県   前橋  40  2001-07-24

山形県   酒田  40.1    1978-08-03

千葉県   牛久  40.2    2004-07-20

静岡県   佐久間   40.2    2001-07-24

愛媛県   宇和島   40.2    1927-07-22

群馬県   館林  40.3    2007-08-16

群馬県   上里見   40.3    1998-07-04

愛知県   愛西  40.3    1994-08-05

埼玉県   越谷  40.4    2007-08-16

山梨県   勝沼  40.5    2013-08-10

和歌山県    かつらぎ    40.6    1994-08-08

静岡県   天竜  40.6    1994-08-04

山梨県   甲府  40.7    2013-08-10

山形県   山形  40.8    1933-07-25

埼玉県   熊谷  40.9    2007-08-16

岐阜県   多治見   40.9    2007-08-16

高知県   江川崎   41  2013-08-12

$ cat hightemp.txt |  sort -k3
愛知県   名古屋   39.9    1942-08-02
山形県   鶴岡  39.9    1978-08-03
山梨県   大月  39.9    1990-07-19
大阪府   豊中  39.9    1994-08-08
埼玉県   鳩山  39.9    1997-07-05
千葉県   茂原  39.9    2013-08-11
群馬県   前橋  40  2001-07-24
岐阜県   美濃  40  2007-08-16
山形県   酒田  40.1    1978-08-03
愛媛県   宇和島   40.2    1927-07-22
静岡県   佐久間   40.2    2001-07-24
千葉県   牛久  40.2    2004-07-20
愛知県   愛西  40.3    1994-08-05
群馬県   上里見   40.3    1998-07-04
群馬県   館林  40.3    2007-08-16
埼玉県   越谷  40.4    2007-08-16
山梨県   勝沼  40.5    2013-08-10
静岡県   天竜  40.6    1994-08-04
和歌山県    かつらぎ    40.6    1994-08-08
山梨県   甲府  40.7    2013-08-10
山形県   山形  40.8    1933-07-25
岐阜県   多治見   40.9    2007-08-16
埼玉県   熊谷  40.9    2007-08-16
高知県   江川崎   41  2013-08-12

19. 各行の1コラム目の文字列の出現頻度を求め,出現頻度の高い順に並べる

各行の1列目の文字列の出現頻度を求め,その高い順に並べて表示せよ.確認にはcut, uniq, sortコマンドを用いよ.

19.py
from collections import Counter

# 1列目のデータを取り出し
col1 = [line.split('\t')[0] for line in open('./hightemp.txt')]

# collections.Counterを利用
counter = Counter(col1)
for word,count in counter.most_common():
    print(word+', '+str(count))

# 確認用コマンド
# $ cat ./hightemp.txt  | cut -f 1 | sort | uniq -c | sort -r
$ python 19.py 
埼玉県, 3
山形県, 3
山梨県, 3
群馬県, 3
岐阜県, 2
静岡県, 2
愛知県, 2
千葉県, 2
高知県, 1
和歌山県, 1
愛媛県, 1
大阪府, 1

$ cat ./hightemp.txt  | cut -f 1 | sort | uniq -c | sort -r
      3 山梨県
      3 山形県
      3 埼玉県
      3 群馬県
      2 千葉県
      2 静岡県
      2 岐阜県
      2 愛知県
      1 和歌山県
      1 大阪府
      1 高知県
      1 愛媛県

2017/03/18修正

コメントいただいたので修正

10.py
# リスト内包表記使ってみる
# num_lines = len(list(open('./hightemp.txt')))

# ジェネレータ内包表記
# 1行づつ読み込み、行数カウント
# リスト内包表記のようにリストを作成しないためメモリ使用量が減る
num_lines = sum(1 for line in open('./hightemp.txt'))
print(num_lines)

リスト内包表記ではメモリにファイルデータを一旦すべて載せてしまうし
無駄にリストを作成することになってしまうので
なるべくジェネレータ内包表記を使ったほうがよいらしい

11.py
# リスト内包表記で各行のタブを1文字スペースに変換
space_text = [line.expandtabs(1) for line in open('./hightemp.txt')]

# python3からのprint関数では第2引数にend=""で""内の文字を終端文字として扱える
# end=""だと改行なしとなる
print(''.join(space_text),end='')

print関数の第2引数でend=""を使うと
終端文字を設定できる
変な改行してたのを解消

12.py
# リスト内包表記で各行をタブでスライスして、1列目と2列目をリスト化
# col1 = [line.split('\t')[0] for line in open('./hightemp.txt')]
# col2 = [line.split('\t')[1] for line in open('./hightemp.txt')]

# ジェネレータ内包表記
col1 = '\n'.join(line.split('\t')[0] for line in open('./hightemp.txt'))
col2 = '\n'.join(line.split('\t')[1] for line in open('./hightemp.txt'))

# 書き込みモードでファイルオープン
f1 = open('./col1.txt','w')
f2 = open('./col2.txt','w')

# 改行コードでjoin
f1.write(col1)
f2.write(col2)
14.py
# input()で標準入力受け付けれる
# int()でinteger型に変換
input_num = int(input())

lines = [line for line in open('./hightemp.txt')]

print(''.join(lines[:input_num]))
15.py
# 14と同じ感じ
input_num = int(input())

lines = [line for line in open('./hightemp.txt')]

# スライスおさらい
# 負の数与えると末尾からの順番で扱える
print(''.join(lines[-input_num:]))
16.py
input_num = int(input())

lines = [line for line in open('./hightemp.txt')]

sublist = [''.join(lines[i:i+input_num]) for i in range(0,len(lines),input_num)]

# python結果確認用
for i in sublist:
    print(i)

input = int(input())だとこれ以降input関数使用不可になるため
変数名をinput_numに変更

18.py
# 3列目のリストと、行ごとのリストをとる
values = [line.split('\t')[2] for line in open('./hightemp.txt')]
keys = [line for line in open('./hightemp.txt')]

dic = dict(zip(keys,values))

# 3列目の値でソート
sort_dic = sorted(dic.items(), key=lambda x:x[1])

for k,v in sort_dic:
    print(k,end='')

print(**,end='')で変な改行を消した

19.py
from collections import Counter

# 1列目のデータを取り出し
# col1 = [line.split('\t')[0] for line in open('./hightemp.txt')]
# collections.Counterを利用
# counter = Counter(col1)

# 1行にまとめてジェネレータ内包表記のほうが良い?
counter = Counter(line.split('\t')[0] for line in open('./hightemp.txt'))
for word,count in counter.most_common():
    print(word+', '+str(count))

全体的にファイル読み込み後にリストでの処理を行うの以外は
すべてジェネレータ内包表記に修正した

0
1
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1