簡體   English   中英

子集巨大的分隔文件的有效方法

[英]Efficient way to subset a huge delimited file

我之前曾發布過一個問題,然后才能使用R子集遞歸data.frame ,但是文件太大 ,以至於我需要大量時間和RAM內存才能讀取它。 我想知道是否可以在python中使用pandas來做同樣的事情,因為我是python的新手,pandas似乎更類似於R,至少在其sintax上。 這是我以前的帖子的摘要:

上一篇文章:我有一個制表符分隔的文件,其中包含近1500萬行,其大小為27GB。 我需要一種有效的方法來基於兩個條件對數據進行子集化。 我可以這樣做是一個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    

我首先要做的是選擇那些P值低於閾值的SNP,然后按CHR和BP排序此子集。 一旦有了這個子集,我就需要從有效的SNP向上和向下獲取落入500,000窗口的所有SNP,此步驟將定義一個區域。 我需要對所有重要的SNP都執行此操作,並將每個區域存儲到列表或類似內容中以進行進一步的分析。 例如,在顯示的數據幀中,CHR == chr1的最高有效SNP(即低於0.001的閾值)為rs1000000,而CHR == chr4的最高有效SNP為rs10000092。 因此,這兩個SNP將定義兩個區域,我需要在這些區域的每一個中獲取從每個最高SNP的POS上下掉入500,000的SNP。

@eddi和@rafaelpereira提供的R代碼解決方案如下:

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]

首先,我會強烈建議從CSV文件切換到PyTables(HDF存儲)和存儲您的DF排序['SNP','BP']如果有可能,因為它是快幾個數量級,允許有條件地選擇(見where參數),通常占用較少的空間-請參見此比較

HDF商店食譜

這是一個有效的示例腳本,該腳本執行以下操作:

  1. 生成樣本DF(20M行,8列: 'SNP', 'CHR', 'BP', 'P', 'SNP2', 'CHR2', 'BP2', 'P2' )。 我故意將列數加倍,因為我認為您的CSV具有更多的列,因為生成的具有20M行和8列的CSV文件的大小僅為 1.7GB。
  2. 將生成的DF保存到CSV文件(文件大小:1.7 GB)
  3. 以1M行的塊讀取CSV文件(僅讀取前4列)
  4. ['CHR','BP']排序DF並將結果另存為PyTable(.h5)
  5. 從HDF讀取的內容僅存儲P < threshold那些行
  6. 從HDF讀取存儲min(SNP) - 500Kmax(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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM