Pythonでリスト要素に含まれる単語の頻度を数えることは、特にヒストグラムの分布データを作成する際に、比較的よく行われる作業です。
例えば、リスト ['b', 'b', 'a']
があったとして、”b” が2回、”a” が1回出現しているとします。
このガイドでは、Pythonのリストで単語の出現回数を数える3つの異なる方法を紹介します。
- PandasとNumpyを使用する
- count()`関数を使う。
- Collectionモジュールの
Counter
を使う方法 - ループとカウンタ変数の使用
実際には、Pandas/Numpy、 count()
関数、または Counter
を使うことになるでしょう。
これらはかなり便利に使えるからです。
PandasとNumpyの使用
簡単に操作できるフォーマット(DataFrame
)で値のカウントを取得する最も簡単で短い方法は、NumpyとPandasを利用することです。
リストをNumpyの配列にラップして、 pd
インスタンスの value_counts()
メソッドを呼び出します(これはすべての DataFrame
インスタンスで利用可能です)。
import numpy as np
import pandas as pd
words = ['hello', 'goodbye', 'howdy', 'hello', 'hello', 'hi', 'bye']
pd.value_counts(np.array(words))
この結果、 DataFrame
が生成されます。
hello 3
goodbye 1
bye 1
howdy 1
hi 1
dtype: int64
その values
フィールドにアクセスしてカウント値を取得したり、 index
フィールドにアクセスして単語を取得したりすることができます。
df = pd.value_counts(np.array(words))
print('Index:', df.index)
print('Values:', df.values)
この結果は
Index: Index(['hello', 'goodbye', 'bye', 'howdy', 'hi'], dtype='object')
Values: [3 1 1 1 1]
count()関数の使い方
リスト中の単語の出現回数を得るための「標準的な」方法(外部ライブラリなし)は、リストオブジェクトの count()
関数を使用することです。
count()` メソッドは、要素を唯一の引数として受け取り、その要素がリスト中に何回出現したかを返す組み込み関数です。
count()関数の計算量は O(n) であり、ここで
n` はリストに存在する要素の数である。
以下のコードでは、count()
を使って、リスト中のある単語の出現回数を得ています。
words = ['hello', 'goodbye', 'howdy', 'hello', 'hello', 'hi', 'bye']
print(f'"hello" appears {words.count("hello")} time(s)')
print(f'"howdy" appears {words.count("howdy")} time(s)')
これは、ループを使う前と同じ出力になるはずです。
"hello" appears 3 time(s)
"howdy" appears 1 time(s)
count()`メソッドは、リスト内の各単語の出現回数を簡単に取得する方法を提供します。
コレクションモジュールのカウンターを利用する
Counterクラスのインスタンスは、他のオブジェクトのインスタンスをカウントするために使用することができます。
コンストラクタにリストを渡すと、リスト内のすべての要素とその出現回数の辞書を返すCounter` のインスタンスが生成される。
そこから、ある単語の出現回数を得るには、その単語を辞書のキーとして使用すればよい。
from collections import Counter
words = ['hello', 'goodbye', 'howdy', 'hello', 'hello', 'hi', 'bye']
word_counts = Counter(words)
print(f'"hello" appears {word_counts["hello"]} time(s)')
print(f'"howdy" appears {word_counts["howdy"]} time(s)')
これは、以下のようになります。
"hello" appears 3 time(s)
"howdy" appears 1 time(s)
ループとカウンタ変数を利用する
最終的には、リスト内のすべての単語をループして、単語が見つかったらカウンタを1つ増やし、総単語数を返すという総当たり的な方法が有効です!
もちろん、この方法はリストのサイズが大きくなるにつれて非効率的になりますが、概念的には理解しやすく実装しやすい方法です。
以下のコードでは、この方法を count_occurrence()
メソッドで使用しています。
def count_occurrence(words, word_to_count):
count = 0
for word in words:
if word == word_to_count:
# update counter variable
count = count + 1
return count
words = ['hello', 'goodbye', 'howdy', 'hello', 'hello', 'hi', 'bye']
print(f'"hello" appears {count_occurrence(words, "hello")} time(s)')
print(f'"howdy" appears {count_occurrence(words, "howdy")} time(s)')
このコードを実行すると、次のような出力が得られるはずです。
"hello" appears 3 time(s)
"howdy" appears 1 time(s)
簡単でいいですね。
最も効率的な解決策?
当然ながら、大量の単語コーパスを扱う場合は、最も効率的なソリューションを探すことになります。
これらのソリューションをベンチマークして、そのパフォーマンスを確認しましょう。
タスクは、すべての単語の出現を見つけるか、1つの単語の出現を見つけるかに分けることができます。
import numpy as np
import pandas as pd
import collections
def pdNumpy(words):
def _pdNumpy():
return pd.value_counts(np.array(words))
return _pdNumpy
def countFunction(words):
def _countFunction():
counts = []
for word in words:
counts.append(words.count(word))
return counts
return _countFunction
def counterObject(words):
def _counterObject():
return collections.Counter(words)
return _counterObject
import timeit
words = ['hello', 'goodbye', 'howdy', 'hello', 'hello', 'hi', 'bye']
print("Time to execute:
")
print("Pandas/Numpy: %ss" % timeit.Timer(pdNumpy(words)).timeit(1000))
print("count(): %ss" % timeit.Timer(countFunction(words)).timeit(1000))
print("Counter: %ss" % timeit.Timer(counterObject(words)).timeit(1000))
その結果
Time to execute:
Pandas/Numpy: 0.33886080000047514s
count(): 0.0009540999999444466s
Counter: 0.0019409999995332328s
count()` メソッドは他のメソッドに比べて非常に高速ですが、他の2つのメソッドのようにカウントに関連するラベルを与えてくれません。
もしラベルが必要なら、 Counter
はリストを Numpy 配列でラップしてからカウントするという非効率的な処理よりも優れています。
一方、DataFrameのメソッドを利用することで、ソートや他の方法ではできないような操作を行うことができる。
また、 Counter
にはユニークなメソッドもいくつかある。
最終的には、 Counter
を使って辞書を作成し、その辞書を DataFrame
にすることで、 Counter
の高速性と DataFrame
の多機能性を活用することができる。
df = pd.DataFrame.from_dict([Counter(words)]).T
もし、ラベルが必要ないのであれば、 count()
が最適な方法です。
あるいは、1つの単語を探すのであれば
import numpy as np
import pandas as pd
import collections
def countFunction(words, word_to_search):
def _countFunction():
return words.count(word_to_search)
return _countFunction
def counterObject(words, word_to_search):
def _counterObject():
return collections.Counter(words)[word_to_search]
return _counterObject
def bruteForce(words, word_to_search):
def _bruteForce():
counts = []
count = 0
for word in words:
if word == word_to_search:
# update counter variable
count = count + 1
counts.append(count)
return counts
return _bruteForce
import timeit
words = ['hello', 'goodbye', 'howdy', 'hello', 'hello', 'hi', 'bye']
print("Time to execute:
")
print("count(): %ss" % timeit.Timer(countFunction(words, 'hello')).timeit(1000))
print("Counter: %ss" % timeit.Timer(counterObject(words, 'hello')).timeit(1000))
print("Brute Force: %ss" % timeit.Timer(bruteForce(words, 'hello')).timeit(1000))
という結果になります。
Time to execute:
count(): 0.0001573999998072395s
Counter: 0.0019498999999996158s
Brute Force: 0.0005682000000888365s
ブルートフォースサーチと count()
メソッドは Counter
よりも優れていますが、これは Counter
が本質的に、1つではなくすべての単語をカウントしているためです。
結論
このガイドでは、Pythonのリストで単語の出現を見つけることを探求し、それぞれの解決策の効率を評価し、それぞれがより適している場合を計量しました。