Python 计算numpy列表中项目的精确同时出现次数

Python 计算numpy列表中项目的精确同时出现次数,python,numpy,Python,Numpy,我试图找出最快的方法来计算两个值在numpy列表中一个接一个地被定位的时间 例如: list=[1,5,4,1,2,4,6,7,2,1,3,3,1,2] 我想计算值1跟在值2后面的次数(但不是相反) 在上面的例子中,答案应该是1,因为1只跟随2一次 很明显,我可以通过一个简单的for循环得出答案,每当项目I等于1和项目I-1等于2时,该循环就会添加到计数器中,但我觉得必须有一种更快的方法来实现 谢谢您可以使用和: 返回1 大型阵列上的计时: 在一个小列表中,迭代方法和numpy方法之间的时间差不

我试图找出最快的方法来计算两个值在numpy列表中一个接一个地被定位的时间

例如:

list=[1,5,4,1,2,4,6,7,2,1,3,3,1,2]
我想计算值
1
跟在值
2
后面的次数(但不是相反)

在上面的例子中,答案应该是
1
,因为
1
只跟随
2
一次

很明显,我可以通过一个简单的for循环得出答案,每当项目
I
等于
1
和项目
I-1
等于
2
时,该循环就会添加到计数器中,但我觉得必须有一种更快的方法来实现

谢谢

您可以使用和:

返回
1

大型阵列上的计时

在一个小列表中,迭代方法和
numpy
方法之间的时间差不会明显。但是在大型阵列上,如下面的示例所示,
numpy
的性能要好得多

import timeit

mylist = np.random.choice(range(0,9), 1000000)

def np_method(mylist = mylist):
    return np.sum((mylist[:-1] == 2) & (np.diff(mylist) == -1))

def zip_loop(a = mylist):
    return len( [1 for i,j in zip(a, a[1:]) if i == 2 and j == 1] )

def for_loop(list1 = mylist):
    count=0
    desired_num=2
    follower_num=1
    for i in range(len(list1)-1):
        if list1[i]==desired_num:
            if list1[i+1]==follower_num:
                count+=1
    return count

>>> timeit.timeit(np_method, number = 100) / 100
0.006748438189970329

>>> timeit.timeit(zip_loop, number = 100) / 100
0.3811768989200209

>>> timeit.timeit(for_loop, number = 100) / 100
0.3774999916599336

您不应该调用变量
list
——它已经在python中使用过,而且非常混乱

>>> a = [1, 5, 4, 1, 2, 4, 6, 7, 2, 1, 3, 3, 1, 2]
>>> len( [1 for i,j in zip(a, a[1:]) if i == 2 and j == 1] )
1
基本上,您可以使用
zip()
将数组置于自身之上,并处理数字对,寻找任意组合:

>>> zip(a, a[1:])
[(1, 5), (5, 4), (4, 1), (1, 2), (2, 4), (4, 6), (6, 7), (7, 2), (2, 1), (1, 3), (3, 3), (3, 1), (1, 2)]

我建议您使用切片和理解来迭代输入列表,如下所示:

myList = [1, 5, 4, 1, 2, 4, 6, 7, 2, 1, 3, 3, 1, 2]

result = sum(myList[i:i+2] == [2,1] for i in range(len(myList)-1))

print(result) # 1
使用
zip()
函数还可以帮助您:

myList = [1, 5, 4, 1, 2, 4, 6, 7, 2, 1, 3, 3, 1, 2]

result = sum((i,j) == (2,1) for (i,j) in zip(myList, myList[1:]))

print(result) # 1

我能想到的最简单的方法是使用for循环

count=0
desired_num=2
follower_num=1
for i in range(len(list1)-1):
    if list1[i]==desired_num:
        if list1[i+1]==follower_num:
            count+=1
print("total occurance=",count)

在我的机器上拍摄:0.0003437995910644531s

为了好玩,我对所有4个主要解决方案进行了计时,结果如下:

#!/usr/bin/env python

import numpy as np
import random

def f1(li):
    return np.sum((np.array(li[:-1]) == 2) & (np.diff(li) == -1))

def f2(li):
    return sum((i,j) == (2,1) for (i,j) in zip(li, li[1:]))

def f3(li):
    count=0
    desired_num=2
    follower_num=1
    for i in range(len(li)-1):
        if li[i]==desired_num:
        if li[i+1]==follower_num:
            count+=1
    return count    

def f4(li) :
    return len( [1 for i,j in zip(li, li[1:]) if i == 2 and j == 1] )

if __name__=='__main__':
    import timeit   
    import random
    s = []
    for i in range(10000000) :
        s.append( random.randint(1,10) )

    print f1(s), f2(s), f3(s), f4(s)

    print(f1(s)==f2(s)==f3(s)==f4(s))

    for f in (f1,f2,f3,f4):
        print("   {:^10s}{:.4f} secs".format(f.__name__, timeit.timeit("f(s)", setup="from __main__ import f, s", number=10)))

'''
output:

100236 100236 100236 100236
True
       f1    7.2285 secs
       f2    13.7680 secs
       f3    4.3167 secs
       f4    7.7375 secs

'''

令人惊讶的是,简单的
for
循环胜过
numpy

注意:不要使用
list
作为变量名,因为它已经是pythonRelated(更通用)中内置的
dtype
:您的示例有点不清楚-您是否有正在使用的NumPy数组或Python列表,您认为使用NumPy可以更快地执行此操作?没有“numpy列表”这样的东西。如果你需要的只是发生的次数,你可以使用
sum
而不是
len(np.where(…)
。谢谢@busybear,是的,那更好
np.sum((mylist[:-1]==2)和(np.diff(mylist)=-1))
返回
0
无论输入什么。@lenik他们用NumPy标记问题,并说他们有一个“NumPy列表”。假设他们打算使用NumPy数组似乎是合理的。np.sum((mylist[:-1]==2)和(mylist[:1]==1))的速度是前者的两倍。这在小数组上可以很快工作,但在我的机器上,对于一个大数组(1000000个元素)来说,这大约需要0.3618秒。lozz我有7 16 GB ram请提供您的规格??5 8GB ram。我的机器有点旧了,但是在一个大数组中循环通常要比向量化的
numpy花费更长的时间methods@Inder不错,是公认答案的两倍。向上投票。你正在生成一个很长的列表,其中大部分是零,这不是非常有效的内存浪费。有关生成较小列表的方法,请参见下文。对于我们正在寻找的每种情况,该列表只包含一个元素。@sacul 10000000是一个很小的数字?仅供参考,我不是下选者(在您的两个答案中)。你可以怀疑,没关系。让我们同意不同意:)。OP可以选择他们同意的答案。对不起,这是我的错frustration@sacul我不在乎选民。我希望你的解决方案真的能像你说的那样快。不幸的是,它输给了一个简单的
for
循环,速度大约和
zip()
的列表理解一样快。太遗憾了。@lenik您正在从列表中创建一个巨大的NumPy数组。这是毫无成效的。我同意,他们的问题不清楚他们是否真的在使用NumPy,但对NumPy数组的创建进行基准测试并没有任何意义。@miradulo我逐字使用答案中的代码。压缩大型列表也不是免费的午餐=)
#!/usr/bin/env python

import numpy as np
import random

def f1(li):
    return np.sum((np.array(li[:-1]) == 2) & (np.diff(li) == -1))

def f2(li):
    return sum((i,j) == (2,1) for (i,j) in zip(li, li[1:]))

def f3(li):
    count=0
    desired_num=2
    follower_num=1
    for i in range(len(li)-1):
        if li[i]==desired_num:
        if li[i+1]==follower_num:
            count+=1
    return count    

def f4(li) :
    return len( [1 for i,j in zip(li, li[1:]) if i == 2 and j == 1] )

if __name__=='__main__':
    import timeit   
    import random
    s = []
    for i in range(10000000) :
        s.append( random.randint(1,10) )

    print f1(s), f2(s), f3(s), f4(s)

    print(f1(s)==f2(s)==f3(s)==f4(s))

    for f in (f1,f2,f3,f4):
        print("   {:^10s}{:.4f} secs".format(f.__name__, timeit.timeit("f(s)", setup="from __main__ import f, s", number=10)))

'''
output:

100236 100236 100236 100236
True
       f1    7.2285 secs
       f2    13.7680 secs
       f3    4.3167 secs
       f4    7.7375 secs

'''