次のような名前のリストがあります。
names = ['A', 'B', 'C', 'D']
とドキュメントのリスト、各ドキュメントでこれらの名前のいくつかが言及されています。
document =[['A', 'B'], ['C', 'B', 'K'],['A', 'B', 'C', 'D', 'Z']]
次のような共起の行列として出力を取得したいと思います。
A B C D
A 0 2 1 1
B 2 0 2 1
C 1 2 0 1
D 1 1 1 0
Rでのこの問題の解決策( Creating co-occurrence matrix )はありますが、Pythonではできませんでした。私はパンダでそれを行うことを考えていますが、まだ進歩していません!
明らかにこれはあなたの目的のために拡張することができますが、それは一般的な操作を念頭に置いて実行します:
import math
for a in 'ABCD':
for b in 'ABCD':
count = 0
for x in document:
if a != b:
if a in x and b in x:
count += 1
else:
n = x.count(a)
if n >= 2:
count += math.factorial(n)/math.factorial(n - 2)/2
print '{} x {} = {}'.format(a, b, count)
別のオプションは、コンストラクターcsr_matrix((data, (row_ind, col_ind)), [shape=(M, N)])
を scipy.sparse.csr_matrix から使用することです。ここで、data
、row_ind
、およびcol_ind
は、a[row_ind[k], col_ind[k]] = data[k]
の関係を満たします。
トリックは、ドキュメントを反復処理してタプル(doc_id、Word_id)のリストを作成することにより、row_ind
およびcol_ind
を生成することです。 data
は単純に同じ長さのベクトルです。
Docs-words行列にその転置を掛けると、共起行列が得られます。
さらに、これは実行時間とメモリ使用量の両方の点で効率的であるため、大きなコーパスも処理する必要があります。
import numpy as np
import itertools
from scipy.sparse import csr_matrix
def create_co_occurences_matrix(allowed_words, documents):
print(f"allowed_words:\n{allowed_words}")
print(f"documents:\n{documents}")
Word_to_id = dict(Zip(allowed_words, range(len(allowed_words))))
documents_as_ids = [np.sort([Word_to_id[w] for w in doc if w in Word_to_id]).astype('uint32') for doc in documents]
row_ind, col_ind = Zip(*itertools.chain(*[[(i, w) for w in doc] for i, doc in enumerate(documents_as_ids)]))
data = np.ones(len(row_ind), dtype='uint32') # use unsigned int for better memory utilization
max_Word_id = max(itertools.chain(*documents_as_ids)) + 1
docs_words_matrix = csr_matrix((data, (row_ind, col_ind)), shape=(len(documents_as_ids), max_Word_id)) # efficient arithmetic operations with CSR * CSR
words_cooc_matrix = docs_words_matrix.T * docs_words_matrix # multiplying docs_words_matrix with its transpose matrix would generate the co-occurences matrix
words_cooc_matrix.setdiag(0)
print(f"words_cooc_matrix:\n{words_cooc_matrix.todense()}")
return words_cooc_matrix, Word_to_id
実行例:
allowed_words = ['A', 'B', 'C', 'D']
documents = [['A', 'B'], ['C', 'B', 'K'],['A', 'B', 'C', 'D', 'Z']]
words_cooc_matrix, Word_to_id = create_co_occurences_matrix(allowed_words, documents)
出力:
allowed_words:
['A', 'B', 'C', 'D']
documents:
[['A', 'B'], ['C', 'B', 'K'], ['A', 'B', 'C', 'D', 'Z']]
words_cooc_matrix:
[[0 2 1 1]
[2 0 2 1]
[1 2 0 1]
[1 1 1 0]]
from collections import OrderedDict
document = [['A', 'B'], ['C', 'B'], ['A', 'B', 'C', 'D']]
names = ['A', 'B', 'C', 'D']
occurrences = OrderedDict((name, OrderedDict((name, 0) for name in names)) for name in names)
# Find the co-occurrences:
for l in document:
for i in range(len(l)):
for item in l[:i] + l[i + 1:]:
occurrences[l[i]][item] += 1
# Print the matrix:
print(' ', ' '.join(occurrences.keys()))
for name, values in occurrences.items():
print(name, ' '.join(str(i) for i in values.values()))
出力;
A B C D
A 0 2 1 1
B 2 0 2 1
C 1 2 0 1
D 1 1 1 0
itertools
とCounter
モジュールのcollections
クラスを使用する別のソリューションを次に示します。
import numpy
import itertools
from collections import Counter
document =[['A', 'B'], ['C', 'B'],['A', 'B', 'C', 'D']]
# Get all of the unique entries you have
varnames = Tuple(sorted(set(itertools.chain(*document))))
# Get a list of all of the combinations you have
expanded = [Tuple(itertools.combinations(d, 2)) for d in document]
expanded = itertools.chain(*expanded)
# Sort the combinations so that A,B and B,A are treated the same
expanded = [Tuple(sorted(d)) for d in expanded]
# count the combinations
c = Counter(expanded)
# Create the table
table = numpy.zeros((len(varnames),len(varnames)), dtype=int)
for i, v1 in enumerate(varnames):
for j, v2 in enumerate(varnames[i:]):
j = j + i
table[i, j] = c[v1, v2]
table[j, i] = c[v1, v2]
# Display the output
for row in table:
print(row)
出力(DataFrameに変換するのは簡単です)は次のとおりです。
[0 2 1 1]
[2 0 2 1]
[1 2 0 1]
[1 1 1 0]
マトリックストリックを使用して、共起マトリックスを見つけることもできます。あなたがより大きな語彙を持っているときにこれがうまくいくことを願っています。
import scipy.sparse as sp
voc2id = dict(Zip(names, range(len(names))))
rows, cols, vals = [], [], []
for r, d in enumerate(document):
for e in d:
if voc2id.get(e) is not None:
rows.append(r)
cols.append(voc2id[e])
vals.append(1)
X = sp.csr_matrix((vals, (rows, cols)))
これで、X.T
とX
を単純に乗算することで、共起行列を見つけることができます。
Xc = (X.T * X) # coocurrence matrix
Xc.setdiag(0)
print(Xc.toarray())
私は同じ問題に直面していました...それで私はこのコードを手に入れました。このコードは、コンテキストウィンドウを考慮して、co_occurance行列を決定します。
これがあなたに役立つことを願っています...
def countOccurences(Word,context_window):
"""
This function returns the count of context Word.
"""
return context_window.count(Word)
def co_occurance(feature_dict,corpus,window = 5):
"""
This function returns co_occurance matrix for the given window size. Default is 5.
"""
length = len(feature_dict)
co_matrix = np.zeros([length,length]) # n is the count of all words
corpus_len = len(corpus)
for focus_Word in top_features:
for context_Word in top_features[top_features.index(focus_Word):]:
# print(feature_dict[context_Word])
if focus_Word == context_Word:
co_matrix[feature_dict[focus_Word],feature_dict[context_Word]] = 0
else:
start_index = 0
count = 0
while(focus_Word in corpus[start_index:]):
# get the index of focus Word
start_index = corpus.index(focus_Word,start_index)
fi,li = max(0,start_index - window) , min(corpus_len-1,start_index + window)
count += countOccurences(context_Word,corpus[fi:li+1])
# updating start index
start_index += 1
# update [Aij]
co_matrix[feature_dict[focus_Word],feature_dict[context_Word]] = count
# update [Aji]
co_matrix[feature_dict[context_Word],feature_dict[focus_Word]] = count
return co_matrix
'' '2のウィンドウの場合、data_corpusはテキストデータで構成されるシリーズ、wordsは共起行列が作成される単語で構成されるリストです' '
「co_ocは共起行列です」
co_oc=pd.DataFrame(index=words,columns=words)
for j in tqdm(data_corpus):
k=j.split()
for l in range(len(k)):
if l>=5 and l<(len(k)-6):
if k[l] in words:
for m in range(l-5,l+6):
if m==l:
continue
Elif k[m] in words:
co_oc[k[l]][k[m]]+=1
Elif l>=(len(k)-6):
if k[l] in words:
for m in range(l-5,len(k)):
if m==l:
continue
Elif k[m] in words:
co_oc[k[l]][k[m]]+=1
else:
if k[l] in words:
for m in range(0,l+5):
if m==l:
continue
Elif k[m] in words:
co_oc[k[l]][k[m]]+=1
print(co_oc.head())