从交互表在python中创建大型矩阵的有效方法

时间:2018-07-09 16:47:46

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

我在以下结构中有一个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

2 个答案:

答案 0 :(得分:2)

看看使用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

答案 1 :(得分:1)

我认为您只需要.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