一组单词中的模式并将它们分组
Pattern in a set of words and group them
我需要在一组 5000 个样本中找出多个词之间的相关性。
样本:-
- 芒果、番石榴、荔枝、苹果
- 芒果、番石榴、荔枝、橙子
- 芒果、番石榴、菠萝、葡萄
- 钢笔、铅笔、书本、复印件、笔记本
- 钢笔、铅笔、书本、复印件、秤
我们看到 1 和 2 彼此非常接近。 3 几乎接近 1 和 2。我们还有 4 和 5 彼此非常接近。
我们可以使用什么方法和技术来检查这种相关性?
提前致谢!
修订:在分组方面也需要帮助,例如 A 组包含第 1、2、3 行,B 组包含第 4 和 5 行。?
这是解决此问题的一种方法。我使用 scikit-learn 将每个列表转换为文档术语矩阵。然后使用 scipy.spacial.distance
.
计算每行之间的余弦相似度矩阵
from sklearn.feature_extraction.text import CountVectorizer
from scipy.spatial import distance
count_vect = CountVectorizer(tokenizer=lambda x: x.split(', '))
ls = ['mango, guava, litchi, apple',
'mango, guava, litchi, orange',
'mango, guava, pineapple, grape',
'pen, pencil, book, copy, notebook',
'pen, pencil, book, copy, scale']
X = count_vect.fit_transform(ls).toarray()
D = distance.cdist(X, X, metric='cosine')
输出是每行之间的距离矩阵。看起来像下面这样:
[[ 0. , 0.25, 0.5 , 1. , 1. ],
[ 0.25, 0. , 0.5 , 1. , 1. ],
[ 0.5 , 0.5 , 0. , 1. , 1. ],
[ 1. , 1. , 1. , 0. , 0.2 ],
[ 1. , 1. , 1. , 0.2 , 0. ]])
例如D[0, 1]
表示第1行靠近第2行,因为两行之间的距离很小。此外,您可以看到 D[3, 4]
很小,这意味着第 4 行接近第 5 行。
注意 你也可以考虑使用 distance.pdist(X, metric='cosine')
给出矩阵的下对角线只是因为下对角线和上对角线是相等的。
分组文件
为了更花哨,您可以使用层次聚类将每一行与计算的距离矩阵聚类在一起。
from scipy.cluster import hierarchy
D = distance.pdist(X, metric='cosine')
Z = hierarchy.linkage(D, metric='euclidean')
partition = hcluster.fcluster(Z, t=0.8, criterion='distance') # [2, 2, 2, 1, 1]
这意味着文档 1、2、3 被分到第 2 组,4、5 被分到第 1 组。如果绘制树状图,您可以看到每一行如何聚集在一起
from scipy.cluster.hierarchy import dendrogram
import matplotlib.pyplot as plt
hierarchy.dendrogram(Z, above_threshold_color='#bcbddc',
orientation='top')
另一种方法,或者可能是解决您问题的新开始的另一种想法:
import re
from itertools import chain
a = ['mango, guava, litchi, apple',
'mango, guava, litchi, orange',
'mango, guava, pineapple, grape',
'pen, pencil, book, copy, notebook',
'pen, pencil, book, copy, scale']
def get_words(lst):
return [re.findall(r'[\w]+', k) for k in a]
def get_percent(lst):
groupped_valid_dict = {}
for k in range(len(lst)):
sub = []
for j in range(k+1, len(lst)):
s = sum([1 if m == n else 0 for m, n in zip(lst[k], lst[j])])
#percent = (1 - float(len(lst[k]) - s)/len(lst[k])) * 100
#fmt = '%.2f%%' % percent
#print 'Words of lines: %d and %d are %s close' %(k+1, j+1, fmt)
if s > 0:
sub.append("Line{}".format(j+1))
if sub:
groupped_valid_dict["Line{}".format(k+1)] = sub
return groupped_valid_dict
lst = get_words(a)
lines = get_percent(lst)
groups = [[k] + lines[k] for k in lines if k not in chain.from_iterable(lines.values())]
groups.sort(key=lambda x: x[0])
for k, v in enumerate(groups, 1):
print "Group%d" %k, v
输出:
Group1 ['Line1', 'Line2', 'Line3']
Group2 ['Line4', 'Line5']
我需要在一组 5000 个样本中找出多个词之间的相关性。
样本:-
- 芒果、番石榴、荔枝、苹果
- 芒果、番石榴、荔枝、橙子
- 芒果、番石榴、菠萝、葡萄
- 钢笔、铅笔、书本、复印件、笔记本
- 钢笔、铅笔、书本、复印件、秤
我们看到 1 和 2 彼此非常接近。 3 几乎接近 1 和 2。我们还有 4 和 5 彼此非常接近。
我们可以使用什么方法和技术来检查这种相关性?
提前致谢!
修订:在分组方面也需要帮助,例如 A 组包含第 1、2、3 行,B 组包含第 4 和 5 行。?
这是解决此问题的一种方法。我使用 scikit-learn 将每个列表转换为文档术语矩阵。然后使用 scipy.spacial.distance
.
from sklearn.feature_extraction.text import CountVectorizer
from scipy.spatial import distance
count_vect = CountVectorizer(tokenizer=lambda x: x.split(', '))
ls = ['mango, guava, litchi, apple',
'mango, guava, litchi, orange',
'mango, guava, pineapple, grape',
'pen, pencil, book, copy, notebook',
'pen, pencil, book, copy, scale']
X = count_vect.fit_transform(ls).toarray()
D = distance.cdist(X, X, metric='cosine')
输出是每行之间的距离矩阵。看起来像下面这样:
[[ 0. , 0.25, 0.5 , 1. , 1. ],
[ 0.25, 0. , 0.5 , 1. , 1. ],
[ 0.5 , 0.5 , 0. , 1. , 1. ],
[ 1. , 1. , 1. , 0. , 0.2 ],
[ 1. , 1. , 1. , 0.2 , 0. ]])
例如D[0, 1]
表示第1行靠近第2行,因为两行之间的距离很小。此外,您可以看到 D[3, 4]
很小,这意味着第 4 行接近第 5 行。
注意 你也可以考虑使用 distance.pdist(X, metric='cosine')
给出矩阵的下对角线只是因为下对角线和上对角线是相等的。
分组文件
为了更花哨,您可以使用层次聚类将每一行与计算的距离矩阵聚类在一起。
from scipy.cluster import hierarchy
D = distance.pdist(X, metric='cosine')
Z = hierarchy.linkage(D, metric='euclidean')
partition = hcluster.fcluster(Z, t=0.8, criterion='distance') # [2, 2, 2, 1, 1]
这意味着文档 1、2、3 被分到第 2 组,4、5 被分到第 1 组。如果绘制树状图,您可以看到每一行如何聚集在一起
from scipy.cluster.hierarchy import dendrogram
import matplotlib.pyplot as plt
hierarchy.dendrogram(Z, above_threshold_color='#bcbddc',
orientation='top')
另一种方法,或者可能是解决您问题的新开始的另一种想法:
import re
from itertools import chain
a = ['mango, guava, litchi, apple',
'mango, guava, litchi, orange',
'mango, guava, pineapple, grape',
'pen, pencil, book, copy, notebook',
'pen, pencil, book, copy, scale']
def get_words(lst):
return [re.findall(r'[\w]+', k) for k in a]
def get_percent(lst):
groupped_valid_dict = {}
for k in range(len(lst)):
sub = []
for j in range(k+1, len(lst)):
s = sum([1 if m == n else 0 for m, n in zip(lst[k], lst[j])])
#percent = (1 - float(len(lst[k]) - s)/len(lst[k])) * 100
#fmt = '%.2f%%' % percent
#print 'Words of lines: %d and %d are %s close' %(k+1, j+1, fmt)
if s > 0:
sub.append("Line{}".format(j+1))
if sub:
groupped_valid_dict["Line{}".format(k+1)] = sub
return groupped_valid_dict
lst = get_words(a)
lines = get_percent(lst)
groups = [[k] + lines[k] for k in lines if k not in chain.from_iterable(lines.values())]
groups.sort(key=lambda x: x[0])
for k, v in enumerate(groups, 1):
print "Group%d" %k, v
输出:
Group1 ['Line1', 'Line2', 'Line3']
Group2 ['Line4', 'Line5']