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

2章です
コードは[github](https://github.com/tomoyaRed/python100)にあげるようにしました。

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

```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
# リスト内包表記で各行のタブを１文字スペースに変換
space_text = [line.expandtabs(1) for line in open('./hightemp.txt')]
[print(line) for line in space_text]

# 確認用コマンド
# $ cat ./hightemp.txt | tr '\t' ' '
```

```11実行結果
$ 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
# リスト内包表記で各行をタブでスライスして、１列目と２列目をリスト化
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
```

```12実行結果
$ 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つのリストをタブで連結、改行コードを削除を１行として
# 最後に改行いれて次の行へ
for col in zip(col1, col2):
    new_file.write('\t'.join(col).replace('\n',''))
    new_file.write('\n')

# 確認用コマンド
# $ paste ./col1.txt ./col2.txt
```

```13結果
$ 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
```

```14結果
$ 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
```

```15結果
$ 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 
```

```16結果
$ 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列目の文字列の種類（異なる文字列の集合）を求めよ．確認にはsort, uniqコマンドを用いよ．

```17.py
# １列目のデータを取り出し
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
```

```17結果
$ 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))

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

for k,v in sort_dic:
    print(k)

# 確認用コマンド
# $ cat hightemp.txt |  sort -k3
```

```18結果
$ 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

# １列目のデータを取り出し
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
```

```19結果
$ 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
# リスト内包表記で各行のタブを１文字スペースに変換
space_text = [line.expandtabs(1) for line in open('./hightemp.txt')]

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

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

```12.py
# リスト内包表記で各行をタブでスライスして、１列目と２列目をリスト化
# 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))

# ３列目の値でソート
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

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

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

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