【问题标题】:Efficient way to create a large matrix in python from a table of interactions从交互表中在 python 中创建大型矩阵的有效方法
【发布时间】:2018-12-17 10:12:55
【问题描述】:

我有一个以下结构的 csv 文件,表示“交互”。

我需要将其转换为标准方阵格式,以便我可以使用为图形编写的其他一些函数(使用 igraph)。

我要转换的 CSV 文件有大约 1.06 亿行,格式如下

node1 node2 interaction strength
XYZ   ABC   0.74
XYZ   TAH   0.24
XYZ   ABA   0.3
ABC   TAH   0.42
... (node names are made up to show there is no pattern except node1 is ordered)

我希望这些数据有大约 16K 行和 16K 列的标准格式如下:

    XYZ   ABC   ABA  TAH ...
XYZ 0     0.74  0.3  0
ABC 0.74  0     0    0.42
ABA 0.3   0     0    0
TAH 0     0.42  0    0
.
.
.

我不一定需要最后有一个数据框,但我需要以相同的顺序记录行名和列名,并将这个最终矩阵作为 csv 保存到某个地方。

我尝试的是:

import pandas as pd
import progressbar

def list_uniqify(seq, idfun=None):
    # order preserving
    if idfun is None:
        def idfun(x): return x
    seen = {}
    result = []
    for item in seq:
        marker = idfun(item)
        # in old Python versions:
        # if seen.has_key(marker)
        # but in new ones:
        if marker in seen: continue
        seen[marker] = 1
        result.append(item)
    return result

data = pd.read_csv('./pipelines/cache/fr2/summa_fr2.csv', index_col=0)
names_ordered = helper.list_uniqify( data.iloc[:, 0].tolist() + data.iloc[:, 1].tolist() )

adj = pd.DataFrame(0, index=names_ordered, columns=names_ordered)

bar = progressbar.ProgressBar(maxval=data.shape[0]+1,
                              widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()])
bar.update(0)
bar.start()

print("Preparing output...")
for i in range(data.shape[0]):
    bar.update(i)
    adj.loc[data.iloc[i, 0], data.iloc[i, 1]] = data.iloc[i, 2]
    adj.loc[data.iloc[i, 1], data.iloc[i, 0]] = data.iloc[i, 2]
bar.finish()

print("Saving output...")
adj.to_csv("./data2_fr2.csv")

大约 20-30 分钟后,我只获得了 1%,这意味着这需要大约 2 天,这太长了。

我能做些什么来加快这个过程吗?

注意:我可以并行化这个(8 核,15GB RAM,~130GB SWAP) 但是单核操作需要 15GB RAM,已经有 ~15GB SWAP。我不确定这是否是个好主意。由于没有两个进程会在数据帧的同一个单元格上写入数据,因此我不需要更正竞速条件,对吧?

编辑:以下是建议功能的速度测试,它们比实现的循环要好得多(50K 需要大约 34 秒...)

speeds in seconds for 250K, 500K, 1M rows:
pivot_table: 0.029901999999999873, 0.031084000000000334, 0.0320750000000003
crosstab: 0.023093999999999948, 0.021742999999999846, 0.021409000000000233

【问题讨论】:

    标签: python-3.x performance pandas numpy parallel-processing


    【解决方案1】:

    看看使用pd.crosstab:

    pd.crosstab(df['node1'],df['node2'],df['interaction'],aggfunc='first').fillna(0)
    

    输出:

    node2  ABA   ABC   TAH
    node1                 
    ABC    0.0  0.00  0.42
    XYZ    0.3  0.74  0.24
    

    【讨论】:

    • 您是否知道它的运行速度如此之快?性能提升是惊人的。他们是否只是更改文件的格式而不触及值?
    • 它使用向量化操作并连续使用内存。熊猫/numpy 魔法。我无法更详细地解释它。
    【解决方案2】:

    我认为您只需要 .pivot_table 然后重新索引列(以及更改的行),用 0 填充缺失值。

    import pandas as pd
    
    df2 = (pd.pivot_table(df, index='node1', columns='node2', values='interaction_strength')
             .reindex(df.node1.drop_duplicates())
             .reindex(df.node1.drop_duplicates(), axis=1)
             .fillna(0))
    df2.index.name=None
    df2.columns.name=None
    

    输出:

         XYZ   ABC
    XYZ  0.0  0.74
    ABC  0.0  0.00
    

    【讨论】:

    • 这是你得到的实际输出,因为它不是对称的吗? (我会加速测试这里建议的所有方法并在最后写出结果)
    • @ÖzgenEren 这是基于您提供的示例,它没有node1 = ABCnode2 = XYZ 行,这就是它不对称的原因。但是,如果您只有数据来创建 DataFrame 的上三角形,那么您可以轻松地将其镜像到对角线。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    • 2019-08-26
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多