2012-10-09 4 views
1

로 읽지 않고 파이썬에서 그것에서 임의의 라인을 얻을 나는 어떤 CSV 텍스트 형식의 파일이 있습니다 파일은 3.5GB에 대한 있습니다텍스트 CSV 이진 파일을 변환 및 메모리

1.3, 0, 1.0 
20.0, 3.2, 0 
30.5, 5.0, 5.2 

크기와 I를 유용한 시간 안에 팬더의 메모리로 그 중 어떤 것도 읽을 수 없습니다.

그러나 모든 파일을 읽을 필요가 없습니다. 원하는 작업은 파일에서 임의의 줄을 선택하고 거기에있는 값을 읽는 것입니다. 이론적으로는 파일 모든 필드의 크기가 같은 방식으로 형식이 지정됩니다 (예 : 이진 파일의 float16). 어떻게 변환이 완료된 후 나는 그것에서 임의의 선을 따기 가야 할, How to output list of floats to a binary file in Python

그러나 :

지금, 난 그냥 질문에 대한 답변에 명시된 NumPy와 방법을 사용하여 변환 할 수 있습니다 생각 ? 일반 텍스트 파일에서

은 그냥 할 수있는 :

import random 
offset = random.randrange(filesize) 
f = open('really_big_file') 
f.seek(offset)     #go to random position 
f.readline()     # discard - bound to be partial line 
random_line = f.readline()  # bingo! 

하지만이 NumPy와 만든 바이너리 파일에서 작업 할 수있는 방법을 찾을 수 없습니다.

+0

@TimPietzcker - 기본적으로 코드 스 니펫이 수행하는 작업이 아닌가요? 물론 그 방법으로 첫 번째 줄을 선택할 가능성을 없애줍니다 ... – mgilson

+2

원본 텍스트 CSV의 줄이 다른 길이이기 때문에 더 큰 줄을 선호하는 편향을 얻을 수 있습니다. 더 작은 것의 대신에 뽑혔다. (즉, 예시 데이터에서, 제 3 라인은 제 1 라인보다 거의 30 % 더 높은 확률을 가질 것이다.) – jbssm

+0

@jbssm - 흠 ... 흥미로운 점. – mgilson

답변

2

나는 바이너리로 변환 struct을 사용하십시오 : 표준 4 바이트는 대부분의 시스템에서 수레로

import struct 
with open('input.txt') as fin, open('output.txt','wb') as fout: 
    for line in fin: 
     #You could also use `csv` if you're not lazy like me ... 
     out_line = struct.pack('3f',*(float(x) for x in line.split(','))) 
     fout.write(out_line) 

이 모든 것을 기록합니다. 이제

, 다시 데이터를 읽을 수 : 디스크 공간에 대한 우려와 np.float16 (2 바이트 수레)를 사용하여 아래로 데이터를 압축 할 경우

with open('output.txt','rb') as fin: 
    line_size = 12 #each line is 12 bytes long (3 floats, 4 bytes each) 
    offset = random.randrange(filesize//line_size) #pick n'th line randomly 
    f.seek(offset*line_size) #seek to position of n'th line 
    three_floats_bytes = f.read(line_size) 
    three_floats = struct.unpack('3f',three_floats_bytes) 

, 당신은 너무 기본을 사용하는 것을 할 수있다 위의 스켈레톤 대신 struct.pack 대신 np.fromstringstruct.unpackndarray.tostring으로 대체하십시오. 적절한 데이터 유형 ndarray를 사용하면 line_size은 6 ...으로 떨어집니다.

+0

감사합니다. 당신은 저를 많이 도와주었습니다. NumPy에 대한 질문에서 언급 한 예제와 예제를 결합하여 NumPy에서 내가 원하는 것을 할 수있었습니다. 나는 그것을 아래에 더할 것이라고 생각한다. – jbssm

+0

이 코드가 작동하지 않는다고 말하면됩니다. 오류가 발생합니다 : lineOut = struct.pack ('3f', * (float (x) for line.split (','))) struct.오류 : 팩에는 정확히 3 개의 인수가 필요합니다. – jbssm

+0

@jbssm - 그러면 3 개 이상의 요소가있는 레코드가있는 것 같습니다. – mgilson

0

당신은 오프셋이 저장 크기에 따라 함께 놀러해야 할 것,하지만 : 누군가가 경우

import csv 
import struct 
import random 

count = 0 
with open('input.csv') as fin, open('input.dat', 'wb') as fout: 
    csvin = csv.reader(fin) 
    for row in csvin: 
     for col in map(float, row): 
      fout.write(struct.pack('f', col)) 
      count += 1 


with open('input.dat', 'rb') as fin: 
    i = random.randrange(count) 
    fin.seek(i * 4) 
    print struct.unpack('f', fin.read(4)) 
+0

이것은 임의의 부동 소수점 행이 아닌 임의의 부동 소수점을 찾습니다. 즉, 여기서 "기록"정보를 잃어 버리는 것입니다. – mgilson

+0

실제로 @mgilson - 나는 당신의 답을 보았습니다 -하지만 거의 같았습니다. 당신이 말했던 것처럼'line_size'를 조정하십시오. –

0

그래서, helpfull 답변에서 제공하는 예제를 사용하여, 나는 NumPy와 함께 할 수있는 방법을 발견 관심있는 :

# this converts the file from text CSV to bin 
with zipfile.ZipFile("input.zip", 'r') as inputZipFile: 
    inputCSVFile = inputZipFile.open(inputZipFile.namelist()[0], 'r') # it's 1 file only zip 

    with open("output.bin", 'wb') as outFile: 
     outCSVFile = csv.writer(outFile, dialect='excel') 
     for line in inputCSVFile: 
      lineParsed = ast.literal_eval(line) 
      lineOut = numpy.array(lineParsed,'float16') 
      lineOut.tofile(outFile) 
     outFile.close() 

    inputCSVFile.close() 
    inputZipFile.close() 

# this reads random lines from the binary file 
with open("output.bin", 'wb') as file: 
    file.seek(0) 

    lineSize = 20 # float16 has 2 bytes and there are 10 values: 
    fileSize = os.path.getsize("output.bin") 

    offset = random.randrange(fileSize//lineSize) 
    file.seek(offset * lineSize) 
    random_line = file.read(lineSize) 
    randomArr = numpy.fromstring(random_line, dtype='float16') 
관련 문제