我在一个 3.0GB 的 CSV 文件中有 292 万个数据点,我需要遍历它两次以创建一个我想加载到 NetworkX 中的图形。按照目前的速度,生成这张图需要几天时间。我怎样才能加快速度?
similarity = 8
graph = {}
topic_pages = {}
CSV.foreach("topic_page_node_and_edge.csv") do |row|
topic_pages[row[0]] = row[1..-1]
end
CSV.open("generate_graph.csv", "wb") do |csv|
i = 0
topic_pages.each do |row|
i+=1
row = row.flatten
topic_pages_attributes = row[1..-1]
graph[row[0]] = []
topic_pages.to_a[i..-1].each do |row2|
row2 = row2.flatten
topic_pages_attributes2 = row2[1..-1]
num_matching_attributes = (topic_pages_attributes2 & topic_pages_attributes).count
if num_matching_attributes >= similarity or num_matching_attributes == topic_pages_attributes2.count or num_matching_attributes == topic_pages_attributes.count
graph[row[0]].push(row2[0])
end
end
csv << [row[0], graph[row[0]]].flatten
end
end
请您参考如下方法:
基准。例如使用 Python 附带的 cProfile。在您的代码中很容易出现一些代价高昂的低效问题,而且它们很容易在密集型应用程序中以 10 倍的性能成本出现。
漂亮的代码如
(topic_pages_attributes2 & topic_pages_attributes).count
可能最终证明是您运行时的一个主要因素,可以通过使用更传统的代码轻松减少。
使用更高效的语言。例如在 benchmarksgame.alioth ,在许多密集型问题上,最快 Python 3 程序的平均速度比最快的 C 程序慢 63 倍(Ruby 为 67 倍,JRuby 为 33 倍)。是的,性能差距可能很大,即使使用优化良好的 Python 代码也是如此。但是如果你没有优化你的代码,它可能会更大;通过使用更高效的语言并仔细优化您的代码,您可能可以获得 100 到 1000 倍的加速。
考虑更巧妙地表述您的问题。例如,不是遍历每个节点,而是遍历每个边一次。在你的情况下,这可能意味着建立一个倒排索引,主题 ->页面。这与文本搜索引擎的工作方式非常相似,也是在集群上计算此类操作的一种流行方式:可以在单独的节点上拆分各个主题。这种方法受益于数据的稀疏性。 这可以大大缩短算法的运行时间。
您有大约 3 个 Mio 文档。从你的总数据量来看,他们平均大概只有不到100个topic吧?您的成对比较方法需要 3mio^2 比较,这会伤害您。如果更受欢迎的主题每个仅用于 30.000 个文档,则您可能只需计算 30k^2 * 主题数即可。假设您有 100 个非常受欢迎的主题(稀有主题无关紧要),这将是 100 倍的加速。
简化您的问题。例如,首先通过排序合并具有完全相同主题的所有文档。为了使这更有效,还要消除所有只出现一次的主题。但可能只有大约 10.000-100.000 个不同的集合文档。使用排序可以轻松解决此步骤,并将使您的问题简单 900-90000 倍(假设高于值范围)。
其中一些数字可能过于乐观 - 例如,根本没有考虑 IO,如果您的问题受 I/O 限制,使用 C/Java 可能帮不上什么忙。可能有一些非常流行的主题可能会损害 C 中讨论的方法。对于 D),您需要 O(n log n) 时间来对数据进行排序;但是对此有很好的实现。但这绝对是您应该做的简化。这些文档还将在您的最终数据中形成完全连接的派系,这也可能会影响其他分析。