我有一个非常大的tsv文件,需要删除几个列。我找到了CSV模块,并在下面给出了一个类似问题的答案(参见下面的脚本)。但是我需要删除大量的列,并且不希望键入要删除的每列的每个索引。即从一个包含689513列的文件,我想删除列628715到650181,并删除列653321到689513.(如果删除两个集合太难了,我可以去除最后一个,即, 653321到689613,或等效的653321到文件的末尾)。对不起基本问题;我是脚本和丢失的新手......并且CSV模块页面没有详细说明删除列范围。我尝试在R中执行此操作但第一个单元格条目为空(请参阅下面的代码示例列表)。我的文件是一个tsv tab分隔文件,但我收集到的可以使用命令将分隔符设置为\ t来纠正。任何帮助是极大的赞赏!!! (注意:不幸的是,我需要在我的列的名称中包含冒号,即2L:1274完全是一列的名称)。
import csv
with open("source","rb") as source:
rdr= csv.reader( source )
with open("result","wb") as result:
wtr= csv.writer( result )
for r in rdr:
wtr.writerow( (r[0], r[1], r[3], r[4]) )
2L:1274 2L:2425 2L:2853 3L:4 3L:5 3L:7
indivBCsusceptiblePL7A10_TATAGT NA NA NA NA NA NA
indivBCsusceptiblePL7A11_CCTGAA NA 5 NA NA NA NA
indivBCsusceptiblePL7A12_CAATAT NA NA 6 7 8 9
indivBCsusceptiblePL7A1_CCGAAT NA NA NA NA NA NA
答案 0 :(得分:2)
您可以使用del
删除列表的切片。
with open('in.tsv', 'r') as fin, open('out.tsv', 'w') as fout:
reader = csv.reader(fin, dialect='excel-tab')
writer = csv.writer(fout, dialect='excel-tab')
for row in reader:
# delete indices in reverse order to avoid shifting earlier indices
del row[653321:689513+1]
del row[628715:650181+1]
writer.writerow(row)
答案 1 :(得分:1)
你可以用很少的内存使用Python来做到这一点。
首先定义一个描述你的tsv格式的方言。有关详细信息,请参阅the documentation on dialects。
class TsvDialect(csv.Dialect):
delimiter = '\t'
quoting = csv.QUOTE_NONE
escapechar = None
# you can just pass this class around, or you can register it under a name
csv.register_dialect('tsv', TsvDialect)
然后,您可以浏览每一行并复制到新的tsv:
with open('source.tsv', 'rb') as src, open('result.tsv', 'wb') as res:
csrc = csv.reader(src, dialect='tsv')
cres = csv.writer(res, dialect='tsv')
for row in csrc:
cres.writerow(row)
这是一个简单的副本。由于您只需要一些行,因此只允许复制这些行。
Python的列表是零索引的(第一列是第0列,而不是第1列);和索引切片不包括最后一项(wholelist[:2]
与[wholelist[0], wholelist[1]]
相同)。请记住这些,以避免出现错误!
with open('source.tsv', 'rb') as src, open('result.tsv', 'wb') as res:
csrc = csv.reader(src, dialect='tsv')
cres = csv.writer(res, dialect='tsv')
for row in csrc:
# remove [628714:650181] and [653320:689512]
newrow = row[:628714] # columns before 628714
newrow.extend(row[650181:653320]) # columns between 650180 and 653320
cres.writerow(newrow)
或者,您可以删除不需要的列,而不是将所需的列复制到新行,而是以代码清晰度为代价来节省一些内存:
for row in csrc:
# remove [628714:650181] and [653320:689512]
# be sure to remove in reverse order!
del row[653320:689512]
del row[628714:650181]
cres.writerow(row)
如果您需要经常执行此操作,可以将列切割(任一方法,使用您熟悉的任何索引)抽象为函数。
您可能还想查看csvkit python library and command-line tools,特别是其命令行工具csvcut,它似乎可以完全按照您的要求从命令行执行。
答案 2 :(得分:0)
使用2 GB或更多内存时,应该可以在内存中加载数据集,删除所需的列,并将内容写入文件。这可以在R或python中轻松完成。对于R:
dat = read.table("spam.tsv", ...)
dat = dat[-c(1,5)] # delete row 1 and 5
write.csv(dat, ....)
使用apply
循环或for
循环可以轻松地以块的形式完成此操作。我使用apply
样式:
read_chunk = function(chunk_index, chunk_size, fname) {
dat = read.table(fname, nrow = chunk_size, skip = (chunk_id - 1) * chunk_size, ...)
dat = dat[-c(1,5)] # delete row 1 and 5
write.csv(dat, append = TRUE, ....)
}
tot_no_lines = 10000 # for example
chunk_size = 1000
sapply(1:(tot_no_lines / chunk_size), read_chunk)
请注意,这是R风格代码,可用作灵感,没有可用的R代码。
答案 3 :(得分:0)
您可以动态构建输出行:
for r in rdr:
outrow = []
for i in range(0, 628714):
outrow.append(r[i])
for i in range(650181, 653320):
outrow.append(r[i])
wtr.writerow( outrow )
我想你可以用输入行r的切片更简洁地做到这一点,沿着以下几行:
outrow = r[0:628714)
outrow.extend(r[650181:653320)
wrt.writerow( outrow )
执行速度可能不是最快,但写作肯定更容易。
答案 4 :(得分:0)
你在Linux上吗?然后保存hazzle并使用shell中的csvtool
:
csvtool col 1-500,502-1000 input.csv > output.csv
您也可以设置分隔符等,只需输入csvtool --help
即可。非常容易使用。