LoginSignup
6
1

More than 5 years have passed since last update.

素人の言語処理100本ノック:19

Last updated at Posted at 2016-10-07

言語処理100本ノック 2015の挑戦記録です。環境はUbuntu 16.04 LTS + Python 3.5.2 :: Anaconda 4.1.1 (64-bit)です。過去のノックの一覧はこちらからどうぞ。

第2章: UNIXコマンドの基礎

hightemp.txtは,日本の最高気温の記録を「都道府県」「地点」「℃」「日」のタブ区切り形式で格納したファイルである.以下の処理を行うプログラムを作成し,hightemp.txtを入力ファイルとして実行せよ.さらに,同様の処理をUNIXコマンドでも実行し,プログラムの実行結果を確認せよ.

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

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

出来上がったコード:

main.py
# coding: utf-8
from itertools import groupby
fname = 'hightemp.txt'

# 都道府県名の読み込み
lines = open(fname).readlines()
kens = [line.split('\t')[0] for line in lines]

# 都道府県で集計し、(都道府県, 出現頻度)のリスト作成
kens.sort()    # goupbyはソート済みが前提
result = [(ken, len(list(group))) for ken, group in groupby(kens)]

# 出現頻度でソート
result.sort(key=lambda ken: ken[1], reverse=True)

# 結果出力
for ken in result:
    print('{ken}({count})'.format(ken=ken[0], count=ken[1]))

実行結果:

端末
埼玉県(3)
山形県(3)
山梨県(3)
群馬県(3)
千葉県(2)
岐阜県(2)
愛知県(2)
静岡県(2)
和歌山県(1)
大阪府(1)
愛媛県(1)
高知県(1)

UNIXコマンド確認用のシェルスクリプト:

test.sh
#!/bin/sh

# 1カラム目でソートし、重複除去して件数付きで出力、その結果をソート
cut --fields=1 hightemp.txt | sort | uniq --count | sort --reverse

結果の確認:

端末
segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/19$ ./test.sh
      3 山梨県
      3 山形県
      3 埼玉県
      3 群馬県
      2 千葉県
      2 静岡県
      2 岐阜県
      2 愛知県
      1 和歌山県
      1 大阪府
      1 高知県
      1 愛媛県

前問同様、出現頻度が同じところの並びは変わってしまうので、書式を合わせてdiffするところまではがんばらず、目視で確認しました。

内包表記

今回初めて内包表記を使ってみました。リストを作成する部分は、なんとか読み書きできるようになってきました。

集計処理

都道府県で集計する部分は、itertools.groupby()を利用しました。確認で使っているUNIXのuniq同様、事前にソートしておく必要があるのが注意点ですね。

問題の解釈の誤り

実は最初、問題の意味を取り違えていて、

各行の1列目の文字列の出現頻度を求め,その高い順に【各行を】並べて表示せよ.

だと思っていました。せっかくなので、そのコードと結果も載せておきます。

出来上がったコード(勘違い版):

main2.py
# coding: utf-8
from itertools import groupby
fname = 'hightemp.txt'


def get_ken(target):
    '''1行分のデータから都道府県部分を切り出す

    引数:
    target -- 1行分のデータ
    戻り値:
    都道府県の文字列
    '''
    return target.split('\t')[0]

# 読み込み
lines = open(fname).readlines()

# 都道府県で集計
lines.sort(key=get_ken)    # goupbyはソート済みが前提
groups = groupby(lines, key=get_ken)

# 集計結果を(都道府県, 出現頻度, 該当行のリスト)のリストに変換
result = []
for ken, group in groups:
    lines = list(group)
    result.append((ken, len(lines), lines))

# 出現頻度でソート
result.sort(key=lambda group: group[1], reverse=True)

# 結果表示
for group in result:
    for line in group[2]:
        print(line, end='')

get_ken()は1カラム目の都道府県を取り出す関数で、sort()groupby()の2箇所で使うのでラムダ式ではなく関数にしました。

実行結果(勘違い版):

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

 
20本目のノックは以上です。誤りなどありましたら、ご指摘いただけますと幸いです。

6
1
0

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
6
1