Mam listę zawierającą 1 000 000 elementów (liczb) o nazwie x i chciałbym policzyć, ile z nich jest równych lub większych [0.5, 0.55, 0.60, ..., 1]. Czy można to zrobić bez pętli for?
W tej chwili mam następujący kod, który działa dla określonej wartości przedziału [0,5, ... 1], powiedzmy 0,5 i przypisuje go do zmiennej count
count=len([i for i in x if i >= 0.5])
EDYCJA: Zasadniczo to, czego chcę uniknąć, to robienie tego ... jeśli to możliwe?
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)
Z góry dziękuję. Najlepiej, Mikael
5 odpowiedzi
Nie sądzę, że jest to możliwe bez pętli, ale możesz posortować tablicę x
, a następnie użyć modułu bisect
(doc), aby zlokalizować punkt wstawiania (indeks).
Na przykład:
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)
Wydrukuje:
[5, 4, 4, 4, 3, 2, 1, 1, 1, 1, 0]
Uwaga:
sorted()
ma złożoność n log(n)
i bisect_left()
log(n)
Możesz użyć indeksowania numpy i boolowskiego:
>>> import numpy as np
>>> a = np.array(list(range(100)))
>>> a[a>=50].size
50
Nawet jeśli nie używasz pętli for, używają ich wewnętrzne metody. Ale skutecznie je iteruje.
Możesz użyć poniższej funkcji bez pętli for od końca.
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)
_
to prawidłowa nazwa parametru, ale jest zwykle używana do ignorowanych parametrów, nie jest zalecane, jeśli faktycznie używasz jej wartości (patrz Do czego służy pojedyncza zmienna podkreślenia „_” w Pythonie?).
Na podstawie komentarzy możesz używać numpy, więc użyj np.searchsorted
, aby po prostu wstawić alpha
do posortowanej wersji x
. Indeksy będą twoimi obliczeniami.
Jeśli nie masz nic przeciwko sortowaniu x
na miejscu:
x.sort()
counts = x.size - np.searchsorted(x, alpha)
Jeśli nie,
counts = x.size - np.searchsorted(np.sort(x), alpha)
Te liczby zakładają, że chcesz x < alpha
. Aby uzyskać <=
dodaj słowo kluczowe side='right'
:
np.searchsorted(x, alpha, side='right')
PS
Jest kilka poważnych problemów z linią
count = len([i for i in x if i >= 0.5])
Przede wszystkim tworzysz listę wszystkich pasujących elementów, zamiast je liczyć. Aby je policzyć,
count = sum(1 for i in x if i >= threshold)
Teraz problem polega na tym, że wykonujesz liniowe przejście przez całą tablicę dla każdej alfy, co nie jest konieczne.
Jak skomentowałem pod odpowiedzią @Andreja Kesely, załóżmy, że mamy N = len(x)
i M = len(alpha)
. Twoja implementacja jest O(M * N)
złożona czasowo, a sortowanie daje O((M + N) log N)
. W przypadku M << N
(małego alpha
) Twoja złożoność wynosi około O(N)
, co przewyższa O(N log N)
. Ale w przypadku M ~= N
Twój zbliża się do O(N^2)
w porównaniu z moim O(N log N)
.
EDYCJA: Jeśli używasz już NumPy, możesz po prostu zrobić to:
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]
Jeśli masz do czynienia z dużymi tablicami liczb, możesz rozważyć użycie NumPy. Ale jeśli używasz prostych list Pythona, możesz to zrobić na przykład tak:
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]
x=np.random.binomial(n=20, p=0.5,size=1000000)
Podobne pytania
Powiązane pytania
Nowe pytania
python
Python to wielozadaniowy, wielozadaniowy język programowania dynamicznie typowany. Został zaprojektowany tak, aby był szybki do nauczenia się, zrozumienia i użycia oraz wymuszania czystej i jednolitej składni. Należy pamiętać, że Python 2 oficjalnie nie jest obsługiwany od 01-01-2020. Mimo to, w przypadku pytań Pythona specyficznych dla wersji, dodaj znacznik [python-2.7] lub [python-3.x]. Korzystając z wariantu Pythona (np. Jython, PyPy) lub biblioteki (np. Pandas i NumPy), należy umieścić go w tagach.