2009-10-26 5 views
34

그래서 100 개의 요소가있는 100,000 개의 부동 배열이 있다고 가정 해 보겠습니다. 가장 큰 X 값을 필요로하지만 Y보다 큰 경우에만 필요합니다.이 값과 일치하지 않는 요소는 0으로 설정해야합니다. Python에서이 작업을 수행하는 가장 빠른 방법은 무엇입니까? 주문을 유지해야합니다. 요소의 대부분은 이미 0배열에서 낮은 값을 0으로 만드는 가장 빠른 방법은 무엇입니까?

샘플 변수로 설정됩니다

array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0] 
highCountX = 3 
lowValY = .1 

예상 된 결과 : 가장 간단한 방법은 것

array = [0, .25, 0, .15, .5, 0, 0, 0, 0, 0] 
+0

HightCountX은 무엇으로 –

+0

highCountX는 배열에 존재할 0이 아닌 요소의 최대 수입니다. – David

+0

2 인 경우 예상 결과는 [0, 0, 0, .15, .5, 0, 0, 0, 0, 0] - highCountX는 결과에서 0이 아닌 요소의 수를 제한합니다. – Abgan

답변

73

이 작업의 이러한 종류의 매우 빠르고 NumPy의 일반적인 작업입니다 : 당신은 단지 highCountX 가장 큰 요소를 필요로하는 경우, 당신도 (작은 요소를 "잊지"수, 이제

array_np = numpy.asarray(array) 
low_values_flags = array_np < lowValY # Where values are low 
array_np[low_values_flags] = 0 # All low values set to 0 

물론

array_np = numpy.asarray(array) 
print numpy.sort(array_np[array_np >= lowValY])[-highCountX:] 

, 당신은 단지 몇 가지 요소가 최적이 아닐 수도 있습니다 필요한 경우 전체 배열을 정렬 : 대신 0로 설정하고 정렬) 만 종류의 큰 요소 목록을의. 필요에 따라 표준 heapq 모듈을 고려할 수 있습니다. 제로 일부 임계 값 이하

+5

좋은 ... 적절한 라이브러리를 사용하면 정말 멀리 걸릴 수 있습니다 :-) – Abgan

+0

나는이 numPy로 계속 실행됩니다. 체크 아웃해야 할 것입니다. 도움에 감사드립니다 (모든 사람). – David

+0

@David NumPy는 정말 필요한 것을 채워줍니다. 내가 연계 된 튜토리얼부터 시작하는 것이 좋습니다. 아마도 NumPy로 속도를 높이고 가장 중요한 개념을 배울 수있는 가장 빠른 방법 일 것입니다. – EOL

5

: 조각

topX = sorted([x for x in array if x > lowValY], reverse=True)[highCountX-1] 
print [x if x >= topX else 0 for x in array] 

을, lowValY보다 큰 모든 요소를 ​​선택합니다.

[x for x in array if x > lowValY] 

이 배열에는 임계 값보다 큰 요소 수가 포함됩니다. 이어서, 그렇게 정렬 최대 값의 시작에있다 :

sorted(...)[highCountX-1] 

마지막으로, 원래의 배열이 다른을 사용하여 충전된다 : 다음 목록 지수 가기 highCountX 요소에 대한 임계 값을 취

sorted(..., reverse=True) 

목록 이해 :

[x if x >= topX else 0 for x in array] 

두 번째 이상의 동일 요소가있는 경우 (예를 들어) 세 번째로 높은 요소가있는 경계 조건이 있습니다. 결과 배열에는 해당 요소가 두 번 이상 포함됩니다.

다른 경계 조건도 있습니다 (예 : len(array) < highCountX). 그러한 조건을 처리하는 것은 구현 자에게 맡겨져있다.

+1

원본 배열이 복사되지 않고 열거 된 경우에만 x> lowValY 대신 x> lowValY를 사용하여 x> lowValY 인 배열을 열거 할 수 있습니다. 원본 데이터가 상당히 크면). – Abgan

+1

사실입니다. 'sorted()'는 어쨌든 전체 목록을 필요로 할 것입니다. –

+0

Heh, 3 배 빨라지고 멍청한 점이 있지만 highCountX 한도를 유지하려면 같은 요소가 필요합니다. 배열은 20-200 개 요소 중 하나를 가져야합니다 ... 실제로는 청크로 처리하는 큰 배열의 세그먼트입니다. 지금까지 도움을 주셔서 감사합니다. – David

2

설정 요소는 간단하다. (플러스 가끔 복근() 필요한 경우)

array = [ x if x > threshold else 0.0 for x in array ] 

N 개의 가장 높은 번호의 요구 사항은 그러나, 조금 모호합니다. 예를 들어 무엇입니까? N + 1 개의 동일한 숫자가 임계 값보다 높습니까? 어느 것이자를 것입니까?

당신은 N 번째 요소의 값으로 임계 값을 설정, 먼저 배열을 정렬 수 :

threshold = sorted(array, reverse=True)[N] 
array = [ x if x >= threshold else 0.0 for x in array ] 

참고 :이 솔루션은 읽을 수없는 성능에 최적화되어 있습니다. numpy를 사용

+0

이 경우에는 어느 것이 잘리는 지 중요하지 않습니다. 더 중요한 것은 highCountX 다음에 코드 구문을 테스트하지 않은 – David

6

: partial_sort이 될 수

# assign zero to all elements less than or equal to `lowValY` 
a[a<=lowValY] = 0 
# find n-th largest element in the array (where n=highCountX) 
x = partial_sort(a, highCountX, reverse=True)[:highCountX][-1] 
# 
a[a<x] = 0 #NOTE: it might leave more than highCountX non-zero elements 
      # . if there are duplicates 

:

def partial_sort(a, n, reverse=False): 
    #NOTE: in general it should return full list but in your case this will do 
    return sorted(a, reverse=reverse)[:n] 

다음과 같이 a[a<value] = 0numpy없이 쓸 수있는 표현 :

for i, x in enumerate(a): 
    if x < value: 
     a[i] = 0 
1

사용할 수있는지도와 람다 , 그것은 빠른 전자이어야합니다 아니.

new_array = map(lambda x: x if x>y else 0, array) 
0

heap을 사용하십시오.

시간은 O(n*lg(HighCountX))입니다.

import heapq 

heap = [] 
array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0] 
highCountX = 3 
lowValY = .1 

for i in range(1,highCountX): 
    heappush(heap, lowValY) 
    heappop(heap) 

for i in range(0, len(array) - 1) 
    if array[i] > heap[0]: 
     heappush(heap, array[i]) 

min = heap[0] 

array = [x if x >= min else 0 for x in array] 

deletemin 당신이 사용하는 힙 유형에 따라 힙 O(lg(k)) 및 삽입 O(lg(k)) 또는 O(1)에서 작동합니다.

+0

입니다. – Egon

7

정확하게 NumPy에 특수 MaskedArray 클래스가 있습니다. 사전 조건에 따라 요소를 "마스크"할 수 있습니다. 이것은 제로를 할당하는 것보다 더 잘 나타납니다. 적절한 경우 (예 : 평균값 찾기) 마스크 처리 된 값을 무시합니다.

>>> from numpy import ma 
>>> x = ma.array([.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0]) 
>>> x1 = ma.masked_inside(0, 0.1) # mask everything in 0..0.1 range 
>>> x1 
masked_array(data = [-- 0.25 -- 0.15 0.5 -- -- -- -- --], 
     mask = [ True False True False False True True True True True], 
    fill_value = 1e+20) 
>>> print x.filled(0) # Fill with zeroes 
[ 0 0.25 0 0.15 0.5 0 0 0 0 0 ] 

마스크 된 어레이는 필요한 경우 matplotlib 시각화 라이브러리에서 잘 지원됩니다. 에곤 말한대로 힙을 사용

Docs on masked arrays in numpy

0

은 좋은 생각이다. 그러나 당신은 어떤 노력을 줄이기 위해 heapq.nlargest 기능을 사용할 수 있습니다 :

import heapq 

array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0] 
highCountX = 3 
lowValY = .1 

threshold = max(heapq.nlargest(highCountX, array)[-1], lowValY) 
array = [x if x >= threshold else 0 for x in array] 
+0

표준 모듈 만 사용하는 수제 솔루션이 마음에 듭니다. 그러나, 가장 큰 highCountX 요소를 실제로 반환하도록 업그레이드해야합니다 (배열의 많은 요소가 '임계 값'을 가지면 최종 배열에 0이 아닌 요소가 너무 많음). – EOL

19
from scipy.stats import threshold 
thresholded = threshold(array, 0.5) 

: