[PYTHON] 파이썬에서 거대한 CSV 파일의 무작위 라인 읽기
PYTHON파이썬에서 거대한 CSV 파일의 무작위 라인 읽기
나는이 꽤 큰 CSV 파일 (15Gb)을 가지고 있으며 그것으로부터 약 1 백만개의 무작위 라인을 읽을 필요가있다. 내가 볼 수 있고 구현하는 한, 파이썬의 CSV 유틸리티는 파일에서 순차적으로 반복 만 허용합니다.
임의의 선택을 사용하기 위해 모든 파일을 메모리로 읽어들이는 데 매우 많은 메모리가 필요하며 모든 파일을 골라 일부 값을 버리고 다른 파일을 선택하는 데 많은 시간이 소요되므로 CSV 파일에서 임의의 줄을 선택해야합니다. 그 줄만 읽으시겠습니까?
나는 성공하지 않고 노력했다.
import csv
with open('linear_e_LAN2A_F_0_435keV.csv') as file:
reader = csv.reader(file)
print reader[someRandomInteger]
CSV 파일의 샘플 :
331.093,329.735
251.188,249.994
374.468,373.782
295.643,295.159
83.9058,0
380.709,116.221
352.238,351.891
183.809,182.615
257.277,201.302
61.4598,40.7106
해결법
-
==============================
1.
import random filesize = 1500 #size of the really big file 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! # extra to handle last/first line edge cases if len(random_line) == 0: # we have hit the end f.seek(0) random_line = f.readline() # so we'll grab the first line instead
@AndreBoos가 지적했듯이,이 접근법은 편향된 선택으로 이어질 것입니다. 라인의 최소 및 최대 길이를 알고있는 경우 다음을 수행하여 이러한 편향을 제거 할 수 있습니다.
(이 경우) min = 3, max = 15라고 가정 해 봅시다.
1) 이전 행의 길이 (Lp)를 찾으십시오.
Lp = 3이면 선은 가장 편향됩니다. 그러므로 우리는 100 % 시간을 가져야합니다. Lp = 15이면 선은 가장 편향되어 있습니다. 5 * 선택 가능성이 높기 때문에 시간의 20 % 만 가져 가야합니다.
우리는 무작위로 시간의 X % 라인을 유지하여 이것을 수행합니다.
X = 최소 / Lp
라인을 지키지 않으면 주사위 굴리기가 잘 될 때까지 또 다른 무작위로 선택합니다. :-)
-
==============================
2.정확하게 1 백만 라인을 필요로하지 않고 CSV 파일에 미리 줄 번호를 알고 있다고 가정하면 저장소 샘플링을 사용하여 임의의 하위 집합을 검색 할 수 있습니다. 데이터를 반복하고 각 라인마다 선택되는 라인 확률을 결정하십시오. 그렇게하면 데이터를 한 번만 전달하면됩니다.
정확하게 1 백만 라인을 필요로하지 않고 CSV 파일에 미리 줄 번호를 알고 있다고 가정하면 저장소 샘플링을 사용하여 임의의 하위 집합을 검색 할 수 있습니다. 데이터를 반복하고 각 라인마다 선택되는 라인 확률을 결정하십시오. 그렇게하면 데이터를 한 번만 전달하면됩니다.
무작위 샘플을 자주 추출해야하지만 실제 데이터 세트가 자주 변경되지 않으면 (데이터 세트가 변경 될 때마다 항목 수를 추적하면되므로)이 방법이 유용합니다.
chances_selected = desired_num_results / total_entries for line in csv.reader(file): if random() < chances_selected: result.append(line)
-
==============================
3.파일에서 임의의 행을 선택하는 확률 적 방법의 변형을 사용할 수 있습니다.
파일에서 임의의 행을 선택하는 확률 적 방법의 변형을 사용할 수 있습니다.
선택한 단일 번호를 유지하는 대신 크기 C의 버퍼를 유지할 수 있습니다. 각 줄 번호 n에 대해 N 줄이있는 파일에서 원래 줄이 아닌 확률 C / n으로 줄을 선택하려고합니다 1 / n. 번호가 선택되면 C 길이 버퍼에서 임의의 위치를 선택하여 축출합니다.
다음은 작동 방식입니다.
import random C = 2 fpath = 'somelines.txt' buffer = [] f = open(fpath, 'r') for line_num, line in enumerate(f): n = line_num + 1.0 r = random.random() if n <= C: buffer.append(line.strip()) elif r < C/n: loc = random.randint(0, C-1) buffer[loc] = line.strip()
이 경우 파일을 한 번 통과해야하므로 (선형 시간이므로) 파일에서 정확히 C 행을 반환합니다. 각 라인은 확률 C / N이 선택됩니다.
위의 작업을 확인하기 위해 a, b, c, d, e를 포함하는 5 줄의 파일을 만들었습니다. C = 2로 코드를 10,000 번 실행했습니다. 이것은 5의 균등 분포에 대해 2 (가능한 10) 개의 선택을 선택해야합니다. 결과 :
a,b: 1046 b,c: 1018 b,e: 1014 a,c: 1003 c,d: 1002 d,e: 1000 c,e: 993 a,e: 992 a,d: 985 b,d: 947
-
==============================
4.임의의 라인을 여러 번 잡아 내고 싶다면 (예 : 기계 학습을위한 미니 배치) 메모리에로드하지 않고 거대한 파일을 한 번 스캔해도 괜찮습니다. 빨리 마리아 Zverina의 답변을 기반으로 라인을 잡아 찾기를 사용하십시오.
임의의 라인을 여러 번 잡아 내고 싶다면 (예 : 기계 학습을위한 미니 배치) 메모리에로드하지 않고 거대한 파일을 한 번 스캔해도 괜찮습니다. 빨리 마리아 Zverina의 답변을 기반으로 라인을 잡아 찾기를 사용하십시오.
# Overhead: # Read the line locations into memory once. (If the lines are long, # this should take substantially less memory than the file itself.) fname = 'big_file' s = [0] linelocs = [s.append(s[0]+len(n)) or s.pop(0) for n in open(fname)] f = open(fname) # Reopen the file. # Each subsequent iteration uses only the code below: # Grab a 1,000,000 line sample # I sorted these because I assume the seeks are faster that way. chosen = sorted(random.sample(linelocs, 1000000)) sampleLines = [] for offset in chosen: f.seek(offset) sampleLines.append(f.readline()) # Now we can randomize if need be. random.shuffle(sampleLines)
-
==============================
5.라인이 진정으로 .csv 형식이고 고정 필드가 아니라면, 그렇지 않습니다. 파일을 한 번 크롤링하고 각 행의 바이트 오프셋을 인덱싱 한 다음 나중에 인덱스 세트 만 사용해야 할 경우 임의의 csv 파일에 대한 줄 종료 \ n 문자의 정확한 위치를 선험적으로 예측할 수는 없습니다.
라인이 진정으로 .csv 형식이고 고정 필드가 아니라면, 그렇지 않습니다. 파일을 한 번 크롤링하고 각 행의 바이트 오프셋을 인덱싱 한 다음 나중에 인덱스 세트 만 사용해야 할 경우 임의의 csv 파일에 대한 줄 종료 \ n 문자의 정확한 위치를 선험적으로 예측할 수는 없습니다.
-
==============================
6.당신이 총 라인 수를 알고 있다면 또 다른 해결책이 가능합니다 - 총 라인 수까지 100 만개의 난수 (random.sample (xrange (n), 1000000))를 하나의 세트로 생성 한 다음 다음을 사용하십시오 :
당신이 총 라인 수를 알고 있다면 또 다른 해결책이 가능합니다 - 총 라인 수까지 100 만개의 난수 (random.sample (xrange (n), 1000000))를 하나의 세트로 생성 한 다음 다음을 사용하십시오 :
for i, line in enumerate(csvfile): if i in lines_to_grab: yield line
이렇게하면 공평하지 않은 방식으로 정확히 1 백만 줄을 얻을 수 있지만 사전에 줄 수를 가져야합니다.
-
==============================
7.이 데이터를 sqlite3 데이터베이스에 배치 할 수 있다면 임의의 수의 임의의 행을 선택하는 것은 간단합니다. 파일에서 선을 미리 읽거나 패드 할 필요가 없습니다. sqlite 데이터 파일은 바이너리이기 때문에 데이터 파일은 CSV 텍스트보다 1/3에서 1/2 작습니다.
이 데이터를 sqlite3 데이터베이스에 배치 할 수 있다면 임의의 수의 임의의 행을 선택하는 것은 간단합니다. 파일에서 선을 미리 읽거나 패드 할 필요가 없습니다. sqlite 데이터 파일은 바이너리이기 때문에 데이터 파일은 CSV 텍스트보다 1/3에서 1/2 작습니다.
THIS와 같은 스크립트를 사용하여 CSV 파일을 가져 오거나 더 나은 방법으로 데이터를 처음부터 데이터베이스 테이블에 쓸 수 있습니다. SQLite3은 Python 배포판의 일부입니다.
그런 다음이 명령문을 사용하여 1,000,000 개의 임의 행을 가져옵니다.
mydb='csv.db' con=sqlite3.connect(mydb) with con: cur=con.cursor() cur.execute("SELECT * FROM csv ORDER BY RANDOM() LIMIT 1000000;") for row in cur.fetchall(): # now you have random rows...
-
==============================
8.고정 길이 레코드로 파일을 다시 쓰고 나중에 중간 파일에 대해 임의 액세스를 수행 할 수 있습니다.
고정 길이 레코드로 파일을 다시 쓰고 나중에 중간 파일에 대해 임의 액세스를 수행 할 수 있습니다.
ifile = file.open("inputfile.csv") ofile = file.open("intermediatefile.csv",'w') for line in ifile: ofile.write(line.rstrip('\n').ljust(15)+'\n')
그런 다음 할 수 있습니다.
import random ifile = file.open("intermediatefile.csv") lines = [] samples = random.sample(range(nlines)) for sample in samples: ifile.seek(sample) lines.append(ifile.readline())
더 많은 디스크 공간이 필요하며 첫 번째 프로그램은 실행하는 데 약간의 시간이 걸릴 수 있지만 나중에 무작위로 무작위로 액세스 할 수 있습니다.
-
==============================
9.
# pass 1, count the number of rows in the file rowcount = sum(1 for line in file) # pass 2, select random lines file.seek(0) remaining = 1000000 for row in csv.reader(file): if random.randrange(rowcount) < remaining: print row remaining -= 1 rowcount -= 1
-
==============================
10.이 메소드에서는, 요소의 수가 읽는 행 수와 동일한 난수 세트를 생성합니다. 범위는 데이터에있는 행 수입니다. 그런 다음 가장 작은 것부터 가장 큰 것까지 정렬되고 저장됩니다.
이 메소드에서는, 요소의 수가 읽는 행 수와 동일한 난수 세트를 생성합니다. 범위는 데이터에있는 행 수입니다. 그런 다음 가장 작은 것부터 가장 큰 것까지 정렬되고 저장됩니다.
그런 다음 csv 파일을 한 줄씩 읽고 line_counter를 사용하여 행 번호를 나타냅니다. 이 line_counter는 정렬 된 난수 목록의 첫 번째 요소로 검사되고, 일치하면 특정 줄이 새 CSV 파일에 쓰여지고 첫 번째 요소가 목록에서 제거되고 이전의 두 번째 요소가 먼저주기가 계속됩니다.
import random k=random.sample(xrange(No_of_rows_in_data),No_of_lines_to_be_read) Num=sorted(k) line_counter = 0 with open(input_file,'rb') as file_handle: reader = csv.reader(file_handle) with open(output_file,'wb') as outfile: a=csv.writer(outfile) for line in reader: line_counter += 1 if line_counter == Num[0]: a.writerow(line) Num.remove(Num[0]) if len(Num)==0: break
from https://stackoverflow.com/questions/10819911/read-random-lines-from-huge-csv-file-in-python by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] sqlAlchemy를 사용하는 저장 프로 시저 (0) | 2018.10.31 |
---|---|
[PYTHON] 판다에서 행 평균 계산 (0) | 2018.10.31 |
[PYTHON] flask.ext를 가져 오면 ModuleNotFoundError가 발생합니다. (0) | 2018.10.30 |
[PYTHON] Matplotlib Plot Dashed Circles (plt.scatter 대신 plt.plot 사용) (0) | 2018.10.30 |
[PYTHON] Python MySQL 커넥터 - fetchone을 사용할 때 읽지 않은 결과가 있습니다. (0) | 2018.10.30 |