2016-06-06 5 views
1

Ранее я задал вопрос, который необходимо решить, используя R: subset recursively a data.frame, однако файл настолько велик, что мне нужно много времени и оперативной памяти, чтобы его прочитать. Интересно, могу ли я использовать pandas в python, чтобы сделать то же самое, так как я новичок в python и pandas кажется более похожим на R, по крайней мере, на его sintax. Вот резюме, что мой предыдущий пост:Эффективный способ подмножества огромного файла с разделителями

ПРЕДЫДУЩИЙ ПОЧТА: У меня есть файл с разделителями табуляции с близкими к 15 миллионам строк, а его размер составляет 27 ГБ. Мне нужен эффективный способ подмножества данных на основе двух критериев. Я могу сделать это цикл for, но было интересно, есть ли более элегантный способ сделать это, и, очевидно, более эффективный. Data.frame выглядит следующим образом:

SNP   CHR  BP   P 
rs1000000 chr1 126890980 0.000007 
rs10000010 chr4 21618674 0.262098  
rs10000012 chr4 1357325  0.344192 
rs10000013 chr4 37225069 0.726325  
rs10000017 chr4 84778125 0.204275  
rs10000023 chr4 95733906 0.701778 
rs10000029 chr4 138685624 0.260899 
rs1000002 chr3 183635768 0.779574 
rs10000030 chr4 103374154 0.964166  
rs10000033 chr2 139599898 0.111846  
rs10000036 chr4 139219262 0.564791 
rs10000037 chr4 38924330 0.392908  
rs10000038 chr4 189176035 0.971481  
rs1000003 chr3 98342907 0.000004 
rs10000041 chr3 165621955 0.573376 
rs10000042 chr3 5237152  0.834206  
rs10000056 chr4 189321617 0.268479 
rs1000005 chr1 34433051 0.764046 
rs10000062 chr4 5254744  0.238011  
rs10000064 chr4 127809621 0.000044 
rs10000068 chr2 36924287 0.000003 
rs10000075 chr4 179488911 0.100225  
rs10000076 chr4 183288360 0.962476 
rs1000007 chr2 237752054 0.594928 
rs10000081 chr1 17348363 0.517486  
rs10000082 chr1 167310192 0.261577  
rs10000088 chr1 182605350 0.649975 
rs10000092 chr4 21895517 0.000005 
rs10000100 chr4 19510493 0.296693  

первым, что нужно сделать, это выбрать ту SNP со значением P ниже порогового значения, то заказать эту подгруппу по CHR и BP. Как только у меня есть это подмножество, мне нужно получить все SNP, которые попадают в 500 000 окон вверх и вниз от значительного SNP, этот шаг определит регион. Мне нужно сделать это для всех значимых SNP и сохранить каждый регион в списке или что-то подобное, чтобы провести дальнейший анализ. Например, в отображаемом кадре данных наиболее значимый SNP (т. Е. Ниже порога 0,001) для CHR == chr1 равен rs1000000, а для CHR == chr4 равен rs10000092. Таким образом, эти два SNP будут определять два региона, и мне нужно получить в каждом из этих регионов SNP, которые попадают в область 500 000 вверх и вниз от POS каждого из наиболее значимых SNP.

решение Код The ​​R обеспечивают по @eddi и @rafaelpereira является следующее:

library(data.table) # v1.9.7 (devel version) 
df <- fread("C:/folderpath/data.csv") # load your data 
setDT(df) # convert your dataset into data.table 
#1st step 
# Filter data under threshold 0.05 and Sort by CHR, POS 
df <- df[ P < 0.05, ][order(CHR, POS)] 
#2nd step 
df[, {idx = (1:.N)[which.min(P)] 
    SNP[seq(max(1, idx - 5e5), min(.N, idx + 5e5))]}, by = CHR] 
+0

делает весь DF fit i в ОЗУ? А 27 ГБ - это размер DF в памяти или размер файла CSV? Что такое 'POS' - или это' BP' в вашем образце DF? – MaxU

+0

Извините @MaxU, я отредактировал сообщение, чтобы сделать его более ясным. Размер файла составляет 27 ГБ, и он подходит для памяти, но когда у меня есть вся память, доступная для меня (я делаю это на небольшом сервере). Из-за этого я пытаюсь найти более эффективный способ, так как у меня есть несколько файлов, подобных этому. – user2380782

+0

Я думаю, ваш CSV-файл имеет гораздо больше столбцов рядом с '['SNP', 'CHR', 'BP', 'P']' - это правильно? Я сделал небольшой тестовый сгенерированный очень похожий DF с 4 столбцами и 20 М строк - он занял 534 МБ в ОЗУ и 861 МБ в качестве файла CSV. В этом случае вы обязательно должны использовать 'usecols = ['SNP', 'CHR', 'BP', 'P']' при чтении вашего DF, таким образом, вы НЕ будете читать столбцы, которые вам не нужны – MaxU

ответ

2

Прежде всего я бы настоятельно рекомендовал, чтобы перейти из CSV-файлов PyTables (хранение HDF) и хранить DF отсортировано по ['SNP','BP'], если это возможно, так как оно на порядок быстрее, позволяет условно выбирать (см. Параметр where) и обычно занимает меньше места - см. this comparison.

HDF store recipes

Вот рабочий пример сценария, который выполняет следующие действия:

  1. генерации образца DF (20M строк, 8 колонок: 'SNP', 'CHR', 'BP', 'P', 'SNP2', 'CHR2', 'BP2', 'P2'). Я намеренно удвоил количество столбцов, так как я думаю, что ваш CSV имеет гораздо больше столбцов, потому что размер моего сгенерированного CSV-файла с 20-миллиметровыми строками и 8 столбцами равен только 1,7 ГБ.
  2. сохранения сгенерированного DF в CSV файл (размер файла: 1.7 GB)
  3. чтение CSV файл в 1M-строках кусков (только для чтения первых 4 столбца)
  4. сортировки DF путем ['CHR','BP'] и сохранить результат как PyTable (.h5)
  5. читать из HDF магазина только те строки, в которых P < threshold
  6. чтения из HDF магазина все строки между min(SNP) - 500K и max(SNP) + 500K - Вы могли бы хотеть, чтобы улучшить эту часть

Код:

import numpy as np 
import pandas as pd 

############################## 
# generate sample DF 
############################## 
rows = 2*10**7 
chr_lst = ['chr{}'.format(i) for i in range(1,10)] 

df = pd.DataFrame({'SNP': np.random.randint(10**6, 10**7, rows).astype(str)}) 
df['CHR'] = np.random.choice(chr_lst, rows) 
df['BP'] = np.random.randint(10**6, 10**9, rows) 
df['P'] = np.random.rand(rows) 
df.SNP = 'rs' + df.SNP 

""" 
# NOTE: sometimes it gives me MemoryError !!! 
# because of that i did it "column-by-column" before 
df = pd.DataFrame({ 
    'SNP': np.random.randint(10**6, 10**7, rows).astype(str), 
    'CHR': np.random.choice(chr_lst, rows), 
    'BP': np.random.randint(10**6, 10**9, rows), 
    'P': np.random.rand(rows) 
}, columns=['SNP','CHR','BP','P']) 

df.SNP = 'rs' + df.SNP 
""" 

# make 8 columns out of 4 ... 
df = pd.concat([df]*2, axis=1) 
df.columns = ['SNP', 'CHR', 'BP', 'P', 'SNP2', 'CHR2', 'BP2', 'P2'] 

############################## 
# store DF as CSV file 
############################## 
csv_path = r'c:/tmp/file_8_cols.csv' 
df.to_csv(csv_path, index=False) 

############################## 
# read CSV file (only needed cols) in chunks 
############################## 
csv_path = r'c:/tmp/file_8_cols.csv' 
cols = ['SNP', 'CHR', 'BP', 'P'] 
chunksize = 10**6 

df = pd.concat([x for x in pd.read_csv(csv_path, usecols=cols, 
             chunksize=chunksize)], 
       ignore_index=True) 

############################## 
# sort DF and save it as .h5 file 
############################## 
store_path = r'c:/tmp/file_sorted.h5' 
store_key = 'test' 
(df.sort_values(['CHR','BP']) 
    .to_hdf(store_path, store_key, format='t', mode='w', data_columns=True) 
) 


############################## 
# read HDF5 file in chunks 
############################## 
store_path = r'c:/tmp/file_sorted.h5' 
store_key = 'test' 
chunksize = 10**6 

store = pd.HDFStore(store_path) 

threshold = 0.001 
store_condition = 'P < %s' % threshold 

i = store.select(key=store_key, where=store_condition) 

# select all rows between `min(SNP) - 500K` and `max(SNP) + 500K` 
window_size = 5*10**5 
start = max(0, i.index.min() - window_size) 
stop = min(store.get_storer(store_key).nrows, i.index.max() + window_size) 
df = pd.concat([ 
     x for x in store.select(store_key, chunksize=chunksize, 
           start=start, stop=stop,) 
       ]) 

# close the store before exiting... 
store.close() 

данные образца:

In [39]: df.head(10) 
Out[39]: 
       SNP CHR  BP   P 
18552732 rs8899557 chr1 1000690 0.764227 
3837818 rs1883864 chr1 1000916 0.145544 
13055060 rs2403233 chr1 1001591 0.116835 
9303493 rs5567473 chr1 1002297 0.409937 
14370003 rs1661796 chr1 1002523 0.322398 
9453465 rs8222028 chr1 1004318 0.269862 
2611036 rs9514787 chr1 1004666 0.936439 
10378043 rs3345160 chr1 1004930 0.271848 
16149860 rs4245017 chr1 1005219 0.157732 
667361 rs3270325 chr1 1005252 0.395261 
+0

жаль, что не ответил сначала, но я путешествовал. Я могу хранить файлы .h5. Я пробовал ваш пример, и он работал достаточно хорошо, я буду применять его во всех файлах, спасибо много! – user2380782

+0

@ user2380782, вы очень желанны! :) – MaxU

Смежные вопросы