[英]merge multiple files by reading them simultaneously line by line?
我有3個文件:
文件1:
chrM 6423 5
chrM 6432 4
chrM 7575 1
chrM 7670 1
chrM 7933 1
chrM 7984 1
chrM 8123 1
chrM 9944 1
chrM 10434 1
chrM 10998 13
chrM 10999 19
chrM 11024 17
chrM 11025 29
chrM 11117 21
chrM 11118 42
chr1 197095350 2
chr1 197103061 1
chr1 197103582 1
chr1 197103615 1
chr1 197103810 3
chr1 197103885 2
chr1 197104256 1
chr1 197107467 4
chr1 197107480 5
chr1 197107498 6
chr1 197107528 10
chr1 197107805 1
chr1 197107806 1
chr1 197107813 1
chr1 197107814 1
chr1 197107839 1
chr1 197107840 1
chr1 197107855 1
chr1 197107856 1
chr1 197107877 1
chr1 197107878 1
chr1 197111511 1
chr1 197120122 1
chr1 197125503 1
chr1 197126978 1
chr1 197127070 1
chr1 197127084 1
chr1 197129731 2
chr1 197129758 2
chr1 197129765 1
chr1 197167632 2
chr1 197167652 2
chr1 197167668 2
chr1 197167682 2
chr1 197181417 1
chr1 197181973 3
chr1 197181975 3
chr1 197192150 0
文件2:
chrM 6423 5
chrM 6432 4
chrM 6582 1
chrM 6640 1
chrM 6643 1
chrM 7140 1
chrM 10998 7
chrM 10999 8
chrM 11024 10
chrM 11025 13
chrM 11117 12
chrM 11118 33
chr1 197095157 2
chr1 197095185 2
chr1 197098860 1
chr1 197105061 1
chr1 197107422 1
chr1 197107436 1
chr1 197107467 3
chr1 197107480 4
chr1 197107498 3
chr1 197107528 4
chr1 197107805 2
chr1 197107813 2
chr1 197107839 1
chr1 197108557 1
chr1 197108591 1
chr1 197108596 1
chr1 197108617 1
chr1 197108651 1
chr1 197139308 1
chr1 197139335 1
chr1 197143403 1
chr1 197143442 1
chr1 197145546 1
chr1 197148715 1
chr1 197148723 1
chr1 197148731 1
chr1 197148761 1
chr1 197153190 1
chr1 197166831 1
chr1 197166847 2
chr1 197166922 2
chr1 197166950 1
chr1 197166954 1
chr1 197167041 1
chr1 197167778 1
chr1 197167791 1
chr1 197167834 1
chr1 197167857 2
chr1 197167860 2
chr1 197167865 1
chr1 197167867 1
chr1 197167871 1
chr1 197167935 2
chr1 197167946 2
chr1 197167948 2
chr1 197167951 2
chr1 197167974 1
chr1 197167980 1
chr1 197168142 1
chr1 197168163 1
chr1 197168195 1
chr1 197168210 1
chr1 197169548 1
chr1 197169580 1
chr1 197169609 1
chr1 197183318 1
chr1 197183404 1
chr1 197184910 1
chr1 197184937 1
chr1 197186368 1
chr1 197191991 1
chr1 197192031 1
chr1 197192047 1
chr1 197192097 1
chr1 197192106 1
chr1 197192125 1
chr1 197192150 1
文件3:
chrM 6423 2
chrM 6432 1
chrM 6766 1
chrM 6785 1
chrM 10075 1
chrM 10084 1
chrM 10998 7
chrM 10999 8
chrM 11024 7
chrM 11025 14
chrM 11117 8
chr1 197095943 1
chr1 197096144 1
chr1 197104061 1
chr1 197104257 1
chr1 197107805 2
chr1 197122470 1
chr1 197123085 1
chr1 197123093 1
chr1 197126978 1
chr1 197142562 1
chr1 197157076 1
chr1 197157101 2
chr1 197162035 4
chr1 197167431 1
chr1 197167470 1
chr1 197167535 1
chr1 197167652 1
chr1 197167668 1
chr1 197167682 1
chr1 197167715 1
chr1 197167734 1
chr1 197167755 1
chr1 197168107 2
chr1 197168113 2
chr1 197172198 1
chr1 197172211 1
chr1 197172221 1
chr1 197172271 1
chr1 197175787 1
chr1 197175806 1
chr1 197175822 1
chr1 197192150 0
結果文件應如下所示:
6423 chrM 2 5 5
6432 chrM 1 4 4
6582 chrM 1
197093370 chr1 1
197093385 chr1 1
197094791 chr1 1
197094813 chr1 1
197094855 chr1 1
197094857 chr1 1
197095157 chr1 2
197095185 chr1 2
197095350 chr1 2
197095943 chr1 1
197096
現在我的代碼可以正常工作了,但是在while循環中有一個issu,在合並了許多記錄后,幾乎在合並文件的末尾停止了對該文件的寫操作,而只是寫了197096 ....最后調用):文件“”,第4行,在IndexError中:列表索引超出范圍
我認為這個錯誤與while循環有關。我不知道為什么會這樣。我也在更改我的代碼,如下所示:
看看她來的問題:您可以在結果文件中清楚地看到,在這種情況下,正在發生一些事情,即從單個文件讀取后,代碼無法從所有文件中讀取公共值,並且在這種情況下,它沒有給出應有的7575 7140之后
我有多個大文件,如果它們對於第2列都具有相同的值,我想逐行讀取它們並將它們合並在一起,為此我使用了將所有第二列val放在列表中然后發現其中的最小值。 從文件中寫入最小值的記錄(保存在mycover中的第3列)將顯示最小值的值記錄到新文件中。 然后在my_newfile[]
跟蹤讀取的文件以從文件中讀取下一行,並刪除已寫入文件的記錄。
希望足以理解。 我不知道如何重復該過程,直到所有文件都到達末尾,以便從所有文件中讀取所有記錄。 我的代碼如下:
import sys
import glob
import errno
path = '*Sorted_Coverage.txt'
filenames = glob.glob(path)
files = [open(i, "r") for i in filenames]
p=1
mylist=[]
mychr=[]
mycover=[]
new_mychr=[]
new_mycover=[]
new_mylist=[]
myfile=[]
new_myfile=[]
ab=""
g=1
result_f = open('MERGING_water_onlyselected.txt', 'a')
for j in files:
line = j.readline()
parts = line.split()
mychr.append(parts[0])
mycover.append(parts[2])
mylist.append(parts[1])
myfile.append(j)
mylist=map(int,mylist)
minval = min(mylist)
ind = [i for i, v in enumerate(mylist) if v == minval]
not_ind = [i for i, v in enumerate(mylist) if v != minval]
w=""
j=0
for j in xrange(len(ind)): # writing records to file with minimum value
if(j==0):
ab = (str(mylist[ind[j]])+'\t'+mychr[ind[j]]+'\t'+mycover[ind[j]])
else:
ab=ab+'\t'+mycover[ind[j]]
#smallest written on file
result_f.writelines(ab+'\n')
ab=""
for i in ind:
new_myfile.append(myfile[i])
#removing the records by index which have been used from mylists .
for i in sorted(ind, reverse=True):
del mylist[i]
del mycover[i]
del mychr[i]
del myfile[i]
#how to iterate the following code from all records of all files till the end of each file
while(True):
for i in xrange(len(new_myfile)):
print len(new_myfile)
myfile.append(new_myfile[i])
line = new_myfile[i].readline()
parts = line.split()
mychr.append(parts[0])
mycover.append(parts[2])
mylist.append(parts[1])
new_myfile=[]
mylist=map(int, mylist)
minval = min(mylist)
print minval
print("list values:")
print mylist
ind = [i for i, v in enumerate(mylist) if v == minval]
not_ind = [i for i, v in enumerate(mylist) if v != minval]
k=0
ab=""
for j in xrange(len(ind)): # writing records to file with minimum value
if(j==0):
ab = (str(mylist[ind[j]])+'\t'+str(mychr[ind[j]])+'\t'+str(mycover[ind[j]]))
k=k+1
else:
ab=ab+'\t'+str(mycover[ind[j]])
k=k+1
#smallest written on file
result_f.writelines(ab+'\n')
ab=""
for i in ind:
new_myfile.append(myfile[i])
#removing the records by index which have been used from mylists .
for i in sorted(ind, reverse=True):
del mylist[i]
del mycover[i]
del mychr[i]
del myfile[i]
result_f.close()
我一直在尋找解決方案很多天,但仍然找不到任何解決方案。 我不知道該代碼是否可以進一步改進,因為我對python很陌生。
如果有人可以提供幫助,我將不勝感激。
這是一個非常簡單的方法。 我不知道它在大文件上的表現如何(請參閱下面的評論)。
我假設所有文件都已經針對第二列進行了排序 。 另外,我假設第一列簽名('chrM','chr1')對於第二列中的固定值保持不變(我在下面將其稱為“ id”)。
該算法很簡單:
從每個文件讀取一行(我稱讀取行為“項”)
選擇一個具有最小“ id”(任意一個)的“ item”,並將其與“ current_item”進行比較:
如果兩者都具有相同的ID:將它們組合在一起:將“ current_item”寫入文件並將其替換為“ item”
從與讀取“ item”相同的文件中讀取一行(如果還有任何一行)
從1.開始重復,直到讀取所有文件中的所有行。
import glob
import numpy as np
path = './file[0-9]*'
filenames = glob.glob(path)
files = [open(i, "r") for i in filenames]
output_file = open('output_file', mode = 'a')
# last_ids[i] = last id number read from files[i]
# I choose np.array because of function np.argmin
last_ids = np.ones(shape = len(files)) * np.inf
last_items = [None] *len(files)
# Note: When we hit EOF in a file, the corresponding entries from "files", "last_items", and "last_ids" will be deleted
for i in range(len(files)):
line = files[i].readline()
if line:
item = line.strip().split()
last_ids[i] = int(item[1])
last_items[i] = item
# Find an item with the smallest id
pos = np.argmin(last_ids)
current_item = last_items[pos]
# Inverting positions, so that id is first
current_item[0], current_item[1] = current_item[1], current_item[0]
while True:
# Read next item from the corresponding file
line = files[pos].readline()
if line:
item = line.strip().split()
last_ids[pos] = int(item[1])
last_items[pos] = item
else:
# EOF in files[pos], so delete it from the lists
files[pos].close()
del(files[pos])
del(last_items[pos])
last_ids = np.delete(last_ids, pos)
if last_ids.size == 0:
# No more files to read from
break
# Find an item with the smallest id
pos = np.argmin(last_ids)
if last_items[pos][1] == current_item[0]:
# combine:
current_item.append(last_items[pos][2])
else:
# write current to file and replace:
output_file.write(' '.join(current_item) + '\n')
current_item = last_items[pos]
current_item[0], current_item[1] = current_item[1], current_item[0]
# The last item to write:
output_file.write(' '.join(current_item) + '\n')
output_file.close()
如果所有文件都足夠小以適合內存,那么以下代碼肯定會更短。 是否更快可能取決於數據。 (請參閱下面的評論。)
import glob
import pandas as pd
path = './file[0-9]*'
filenames = glob.glob(path)
df_list = []
# Read in all files and concatenate to a single data frame:
for file in filenames:
df_list.append(pd.read_csv(file, header = None, sep = '\s+'))
df = pd.concat(df_list)
# changing type for convenience:
df[2] = df[2].astype(str)
# sorting here is not necessary:
# df = df.sort_values(by = 1)
df2 = df.groupby(by = 1).aggregate({0:'first', 2: lambda x: ' '.join(x)})
df2.to_csv('output_file', header = None)
# (Columns in 'output_file' are separated by commas. )
我在1000-10000行的幾個輸入文件上測試了這兩種解決方案。 通常,基本解決方案速度更快(有時是另一種解決方案速度的兩倍)。 但這取決於數據的結構。 如果有很多重復的“ id”,那么熊貓可能會更具優勢(相差很小)。
我認為這兩種方法都可以與帶有選項chunksize
或iterator
的pd.read_csv
結合使用。 這樣,我們就可以讀入更大的數據塊並對其進行操作(而不是單行)。 但是我現在不確定它是否會導致更快的代碼。
如果失敗(並且沒有人找到更好的方法),則可以考慮在Amazon Web Services上運行map reduce算法。 在一開始有一些工作可以解決所有設置,但是map-reduce算法對於這類問題非常簡單。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.