2010-03-17 3 views
13

나는 약 10Gb 크기의 csv 데이터 세트를 가지고 있습니다. 그들의 열에서 히스토그램을 생성하고 싶습니다. 그러나 numpy에서 이렇게하는 유일한 방법은 numpy 배열에 전체 열을 먼저로드 한 다음 해당 배열에 numpy.histogram을 호출하는 것입니다. 이렇게하면 불필요한 메모리가 소모됩니다.큰 배열의 너비 히스토그램

numpy는 온라인 비닝을 지원합니까? 나는 그것을 읽으면서 라인과 빈 값에 의해 나의 csv 라인을 반복하는 것을 기대하고있다. 이 방법은 한 번에 최대 한 줄의 메모리에 있습니다.

내 자신을 구르지는 않겠지 만 누군가 이미이 바퀴를 발명했는지 궁금 할 것입니다.

답변

9

당신이 말했듯이, 당신 자신의 것을 굴리는 것은 그리 어렵지 않습니다. 보관함을 직접 설정하고 파일을 반복 할 때 다시 사용해야합니다.

import numpy as np 
datamin = -5 
datamax = 5 
numbins = 20 
mybins = np.linspace(datamin, datamax, numbins) 
myhist = np.zeros(numbins-1, dtype='int32') 
for i in range(100): 
    d = np.random.randn(1000,1) 
    htemp, jnk = np.histogram(d, mybins) 
    myhist += htemp 

내가 추측하고있어 성능은 큰 파일에 문제가, 너무 느린 수 있습니다 각 라인에 히스토그램을 호출의 오버 헤드가 될 것입니다 : 다음은 괜찮은 출발점이 될해야한다. 발전기의 @doug's suggestion은 그 문제를 해결하는 좋은 방법 인 것 같습니다. 발전기와

+0

좋은 해결책. 좀 더 빠르게하고 싶다면'myhist + = htemp'를 할 수 있습니다 (히스토그램을 제자리에 업데이트하기 때문에 더 빠름). – EOL

+0

감사합니다. @ EOL. 옥타브에서 완전히 전환하지 않았기 때문에 좋은 파이썬 기능을 잊어 버렸습니다. 그리고 아직 배워야 할 발전기와 같은 고급 기능이 있습니다. – mtrw

6

여기에 직접 값을 빈에 대한 방법 :

import numpy as NP 

column_of_values = NP.random.randint(10, 99, 10) 

# set the bin values: 
bins = NP.array([0.0, 20.0, 50.0, 75.0]) 

binned_values = NP.digitize(column_of_values, bins) 

'binned_values'는 column_of_values ​​각 값이 속하는 빈의 인덱스를 포함하는 인덱스 배열이다. 발전기를 구축하는 NumPy와의 'loadtxt'를 사용하여 데이터 세트의 크기를 감안할 때

NP.bincount(binned_values) 

, 유용 할 수 있습니다 :

data_array = NP.loadtxt(data_file.txt, delimiter=",") 
def fnx() : 
    for i in range(0, data_array.shape[1]) : 
    yield dx[:,i] 

'bincount'빈 카운트 (명백하게) 당신에게 줄 것이다

+3

하지만 먼저 메모리에 전체 파일을로드하지 않겠습니까? 그것이 바로 제가 피하고 싶은 문제입니다. –

2

비닝 당신은 시간의 미리 원하는 빈의 폭을 알고 있다면

을 (큰 데이터 세트; 고정 폭 쓰레기통 데이터를 플로트) - 버킷의 수백 또는 수천이있는 경우에도 - 그러면 자신의 솔루션을 선전하는 것이 빠를 것이라고 생각합니다 (작성하고 실행하는 것 모두). 다음은 당신에게 파일에서 다음 값 제공하는 반복자 있다고 가정합니다 일부 파이썬의 :

from math import floor 
binwidth = 20 
counts = dict() 
filename = "mydata.csv" 
for val in next_value_from_file(filename): 
    binname = int(floor(val/binwidth)*binwidth) 
    if binname not in counts: 
     counts[binname] = 0 
    counts[binname] += 1 
print counts 

값은 수레가 될 수는 있지만, 이것은 당신이 정수 binwidth를 사용하는 가정입니다; 일부 float 값의 binwidth를 사용하려면이 설정을 약간 조정해야 할 수도 있습니다.

앞서 언급했듯이 iter() 메서드를 사용하여 사용자 지정 생성기 또는 개체를 작성하여이 작업을 효율적으로 수행 할 수 있습니다.이러한 발전기의 의사는이 될 것이다 : 주어진 라인이 여러 개의 값이있는 경우

def next_value_from_file(filename): 
    f = open(filename) 
    for line in f: 
    # parse out from the line the value or values you need 
    val = parse_the_value_from_the_line(line) 
    yield val 

, 다음 parse_the_value_from_the_line()을하거나 목록을 반환하거나 자체 발전기, 그리고이 의사 사용

def next_value_from_file(filename): 
    f = open(filename) 
    for line in f: 
    for val in parse_the_values_from_the_line(line): 
     yield val 
3

을 펜윅 나무비닝 (매우 큰 데이터 세트, 필요 백분위 경계)

내가 두 번째를 게시하도록하겠습니다 이 접근 방식은 매우 다르기 때문에 같은 질문을 던지며 다른 문제를 다룹니다.

대단히 큰 데이터 세트 (수십억 개의 샘플)가 있고 빈 경계가 있어야하는 시점을 미리 알지 못하면 어떻게됩니까? 예를 들어, 사 분위수 나 십진수로 내용을 채우기를 원할 수 있습니다.

작은 데이터 세트의 경우 데이터를 배열에로드하고 정렬 한 다음 배열을 통과하는 비율의 인덱스로 이동하여 주어진 백분위 수의 값을 읽습니다.

배열을 보유 할 메모리 크기가 실용적이지 않은 경우 (정렬 시간은 말할 것도 없음) ... 펜윅 트리, 일명 "바이너리 인덱스 트리"사용을 고려하십시오.

이 데이터는 양의 정수 데이터에서만 작동하므로 펜윅 트리에서 데이터를 집계하기 전에 데이터를 이동 (규모를 조정)하기 위해 데이터 집합에 대해 충분히 알아야합니다.

필자는 합리적인 시간과 매우 편안한 메모리 한계에서 1,000 억 샘플 데이터 세트의 중간 값을 찾기 위해이 방법을 사용했습니다. (내 다른 대답에 따라, 파일을 열고 읽을 발전기를 사용하는 것을 고려, 즉 여전히 유용합니다.)

펜윅 나무에 더 :

+0

계산은 순서와 관계가 없으므로 데이터를 한 번에 배열로로드하거나 정렬 할 필요가 없습니다. – rafaelvalle