【问题标题】:Speed up creating a graph from 2.92M data points加快从 2.92M 数据点创建图表
【发布时间】:2014-11-07 05:17:42
【问题描述】:

我在一个 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

【问题讨论】:

  • 向我们展示您的代码?
  • @theTinMan 添加了代码。谢谢。
  • 那台机器上有多少可用内存?您试图在内存中保存 2.92M 数据点,并且每个点占用一个字节。
  • 您真的需要绘制所有 3e6 点吗?一个不错的随机样本应该可以为您提供足够好的眼球图表。
  • 您能否至少将数据存入数据库,在数据库中进行所需的任何准备工作,然后从那里转储 CSV? 3e6 行对于一个像样的数据库来说不算什么。

标签: python ruby graph cluster-analysis networkx


【解决方案1】:
  1. 基准测试。例如使用 Python 自带的 cProfile。在您的代码中很容易出现一些代价高昂的低效率问题,并且在密集型应用程序中它们很容易导致 10 倍的性能成本。

    漂亮的代码如

    (topic_pages_attributes2 & topic_pages_attributes).count
    

    可能会成为运行时的主要因素,可以通过使用更传统的代码轻松减少。

  2. 使用更高效的语言。例如,在benchmarksgame.alioth 中,在一些密集型问题上,最快 Python 3 程序比最快的 C 程序慢 63 倍(Ruby 是 67 倍,JRuby 是 33 倍)。是的,性能差距可能很大,即使是经过优化的 Python 代码也是如此。但是如果你没有优化你的代码,它可能会更大;通过使用更高效的语言并仔细优化您的代码,您或许能够获得 100 倍至 1000 倍的加速。

  3. 考虑更巧妙地表述您的问题。例如,不是遍历每个节点,而是遍历每个 edge 一次。在您的情况下,这可能意味着构建倒排索引、主题-> 页面。这与文本搜索引擎的工作方式非常相似,也是在集群上计算此类操作的一种流行方式:可以在单独的节点上拆分各个主题。这种方法受益于您数据中的稀疏性。 这会大大降低算法的运行时间。

    您有大约 3 个 Mio 文档。从您的总数据量来看,他们平均可能只有不到 100 个主题?您的成对比较方法需要 3mio^2 比较,这会伤害您。如果每个更流行的主题仅用于 30.000 个文档,您可能只需要计算 30k^2 * 个主题即可。假设您有 100 个这样非常受欢迎的主题(稀有主题并不重要),这将是 100 倍的加速。

  4. 简化您的问题。例如,first 通过排序合并所有具有完全相同主题的文档。为了使这更有效,还要消除所有仅出现一次的主题。但可能只有大约 10.000-100.000 个不同的文档。使用排序可以轻松解决此步骤,并使您的问题容易 900-90000 倍(假设上述值范围)。

其中一些数字可能过于乐观 - 例如,根本没有考虑 IO,如果您的问题是 I/O 绑定的,那么使用 C/Java 可能没有多大帮助。可能有一些非常受欢迎的主题可能会损害 C 中讨论的方法。对于 D),您需要 O(n log n) 时间来对数据进行排序;但是对此有很好的实现。但这绝对是您应该做的简化。这些文档还会在您的最终数据中形成完全连接的集团,这也可能会损害其他分析。

【讨论】:

    【解决方案2】:

    我相信大部分时间都花在从磁盘加载数据上。将数据并行读取到多个线程/进程中,然后创建图形。

    您也可以在不同的机器上创建子图,然后再将它们组合起来。

    【讨论】:

    • 如果磁盘 I/O 确实是这里的瓶颈,我看不出创建多个线程从磁盘读取会有什么帮助。
    • @Deepank 即使我在内存中读取图表。我需要处理 2.92M 其他节点的属性来确定是否存在边缘。我在板凳上做了标记,大约需要 4-5 分钟。请详细说明如何将问题简化为子问题并在以后将它们组合起来。
    猜你喜欢
    • 1970-01-01
    • 2017-02-19
    • 2016-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    相关资源
    最近更新 更多