〜言語処理100本ノック No.15-19〜

## はじめに

[言語処理100本ノック 2015](http://www.cl.ecei.tohoku.ac.jp/nlp100/#)という素敵教材をド素人が挑戦していく記事です。

道のり
[〜言語処理100本ノック No.00-04〜](https://qiita.com/ITNewcomer/items/a440b7bd01dcce194040)
[〜言語処理100本ノック No.05-09〜](https://qiita.com/ITNewcomer/items/60613e4ff0ea706c95e0)
[〜言語処理100本ノック No.10-14〜](https://qiita.com/ITNewcomer/items/4c3a6c58de87abe629f1)

## 環境

Mac OS X 10.14.5
Python 3.7.1

## 準備

* 「hightemp.txt」というテキストがサイトに用意してあるので、ローカルに配置します。

## 15. 末尾のN行を出力

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

### Pythonで実行

```python:15.py
# python 15.py hightemp.txt 3

import sys
# ファイルの読み込み
f = open(sys.argv[1], 'r').readlines()

# 末尾何行を出力するのかの引数格納
line_num = 0
line_num = int(sys.argv[2])

# 末尾N行出力
for line in (f[len(f) - line_num:len(f)]):
    print(line,end="")
```

### 確認(Linuxコマンド)

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

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

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

### Pythonで実行

```python:16.py
# python 16.py hightemp.txt 7

import sys
# ファイルの読み込み
f = open(sys.argv[1], 'r').readlines()
#　ファイルの行数の確認
text_linesize = len(f)

# 何行ずつに区切るのか引数の格納
line_num = 0
line_num = int(sys.argv[2])
file_num = 1
# 末尾N行出力
for i in range(0,len(f),line_num):
    file_name = 'output/chap_2_16_python_'+str(file_num)
    fnew = open (file_name, 'w')
    for x in f[i:i+line_num]:
        fnew.write(str(x))
    fnew.close()
    file_num += 1

# ls output/chap_2_16_python_*
# output/chap_2_16_python_1  output/chap_2_16_python_2  output/chap_2_16_python_3  output/chap_2_16_python_4
```

### 確認(Linuxコマンド)

```bash
# -l で何行ずつ区切るか
# ファイル名のあとに指定した名前でファイルが作成される(末尾にa,bとついていく)。
# ファイル名は変更できる
$ split -l 7 hightemp.txt chap_2_16_linux_
$ ls -l chap_2_16_linux_a*
-rw-r--r--  1 itnewcomer  staff  244  6 27 23:20 chap_2_16_linux_aa
-rw-r--r--  1 itnewcomer  staff  237  6 27 23:20 chap_2_16_linux_ab
-rw-r--r--  1 itnewcomer  staff  230  6 27 23:20 chap_2_16_linux_ac
-rw-r--r--  1 itnewcomer  staff  102  6 27 23:20 chap_2_16_linux_ad
$ cat chap_2_16_linux_aa 
高知県  江川崎  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
$ cat chap_2_16_linux_ad
山梨県  大月    39.9    1990-07-19
山形県  鶴岡    39.9    1978-08-03
愛知県  名古屋  39.9    1942-08-02
```

## 17. １列目の文字列の異なり

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

### Pythonで実行

```python:17.py
# python 17.py hightemp.txt

import sys

print("17. １列目の文字列の異なり")

# ファイルの読み込み
f = open(sys.argv[1], 'r').readlines()

# リストの初期化
word_list = list()

# 1列目のみをリスト化
for line in f:
    word_list.append(line.split()[0])

# 集合にする
word_list = set(word_list)

# 表示
print(word_list)
```

### 確認(Linuxコマンド)

```bash
# -f　何列目か
# -d 区切り文字の指定
$ cut -f 1 -d "$(printf "\t")" hightemp.txt | sort |uniq 
千葉県
埼玉県
大阪府
山形県
山梨県
岐阜県
愛媛県
愛知県
群馬県
静岡県
高知県
和歌山県
```

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

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

### Pythonで実行

```python:18.py
# python 18.py hightemp.txt

import sys
from operator import itemgetter

# ファイルの読み込み
f = open(sys.argv[1], 'r').readlines()

# 多次元配列の作成
my_list = list()
for line in f:
    my_list.append(line.split())

# operatorモジュールを使用
# keyにソートしたい要素を指定

print(sorted(my_list, key=itemgetter(2),reverse=True))

# [
# ['高知県', '江川崎', '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']
# ]
```

### 確認(Linuxコマンド)

```bash
# -k keyとなる列
# -t 区切り文字
# -r reverse
$ sort -k 3 -t "$(printf "\t")" -r hightemp.tx
高知県  江川崎  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
```

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

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

### Pythonで実行

```python:19.py
# python 19.py hightemp.txt 

import collections
import sys

# ファイルの読み込み
f = open(sys.argv[1], 'r').readlines()

# リストの初期化
word_list = list()

# 1列目のみをリスト化
for line in f:
    word_list.append(line.split()[0])

# Python標準ライブラリcollectionsにCounterクラスを利用
c = collections.Counter(word_list)
print(c)

# Counter({'埼玉県': 3, '山形県': 3, '山梨県': 3, '群馬県': 3, '岐阜県': 2, '静岡県': 2, '愛知県': 2, '千葉県': 2, '高知県': 1, '和歌山県': 1, '愛媛県': 1, '大阪府': 1})
```

### 確認(Linuxコマンド)

```bash
# -f 切り出す列番指定
# -d 区切り文字の指定
# uniq -c で各要素が何個あるか出せる
# sort -n 数値として並び替える
# sort -r 降順
$ cut -f 1 -d "$(printf "\t")" hightemp.txt | sort |uniq -c |sort -nr
  3 群馬県
  3 山梨県
  3 山形県
  3 埼玉県
  2 静岡県
  2 愛知県
  2 岐阜県
  2 千葉県
  1 和歌山県
  1 高知県
  1 愛媛県
  1 大阪府
```

## 最後に

今回は結構時間かかりました。
Linuxは普段文字列操作系はあまり使わないので、色々調べて楽しかったのです。
なにかお気づきの点あればコメントいただけると幸いです。