python collections.counter

Python学習【365日チャレンジ!】277日目のマスターU(@Udemy11)です。

ビリギャルの坪田先生の「才能の正体」をAudibleでずーっと聴いているのですが、読まなくても本が読めるという不思議な感覚を体験できるので、超お勧めですよ。

で、この本の中で紹介されている「ゲーム理論」のことを詳しく知りたくなって、図書館でゲーム理論に関する本をたくさん借りてきたのですが、ちょっと理解するのが難しくて頭がこんがらがっています。

期待値とかが関係してきたり、複雑な条件が入ってくると、若干思考停止状態に誘われてしまいます。

ただでさえ、酒井さんのPython講座も難しくなってきて、頭の中がオーバーヒート気味なので、すべてを忘れて海でのんびり餌釣りでもしたい気分です。

それでは今日も、Python学習を始めましょう。

昨日の復習

昨日は、intだけでなくsetでも使えるdefaultdictを学習しました。

集合は、リストなどに含まれる値の重複をまとめて同じ種類にまとめてくれましたが、defaultdictを使って、辞書型データのkeyが同じでvalueが違うものは、順番を保持してvalueを追加したり、keyvalueも違うものは、key-valueを追加したりすることができました。

くわしくは昨日の記事をごらんください。

今日は、文字をカウントしていろいろ便利に活用できるcollections.Counterを学習します。

Counter

Counterは、defaultdictと同じようにリストに含まれる値を集計することができます。

昨日のコードも活用して、Counterで同じような出力をするコードを書いてみます。

import collections

d = {}
l = ['a', 'a', 'a', 'b', 'b', 'c']
for word in l:
    if word not in d:
        d[word] = 0
    d[word] += 1
print(d)

d = {}
l = ['a', 'a', 'a', 'b', 'b', 'c']
for word in l:
    d.setdefault(word, 0)
    d[word] += 1
print(d)

d = collections.defaultdict(int)
l = ['a', 'a', 'a', 'b', 'b', 'c']
for word in l:
    d[word] += 1
print(d)

c = collections.Counter()
l = ['a', 'a', 'a', 'b', 'b', 'c']
for word in l:
    c[word] += 1
print(c)
print(c.most_common(2))
print(c.values())
print(sum(c.values()))

22行目までは昨日と同じコードで、24行目からのハイライトしている部分が追加したcollections.Counterのコードです。

出力した結果は次のようになります。

出力結果

{'a': 3, 'b': 2, 'c': 1}
{'a': 3, 'b': 2, 'c': 1}
defaultdict(, {'a': 3, 'b': 2, 'c': 1})
Counter({'a': 3, 'b': 2, 'c': 1})
[('a', 3), ('b', 2)]
dict_values([3, 2, 1])
6

最初の3行は昨日のコードの出力で、forループとif文を使ったものとsetdefaultを使ったものとdefaultdictを使ったコードの出力です。

出力の4行目は、新しく追加したコード28行目print(c)の出力で、Counterオブジェクトとして、上記の3行と同じ値が保持されています。

コードの29行目は、most_common(2)を使って保持している値のランキング上位2つを返して出力しています。

30行目は、values()Counterオブジェクトに保持している辞書型データのvalueだけを抽出して出力しています。

最後に、values()で抽出した値をsum()で合計して出力しています。

文字列を抽出

今回コードを記述したファイルはlesson5.pyという名前なので、このファイルを読み込んで、含まれる文字列を抽出してみます。

import re
with open('lesson5.py', 'r') as f:
    words = re.findall(r'\w+', f.read().lower())
    print(words)
    print(collections.Counter(words).most_common(20))

出力結果

['import', 'collections', 'd', 'l', 'a', 'a', 'a', 'b', 'b', 'c', 'for', 'word', 'in', 'l', 'if', 'word', 'not', 'in', 'd', 'd', 'word', '0', 'd', 'word', '1', 'print', 'd', 'd', 'l', 'a', 'a', 'a', 'b', 'b', 'c', 'for', 'word', 'in', 'l', 'd', 'setdefault', 'word', '0', 'd', 'word', '1', 'print', 'd', 'd', 'collections', 'defaultdict', 'int', 'l', 'a', 'a', 'a', 'b', 'b', 'c', 'for', 'word', 'in', 'l', 'd', 'word', '1', 'print', 'd', 'c', 'collections', 'counter', 'l', 'a', 'a', 'a', 'b', 'b', 'c', 'for', 'word', 'in', 'l', 'c', 'word', '1', 'print', 'c', 'print', 'c', 'most_common', '2', 'print', 'c', 'values', 'print', 'sum', 'c', 'values', 'import', 're', 'with', 'open', 'main', 'py', 'r', 'as', 'f', 'words', 're', 'findall', 'r', 'w', 'f', 'read', 'lower', 'print', 'words', 'print', 'collections', 'counter', 'words', 'most_common', '20']
[('d', 12), ('a', 12), ('word', 11), ('c', 10), ('print', 9), ('l', 8), ('b', 8), ('in', 5), ('collections', 4), ('for', 4), ('1', 4), ('words', 3), ('import', 2), ('0', 2), ('counter', 2), ('most_common', 2), ('values', 2), ('re', 2), ('r', 2), ('f', 2)]

本来は先頭からライブラリをインポートしますが、便宜上、33行目でreをインポートしています。

34行目でwithステートメントを使いlesson5.pyを開いてfに代入し、35行目でre.findallを使って、開いたファイル(lesson5.py)を読み込んで小文字にしたデータの中から\w+(最初の文字が任意の英数字で始まるパターン)で値を抽出してwordsに入れ、36行目で出力しています。

37行目は、先ほどやったCountermost.commonを使って数の多い値順に20個を出力しています。

まとめ

collection.Counterを使って値を抽出したり、加工したりして、いろいろな使い方ができました。

こんなことができるということがわかっても、なかなか具体的な使い方がイメージできません。

Pythonを学習するのは、Pythonを使って、何かを作り出すためなので、Python学習が目的になってしまっては本末転倒です。

とはいえ、Pythonの基礎基本を学習しないと実践では役に立ちません。

私の場合は、Python学習365日チャレンジを一つ目の目標にしているので、1年はしっかりとPythonの基礎基本を学習しようと思っていますが、ある程度Pythonの知識が身についてきたら、実践的なプログラムに取り組み出した方がPythonスキルが上がるような気がします。

気持ち的にはそろそろ具体的なプログラムに取りかかった方がいいのかな~なんて思うときがあるんですけどね。。。

それでは、明日もGood Python!