如何对DataFrame每行中的“种类”向量进行检查并更新计数?

时间:2019-05-07 14:11:59

标签: python-3.x pandas optimization vectorization

我已经构造了一些大数据框,它们对应于网络图中的联系人。这些DataFrame的格式是行,其中索引值是图形中节点的唯一标识符,而列1是对应于节点“类型”的整数(您可以将其视为颜色,例如,所有类型1均为红色):

import pandas as pd
df = pd.read_csv( 
    "https://gist.githubusercontent.com/ethanagbaker/98062ebc83b3dd2018a1837d3e3b12df/raw/a59cb7645f6ca935e01a8dea04377da28847c365/testData.csv", 
    skiprows=1, header=None, index_col=0 
) 

第3-24列是与行索引指定的节点共享一条边的节点的ID,其中0表示没有邻居。因此,如果行1中的第3列和第4列具有非零值,则节点1相对于那些指定的节点具有边。第25-32列旨在为索引指定的节点指定每种类型的相邻节点的数量,并初始化为零。下面是此数据的示例:https://imgur.com/LtKRM38。节点1是类型6,具有6个邻居:373、389、175、99、127和167。

我有一些功能代码,它们遍历行,检查指定相邻节点的列,然后在数据框中查找它们的类型,并增加count列。这可以达到预期的效果,但是速度较慢。为了清楚起见,类型n的计数在列n + 24中。在500行的帧上,运行时大约需要4分钟,但是我需要将其扩展到约50,000,000行。我一直在尝试将其修改为使用.apply()或矢量化方法,但还不太清楚该怎么做。这是功能齐全的迭代方法:

def countNeighbors(contactMap):
    for index, row in contactMap.iterrows():
        for col in range(3,25):
            cellID = row[col]
            if cellID == 0:
                break
            else:
                cellType = contactMap[1][cellID]
                contactMap[24+cellType][index] += 1
    return contactMap

#run the function
contactMapCounted = countNeighbors(contactMap)

contactMap是上述矩阵,我已经导出了sample one here。请注意,索引和标头是包含且重要的。将其加载为大熊猫DataFrame应该可以复制它。

我想我只是盯着看了很久才能看到在这里做什么,但是有没有明显的方法可以加快它呢?

可能是相关的编辑:经过更深入的测试,似乎单独使用此功能的速度相当快,但是我以以下方式使用它,这是我发现速度明显下降的地方:

n_shuffles = 100
while s < n_shuffles:
        #print(s)
        contactMap_Shuffled = contactMap.sample(frac=1).reset_index(drop=True)
        contactMap_Shuffled.index += 1
        contactMap_Shuffled.loc[:,25:] = 0  #Reset the count cols
        contactMap_Shuffled = countNeighbors(contactMap_Shuffled)
        s += 1

这旨在使帧的索引随机化,然后按照所述重新计算计数值。这是我最初注意到速度下降的地方,并且我曾假设问题出在countNeighbors()上,但也许是在这里...

1 个答案:

答案 0 :(得分:0)

我没有找到一种向量化countNeighbors()的有效方法,但是通过避免链式索引(请参阅Returning a view versus a copy),可以大致将执行时间减半(见{{3}})。 e。通过更改

                cellType = contactMap[1][cellID]
                contactMap[24+cellType][index] += 1

                cellType = contactMap.at[cellID, 1]
                contactMap.at[index, 24+cellType] += 1