Подсчитайте количество точных совпадений предметов в списке - PullRequest
0 голосов
/ 05 июля 2018

Я пытаюсь выяснить самый быстрый способ подсчитать, сколько раз два значения находятся одно за другим в списке с нулевыми значениями.

Например:

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, но я чувствую, что должен быть более быстрый способ сделать это,

Спасибо

Ответы [ 5 ]

0 голосов
/ 05 июля 2018

Просто для удовольствия, я рассчитал все 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 =)

0 голосов
/ 05 июля 2018

Thea самый простой способ, который я могу придумать, это использовать цикл 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 на моей машине

0 голосов
/ 05 июля 2018

Вы не должны называть вашу переменную 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)]
0 голосов
/ 05 июля 2018

Я могу предложить вам использовать нарезку и понимание, чтобы перебрать ваш список ввода следующим образом:

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
0 голосов
/ 05 июля 2018

Вы можете сделать это, используя np.diff и np.where:

import numpy as np

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

# Turn your list into a numpy array
myarray = np.array(mylist)

# find occurences where myarray is 2 and the following element is 2 minus 1
np.sum((myarray[:-1] == 2) & (np.diff(myarray) == -1))

Что возвращает 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...