Элементы в списке больше или равны элементам в другом списке (без цикла for?) - PullRequest
2 голосов
/ 20 ноября 2019

У меня есть список, содержащий 1 000 000 элементов (чисел) с именем x, и я хотел бы подсчитать, сколько из них равно или превышает [0,5,0,55,0.60, ..., 1]. Есть ли способ сделать это без цикла for?

Прямо сейчас у меня есть следующий код, который работает для определенного значения интервала [0,5, ... 1], скажем, 0,5 и назначаетэто к переменной count

count=len([i for i in x if i >= 0.5])

РЕДАКТИРОВАТЬ: В основном то, что я хочу избежать, делает это ... если это возможно?

obs=[]
alpha = [0.5,0.55,0.6,0.65,0.7,0.75,0.8,0.85,0.9,0.95,1]

for a in alpha:
    count= len([i for i in x if i >= a])
    obs.append(count)

Заранее спасибо Бест, Микаэль

Ответы [ 5 ]

1 голос
/ 20 ноября 2019

Я не думаю, что это возможно без цикла, но вы можете отсортировать массив x, а затем вы можете использовать модуль bisect ( doc ), чтобы найти точку вставки (индекс).

Например:

x = [0.341, 0.423, 0.678, 0.999, 0.523, 0.751, 0.7]

alpha = [0.5,0.55,0.6,0.65,0.7,0.75,0.8,0.85,0.9,0.95,1]

x = sorted(x)

import bisect

obs = [len(x) - bisect.bisect_left(x, a) for a in alpha]

print(obs)

Напечатает:

[5, 4, 4, 4, 3, 2, 1, 1, 1, 1, 0]

Примечание:

sorted() имеет сложность n log(n) и bisect_left() log(n)

0 голосов
/ 20 ноября 2019

Основываясь на комментариях, вы можете использовать numpy, поэтому используйте np.searchsorted, чтобы просто вставить alpha в отсортированную версию x. Индексы будут вашими подсчетами.

Если вы в порядке с сортировкой x на месте:

x.sort()
counts = x.size - np.searchsorted(x, alpha)

Если нет,

counts = x.size - np.searchsorted(np.sort(x), alpha)

Эти подсчетыпредположим, что вы хотите x < alpha. Чтобы получить <=, добавьте ключевое слово side='right':

np.searchsorted(x, alpha, side='right')

PS

Есть несколько существенных проблем со строкой

count = len([i for i in x if i >= 0.5])

Прежде всего, вы создаете список всех подходящих элементов, а не просто подсчитываете их. Чтобы подсчитать их, сделайте

count = sum(1 for i in x if i >= threshold)

Теперь проблема в том, что вы делаете линейный проход через весь массив для каждой альфы, что не является необходимым.

Как я прокомментировал в @ Ответ Андрея Кезели , скажем, у нас есть N = len(x) и M = len(alpha). Ваша реализация O(M * N) сложность времени, а сортировка дает O((M + N) log N). Для M << N (маленький alpha) ваша сложность составляет приблизительно O(N), что превосходит O(N log N). Но для M ~= N ваш приближается к O(N^2) против моего O(N log N).

0 голосов
/ 20 ноября 2019

РЕДАКТИРОВАТЬ: Если вы уже используете NumPy, вы можете просто сделать это:

import numpy as np

# Make random data
np.random.seed(0)
x = np.random.binomial(n=20, p=0.5, size=1000000) / 20
bins = np.arange(0.55, 1.01, 0.05)
# One extra value for the upper bound of last bin
bins = np.append(bins, max(bins.max(), x.max()) + 1)
h, _ = np.histogram(x, bins)
result = np.cumsum(h)
print(result)
# [280645 354806 391658 406410 411048 412152 412356 412377 412378 412378]

Если вы имеете дело с большими массивами чисел, вы можете рассмотреть возможность использования NumPy . Но если вы используете простые списки Python, вы можете сделать это, например, так:

def how_many_bigger(nums, mins):
    # List of counts for each minimum
    counts = [0] * len(mins)
    # For each number
    for n in nums:
        # For each minimum
        for i, m in enumerate(mins):
            # Add 1 to the count if the number is greater than the current minimum
            if n >= m:
                counts[i] += 1
    return counts

# Test
import random
# Make random data
random.seed(0)
nums = [random.random() for _ in range(1_000_000)]
# Make minimums
mins = [i / 100. for i in range(55, 101, 5)]
print(mins)
# [0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0]
count = how_many_bigger(nums, mins)
print(count)
# [449771, 399555, 349543, 299687, 249605, 199774, 149945, 99928, 49670, 0]
0 голосов
/ 20 ноября 2019

Даже если вы не используете для цикла, внутренние методы используют их. Но итерирует их эффективно.

Вы можете использовать функцию ниже без цикла for с вашего конца.

x = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
l = list(filter(lambda _: _ > .5 , x))
print(l)
0 голосов
/ 20 ноября 2019

Вы можете использовать индексирование NUMPY и BULEAN:

>>> import numpy as np
>>> a = np.array(list(range(100)))
>>> a[a>=50].size
50
...