PythonのCounterでリストの各要素の出現個数をカウント
Pythonでリストやタプルの全要素の個数は組み込み関数len()
、各要素の個数(要素ごとの出現回数)はcount()
メソッドで取得できる。さらに、Python標準ライブラリcollectionsのCounter
クラスを使うと、出現回数が多い順に要素を取得可能。
サンプルはリストだが、タプルでも同様の処理が可能。
文字列に含まれる特定の文字・文字列の数をカウントしたい場合は以下の記事を参照。
- 関連記事: Pythonで文字・文字列の出現回数をカウント
全要素数をカウント: len()
リストやタプルの全要素数をカウントするには、組み込み関数len()
を使う。
l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']
print(len(l))
# 7
各要素の個数(要素ごとの出現回数)をカウント: count()メソッド
各要素の個数(要素ごとの出現回数)をカウントするには、リストやタプルなどのcount()
メソッドを使う。
要素として存在しない値を引数に渡すと0
が返る。
l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']
print(l.count('a'))
# 4
print(l.count('b'))
# 1
print(l.count('c'))
# 2
print(l.count('d'))
# 0
各要素の出現回数を一括で取得したい場合は次のcollections.Counter
が便利。
collections.Counterの使い方
Python標準ライブラリcollectionsにCounter
クラスがある。
collections.Counter()
にリストやタプルを渡すと、Counter
オブジェクトが生成される。Counter
は辞書型dict
のサブクラスで、キーに要素、値に出現回数という形のデータを持つ。
import collections
l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']
c = collections.Counter(l)
print(c)
# Counter({'a': 4, 'c': 2, 'b': 1})
print(type(c))
# <class 'collections.Counter'>
print(issubclass(type(c), dict))
# True
キーとして要素を指定するとその個数を取得できる。要素として存在しない値を指定すると0を返す。
print(c['a'])
# 4
print(c['b'])
# 1
print(c['c'])
# 2
print(c['d'])
# 0
keys()
, values()
, items()
などの辞書型のメソッドも使える。
print(c.keys())
# dict_keys(['a', 'b', 'c'])
print(c.values())
# dict_values([4, 1, 2])
print(c.items())
# dict_items([('a', 4), ('b', 1), ('c', 2)])
これらのメソッドはdict_keys
型などのオブジェクトを返す。for文で回したりする場合はそのまま使用できる。リストに変換したい場合はlist()
を使えばよい。
出現回数順に要素を取得: most_common()メソッド
Counter
にはmost_common()
メソッドがあり、(要素, 出現回数)
という形のタプルを出現回数順に並べたリストを返す。
l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']
c = collections.Counter(l)
print(c)
# Counter({'a': 4, 'c': 2, 'b': 1})
print(c.most_common())
# [('a', 4), ('c', 2), ('b', 1)]
出現回数が最も多いものは[0]
、最も少ないものは[-1]
のようにインデックスを指定して取得できる。要素だけ、出現回数だけを取得したい場合はさらにインデックスを指定すればOK。
print(c.most_common()[0])
# ('a', 4)
print(c.most_common()[-1])
# ('b', 1)
print(c.most_common()[0][0])
# a
print(c.most_common()[0][1])
# 4
出現回数の少ない順に並べ替えたい場合は増分を-1
としたスライスを使う。
print(c.most_common()[::-1])
# [('b', 1), ('c', 2), ('a', 4)]
most_common()
メソッドに引数n
を指定すると、出現回数の多いn
個の要素のみを返す。省略するとすべての要素。
print(c.most_common(2))
# [('a', 4), ('c', 2)]
(要素, 出現回数)
のタプルではなく、出現回数順に並べた要素・出現回数のリストが個別に欲しい場合は、以下のようにして分解できる。
values, counts = zip(*c.most_common())
print(values)
# ('a', 'c', 'b')
print(counts)
# (4, 2, 1)
組み込み関数zip()
を利用して二次元リスト(ここではタプルのリスト)を転置して、アンパックして取り出している。詳しくは以下の記事を参照。
重複しない要素(一意な要素)の個数(種類)をカウント
リストやタプルに重複しない要素(一意な要素)が何個あるか(何種類あるか)をカウントする場合、上述のCounter
かset()
を使う。
Counter
オブジェクトの要素数が元のリストの重複しない要素の個数に等しい。Counter
オブジェクトの要素数はlen()
で取得できる。
l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']
c = collections.Counter(l)
print(len(c))
# 3
集合型set
のコンストラクタset()
も使える。Counter
オブジェクトが必要ない場合はこちらのほうが楽。
set
型は重複した要素をもたないデータ型で、set()
にリストを渡すと重複する値は無視されて一意な値のみが要素となるset
型のオブジェクトを返す。これの要素数をlen()
で取得する。
print(set(l))
# {'a', 'c', 'b'}
print(len(set(l)))
# 3
リストの重複要素の判定や抽出・削除については以下の記事を参照。
条件を満たす要素の個数をカウント
リストやタプルに特定の条件を満たす要素が何個あるかカウントするには、リスト内包表記またはジェネレーター式を利用する。
- 関連記事: Pythonリスト内包表記の使い方
例として、以下の数値のリストに対して負の値の要素の数をカウントする。
l = list(range(-5, 6))
print(l)
# [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]
各要素に対してリスト内包表記で条件式を適用すると、ブール型bool
(True
, False
)を要素とするリストが得られる。ブール型bool
は整数型int
のサブクラスで、True
は1
、False
は0
として扱われるため、sum()
で合計を算出するとTrue
の個数(条件を満たす要素の個数)がカウントできる。
print([i < 0 for i in l])
# [True, True, True, True, True, False, False, False, False, False, False]
print(sum([i < 0 for i in l]))
# 5
ここで、リスト内包表記の[]
を()
に置き換えるとジェネレーター式となる。リスト内包表記は全要素を処理したリストを生成するのに対して、ジェネレータ式は要素を逐次処理していくため、メモリ効率がよい。
ジェネレーター式を唯一の引数とするときは()
を省略できるため、後者のように書ける。
print(sum((i < 0 for i in l)))
# 5
print(sum(i < 0 for i in l))
# 5
False
の数(条件を満たさない要素の数)をカウントしたい場合はnot
を使う。なお、>
のほうがnot
より優先順位が高い(先に演算される)ので、以下の例の(i < 0)
の括弧()
はなくてもよい。
print([not (i < 0) for i in l])
# [False, False, False, False, False, True, True, True, True, True, True]
print(sum(not (i < 0) for i in l))
# 6
もちろん、条件そのものを変えてもよい。
print(sum(i >= 0 for i in l))
# 6
その他の例をいくつか示す。
数値のリストに対して奇数の要素の数を取得する例。
print([i % 2 == 1 for i in l])
# [True, False, True, False, True, False, True, False, True, False, True]
print(sum(i % 2 == 1 for i in l))
# 6
文字列のリストに対する条件の例。
l = ['apple', 'orange', 'banana']
print([s.endswith('e') for s in l])
# [True, True, False]
print(sum(s.endswith('e') for s in l))
# 2
出現回数の条件でカウントする場合はcollections.Counter
を使う。items()
で(要素, 出現回数)
のタプルを取得し、出現回数で条件を指定する。
出現回数が2個以上の要素を抽出する例と、その総数をカウントする例。この例の場合、a
が4個、c
が2個で計6個。
l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']
c = collections.Counter(l)
print(c.items())
# dict_items([('a', 4), ('b', 1), ('c', 2)])
print([i for i in l if c[i] >= 2])
# ['a', 'a', 'a', 'a', 'c', 'c']
print([i[1] for i in c.items() if i[1] >= 2])
# [4, 2]
print(sum(i[1] for i in c.items() if i[1] >= 2))
# 6
出現回数が2個以上の要素の種類を抽出する例と、その数をカウントする例。この例の場合、a
とc
の2種類。
print([i[0] for i in c.items() if i[1] >= 2])
# ['a', 'c']
print([i[1] >= 2 for i in c.items()])
# [True, False, True]
print(sum(i[1] >= 2 for i in c.items()))
# 2
文字列の単語の出現個数をカウント
具体的な例として、文字列に登場する単語の出現個数を数えてみる。
まず、不必要なカンマ,
や.
をreplace()
メソッドで空文字列と置換し、削除する。さらにsplit()
メソッドで空白で区切ってリスト化する。
s = 'government of the people, by the people, for the people.'
s_remove = s.replace(',', '').replace('.', '')
print(s_remove)
# government of the people by the people for the people
word_list = s_remove.split()
print(word_list)
# ['government', 'of', 'the', 'people', 'by', 'the', 'people', 'for', 'the', 'people']
リスト化できれば、各単語の出現回数や出現する単語の種類を取得したり、collections.Counter
のmost_common()
で最も出現回数の多い単語を取得したりできる。
print(word_list.count('people'))
# 3
print(len(set(word_list)))
# 6
c = collections.Counter(word_list)
print(c)
# Counter({'the': 3, 'people': 3, 'government': 1, 'of': 1, 'by': 1, 'for': 1})
print(c.most_common()[0][0])
# the
以上はごくごくシンプルな処理なので、より複雑な自然言語処理にはNLTKなどのライブラリを利用するほうがいい。
また、日本語のテキストの場合は単語の区切りがはっきりしていないのでsplit()
では分割できない。例えばJanomeというライブラリを使うと実現可能。以下の記事を参照。
文字列の文字の出現個数をカウント
文字列もシーケンス型なので、count()
メソッドを使ったり、collections.Counter()
のコンストラクタの引数に渡したりすることができる。
s = 'supercalifragilisticexpialidocious'
print(s.count('p'))
# 2
c = collections.Counter(s)
print(c)
# Counter({'i': 7, 's': 3, 'c': 3, 'a': 3, 'l': 3, 'u': 2, 'p': 2, 'e': 2, 'r': 2, 'o': 2, 'f': 1, 'g': 1, 't': 1, 'x': 1, 'd': 1})
出現回数の多い文字トップ5を取得する例。
print(c.most_common(5))
# [('i', 7), ('s', 3), ('c', 3), ('a', 3), ('l', 3)]
values, counts = zip(*c.most_common(5))
print(values)
# ('i', 's', 'c', 'a', 'l')