我需要对一些文本文档进行聚类,并且一直在研究各种选项。看起来LingPipe可以在不进行事先转换(到向量空间等)的情况下聚类纯文本,但这是我见过的唯一明确声明可以在字符串上工作的工具。
有没有可以直接将文本聚类的Python工具?如果没有,处理此问题的最佳方法是什么?
文本聚类的质量主要取决于两个因素:
要群集的文档之间存在一些相似性概念。例如,通过tfidf-cosine-distance可以很容易地区分向量空间中有关体育和政治的新闻报道。根据这种度量,将产品评论分为“好”或“差”的难度要大得多。
聚类方法本身。你知道会有多少个集群吗?好的,使用kmeans。您不关心准确性,但想显示一个不错的树形结构来导航搜索结果吗?使用某种分层群集。
没有文本聚类解决方案,在任何情况下都可以很好地工作。因此,开箱即用一些群集软件并将数据投入其中可能还不够。
话虽如此,这是我一段时间前使用的一些实验性代码来进行文本聚类。这些文档表示为归一化的tfidf向量,而相似度则用余弦距离来衡量。聚类方法本身就是主要聚类。
import sys
from math import log, sqrt
from itertools import combinations
def cosine_distance(a, b):
cos = 0.0
a_tfidf = a["tfidf"]
for token, tfidf in b["tfidf"].iteritems():
if token in a_tfidf:
cos += tfidf * a_tfidf[token]
return cos
def normalize(features):
norm = 1.0 / sqrt(sum(i**2 for i in features.itervalues()))
for k, v in features.iteritems():
features[k] = v * norm
return features
def add_tfidf_to(documents):
tokens = {}
for id, doc in enumerate(documents):
tf = {}
doc["tfidf"] = {}
doc_tokens = doc.get("tokens", [])
for token in doc_tokens:
tf[token] = tf.get(token, 0) + 1
num_tokens = len(doc_tokens)
if num_tokens > 0:
for token, freq in tf.iteritems():
tokens.setdefault(token, []).append((id, float(freq) / num_tokens))
doc_count = float(len(documents))
for token, docs in tokens.iteritems():
idf = log(doc_count / len(docs))
for id, tf in docs:
tfidf = tf * idf
if tfidf > 0:
documents[id]["tfidf"][token] = tfidf
for doc in documents:
doc["tfidf"] = normalize(doc["tfidf"])
def choose_cluster(node, cluster_lookup, edges):
new = cluster_lookup[node]
if node in edges:
seen, num_seen = {}, {}
for target, weight in edges.get(node, []):
seen[cluster_lookup[target]] = seen.get(
cluster_lookup[target], 0.0) + weight
for k, v in seen.iteritems():
num_seen.setdefault(v, []).append(k)
new = num_seen[max(num_seen)][0]
return new
def majorclust(graph):
cluster_lookup = dict((node, i) for i, node in enumerate(graph.nodes))
count = 0
movements = set()
finished = False
while not finished:
finished = True
for node in graph.nodes:
new = choose_cluster(node, cluster_lookup, graph.edges)
move = (node, cluster_lookup[node], new)
if new != cluster_lookup[node] and move not in movements:
movements.add(move)
cluster_lookup[node] = new
finished = False
clusters = {}
for k, v in cluster_lookup.iteritems():
clusters.setdefault(v, []).append(k)
return clusters.values()
def get_distance_graph(documents):
class Graph(object):
def __init__(self):
self.edges = {}
def add_edge(self, n1, n2, w):
self.edges.setdefault(n1, []).append((n2, w))
self.edges.setdefault(n2, []).append((n1, w))
graph = Graph()
doc_ids = range(len(documents))
graph.nodes = set(doc_ids)
for a, b in combinations(doc_ids, 2):
graph.add_edge(a, b, cosine_distance(documents[a], documents[b]))
return graph
def get_documents():
texts = [
"foo blub baz",
"foo bar baz",
"asdf bsdf csdf",
"foo bab blub",
"csdf hddf kjtz",
"123 456 890",
"321 890 456 foo",
"123 890 uiop",
]
return [{"text": text, "tokens": text.split()}
for i, text in enumerate(texts)]
def main(args):
documents = get_documents()
add_tfidf_to(documents)
dist_graph = get_distance_graph(documents)
for cluster in majorclust(dist_graph):
print "========="
for doc_id in cluster:
print documents[doc_id]["text"]
if __name__ == '__main__':
main(sys.argv)
对于真实的应用程序,您将使用适当的令牌生成器,使用整数而不是令牌字符串,并且不计算O(n ^ 2)距离矩阵…
问题内容: 我需要实现scikit-learn的kMeans来对文本文档进行聚类。该示例代码可以正常运行,但需要约20个新闻组数据作为输入。我想使用相同的代码对文档列表进行聚类,如下所示: 要使用此列表作为输入,我需要在kMeans示例代码中进行哪些更改?(仅获取“数据集=文档”无效) 问题答案: 这是一个简单的示例: 向量化文本,即将字符串转换为数字特征 集群文件 打印每个群集的主要术语
问题内容: 所以这是我所拥有的: 现在,即使我使用alert(),我的很长的工具提示文本也没有换行符。它向我显示文本实际上有两行。(不过,它包含一个“ \”,请问如何将其删除?) 我无法在任何地方使用CDATA。 问题答案: SVG 1.1不支持此功能。SVG 1.2确实具有自动换行的元素,但并非在所有浏览器中都实现。SVG 2 并未计划实现,但确实具有自动包装的文本。 但是,鉴于您已经知道换行应
问题内容: 想象一下这个目录结构: 我正在编码,我需要从中导入一些东西。我该怎么办? 我尝试过,但是得到了“未打包的相对导入尝试”。 我四处搜寻,但只发现骇客。有没有一种干净的方法? 问题答案: 每个人似乎都想告诉你应该做什么,而不仅仅是回答问题。 问题是你通过将作为参数传递给解释器而将模块作为运行。 从PEP 328: 相对导入使用模块的属性来确定该模块在包层次结构中的位置。如果模块的名称不包含
问题内容: 我正在尝试获得一个函数,如果您对它进行排序(列表名),它将对该列表中的所有数字进行从最小到最大的排序。 我不确定我的问题是什么,但是我需要一些帮助,因为输出实际上并不是最小到最大,对于输出的前两个数字来说,它最小到最大。 范例: 如果list中有23、212、44个,而不是我对它进行排序,则输出将是这样。 输出: 212,23,44 它 应该是 23、44、212。 码: 更多代码:
问题内容: 我有这个清单 但是现在我希望列表按以下方式排序: 如您所见,无论每个数字具有什么符号,我都希望从高到低排序,但是保持符号清晰吗? 问题答案: 使用的关键功能或:
对于我的网站,我需要为我的应用程序创建下载按钮。但我不知道如何在按钮的文本边距。
我有一些问题在python导入。我不太明白为什么会有错误。 我使用jupyter笔记本从目录笔记本。我需要导入函数位于 对于导入,我尝试使用 正如这里https://docs.python.org/3/reference/import.html(第5.7段)和python显示我一个错误试图相对导入超过顶级包。 包
问题内容: 我使用模块启动一个子流程并连接到它的输出流()。我希望能够在它的标准输出上执行非阻塞读取。在调用之前,是否有方法使不阻塞或检查流中是否有数据?我希望它是可移植的,或者至少在和下工作。 这是我目前的操作方式(如果没有可用数据,则会阻塞): 问题答案: ,,不会在这种情况下帮助。 不管使用什么操作系统,一种可靠的读取流而不阻塞的方法是使用: