Python 如何加快在dataframe列中查找重复项的速度

Python 如何加快在dataframe列中查找重复项的速度,python,pandas,numpy,Python,Pandas,Numpy,我希望找到在dataframe列中出现重复值序列的索引。我希望结果是一个列表列表,其中每个子列表都是重复值索引的单独序列 我当前的代码工作正常,但速度非常慢(对于10000行数据帧中10%的重复,apx为15毫秒): 据我所知,所有的时间都花在to_ranges()的主循环中。我对pandas和numpy比较陌生,有谁能建议一种加速的方法吗?这里有一种快速的方法,可以利用scipy.sparse中的高效操作: from scipy.sparse import csr_matrix def du

我希望找到在dataframe列中出现重复值序列的索引。我希望结果是一个列表列表,其中每个子列表都是重复值索引的单独序列

我当前的代码工作正常,但速度非常慢(对于10000行数据帧中10%的重复,apx为15毫秒):


据我所知,所有的时间都花在to_ranges()的主循环中。我对pandas和numpy比较陌生,有谁能建议一种加速的方法吗?

这里有一种快速的方法,可以利用scipy.sparse中的高效操作:

from scipy.sparse import csr_matrix

def duplicate_ranges(df, c):
    index, values = df.index.values, df[c].values

    data = values
    indices = np.arange(len(values))
    indptr = np.concatenate([[0], np.where(np.diff(values) != 0)[0] + 1,
                             [len(values)]])

    M = csr_matrix((index, indices, indptr))[np.diff(indptr) > 1]
    M.sort_indices()
    return np.split(M.data, M.indptr[1:-1])
它比这里的其他方法快一个数量级,因为它避免了整个数组中的Python循环(尽管
split()
函数中有一些Python循环,只在数组的子集中调用)


旧答案:

以下是解决此问题的快速方法:

df = pd.DataFrame({'A': [1, 2, 3, 3, 3, 2, 1, 1, 2, 2]})

def duplicate_ranges(df, c):
    index, values = df.index.values, df[c].values
    ranges = np.split(index, np.where(np.diff(values) != 0)[0] + 1)
    return [list(r) for r in ranges if len(r) > 1]

duplicate_ranges(df, 'A')
# [[2, 3, 4], [6, 7], [8, 9]]

因为它避免了嵌套循环,只需要一次通过整列,所以它应该比其他方法快得多。

这里有一个快速方法,它利用了scipy.sparse中的高效操作:

from scipy.sparse import csr_matrix

def duplicate_ranges(df, c):
    index, values = df.index.values, df[c].values

    data = values
    indices = np.arange(len(values))
    indptr = np.concatenate([[0], np.where(np.diff(values) != 0)[0] + 1,
                             [len(values)]])

    M = csr_matrix((index, indices, indptr))[np.diff(indptr) > 1]
    M.sort_indices()
    return np.split(M.data, M.indptr[1:-1])
它比这里的其他方法快一个数量级,因为它避免了整个数组中的Python循环(尽管
split()
函数中有一些Python循环,只在数组的子集中调用)


旧答案:

以下是解决此问题的快速方法:

df = pd.DataFrame({'A': [1, 2, 3, 3, 3, 2, 1, 1, 2, 2]})

def duplicate_ranges(df, c):
    index, values = df.index.values, df[c].values
    ranges = np.split(index, np.where(np.diff(values) != 0)[0] + 1)
    return [list(r) for r in ranges if len(r) > 1]

duplicate_ranges(df, 'A')
# [[2, 3, 4], [6, 7], [8, 9]]

因为它避免了嵌套循环,只需要一次通过整列,所以它应该比其他方法快得多。

您这里的代码示例似乎有错误-
df
将在
'a'列中有一个相同的值。
np.random.randint(10,10000)奇怪的是,如果我将行:if v==True:更改为just:if v:,它的速度将提高到8 ms.np.random.randint(10,10000)没有指定大小。可能是版本特定的?np.random.randint(10,size=10000)工作您这里的代码示例似乎有错误-
df
在列
'A'
np.random.randint(10,10000)会生成一个包含10000个范围为0到9的随机整数的列表,如果我更改行:if v==True:to just:if v:,它的速度高达8 ms.np.random.randint(101000)没有指定大小。可能是版本特定的?randint(10,size=10000)工作我非常希望这会快得多,但奇怪的是,它的速度和我的修订版差不多。它还包括每个重复序列的第一个索引,而我的示例没有。但这没什么大不了的,我可以解决它。老实说,我认为忽略第一个索引是一个错误:)如果希望与结果匹配,可以将最后一行更改为
[list(r[1:]),用于范围内的r。我认为糟糕的速度来自于对列表的理解。。。也许有一种方法可以解决这个问题……我添加了一种使用
scipy.sparse
的方法,以避免循环/分块数组的开销。我非常希望这会快得多,但奇怪的是,它的速度与我的修订版差不多。它还包括每个重复序列的第一个索引,而我的示例没有。但这没什么大不了的,我可以解决它。老实说,我认为忽略第一个索引是一个错误:)如果希望与结果匹配,可以将最后一行更改为
[list(r[1:]),用于范围内的r。我认为糟糕的速度来自于对列表的理解。。。可能有一种解决方法……我添加了一种使用
scipy.sparse
的方法,以避免循环/分块数组的开销。