我有一个这样的文件:
NODE_1_length_4014_cov_1.97676 1 1
NODE_1_length_4014_cov_1.97676 2 1
NODE_1_length_4014_cov_1.97676 3 1
NODE_1_length_4014_cov_1.97676 4 1
NODE_1_length_4014_cov_1.97676 5 1
NODE_1_length_4014_cov_1.97676 6 1
NODE_1_length_4014_cov_1.97676 7 1
NODE_1_length_4014_cov_1.97676 8 1
NODE_1_length_4014_cov_1.97676 9 1
NODE_1_length_4014_cov_1.97676 10 1
我想根据字符' _'将第一列拆分为新列,如下所示:
1 4014 1.97676 1 1
1 4014 1.97676 2 1
1 4014 1.97676 3 1
1 4014 1.97676 4 1
1 4014 1.97676 5 1
1 4014 1.97676 6 1
1 4014 1.97676 7 1
1 4014 1.97676 8 1
1 4014 1.97676 9 1
1 4014 1.97676 10 1
我知道我可以在熊猫中做到这一点:
df.columns = ['contig','loci','depth']
df['node'] =df.contig.str.split(r'_').str[1]
df['len'] =df.contig.str.split(r'_').str[3]
df['cov'] =df.contig.str.split(r'_').str[5]
df.drop(['contig'], axis=1, inplace=True)
但是我的文件太大(> 2G)并且我的计算机上需要永远做这件事。有没有其他更快的方法来做到这一点?根据我的经验,Pandas通常很慢处理大文件,虽然它很容易使用。
非常感谢。
答案 0 :(得分:1)
使用awk
$ awk -F'_' '{print $2, $4,$6,$7,$8}' infile
1 4014 1.97676 1 1
1 4014 1.97676 2 1
1 4014 1.97676 3 1
1 4014 1.97676 4 1
1 4014 1.97676 5 1
1 4014 1.97676 6 1
1 4014 1.97676 7 1
1 4014 1.97676 8 1
1 4014 1.97676 9 1
1 4014 1.97676 10 1
答案 1 :(得分:1)
您也可以使用cut
$ cut -d_ --output-delimiter=$'\t' -f2,4,6 ip.txt
1 4014 1.97676 1 1
1 4014 1.97676 2 1
1 4014 1.97676 3 1
1 4014 1.97676 4 1
1 4014 1.97676 5 1
1 4014 1.97676 6 1
1 4014 1.97676 7 1
1 4014 1.97676 8 1
1 4014 1.97676 9 1
1 4014 1.97676 10 1
-d
选项允许指定输入分隔符--output-delimiter=$'\t'
指定输出分隔符。注意使用$'\t'
作为Tab字符(不确定这是否适用于所有shell,我在bash
上进行了测试)
速度比较
$ cut --version | head -n1
cut (GNU coreutils) 8.25
$ awk --version | head -n1
GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.4, GNU MP 6.1.0)
$ perl -0777 -lne 'print $_ x 1000000' ip.txt > f1
$ du -h f1
363M f1
$ time cut -d_ --output-delimiter=$'\t' -f2,4,6 f1 > t1
real 0m2.097s
user 0m1.660s
sys 0m0.324s
$ time cut -d_ --output-delimiter=$'\t' -f2,4,6 f1 > t1
real 0m3.267s
user 0m1.612s
sys 0m0.376s
$ time awk -F'_' -v OFS='\t' '{print $2,$4,$6}' f1 > t2
real 0m17.394s
user 0m16.200s
sys 0m0.328s
$ time awk -F'_' -v OFS='\t' '{print $2,$4,$6}' f1 > t2
real 0m16.329s
user 0m15.336s
sys 0m0.432s
$ diff -s t1 t2
Files t1 and t2 are identical
如果输入为ASCII,则awk
显示出很多改进
$ time LC_ALL=C awk -F'_' -v OFS='\t' '{print $2,$4,$6}' f1 > t2
real 0m7.783s
user 0m6.832s
sys 0m0.428s
答案 2 :(得分:0)
使用:
df[['node','len','cov']] = df.contig.str.split(r'_', expand=True).iloc[:,[1,3,5]]
df.drop(['contig'], axis=1, inplace=True)
print (df)
loci depth node len cov
0 1 1 1 4014 1.97676
1 2 1 1 4014 1.97676
2 3 1 1 4014 1.97676
3 4 1 1 4014 1.97676
4 5 1 1 4014 1.97676
5 6 1 1 4014 1.97676
6 7 1 1 4014 1.97676
7 8 1 1 4014 1.97676
8 9 1 1 4014 1.97676
9 10 1 1 4014 1.97676
如果没有NaN
s:
df[['node','len','cov']] = pd.DataFrame([x.split('_') for x in df['contig'].values.tolist()])
.iloc[:,[1,3,5]]
df.drop(['contig'], axis=1, inplace=True)
print (df)
loci depth node len cov
0 1 1 1 4014 1.97676
1 2 1 1 4014 1.97676
2 3 1 1 4014 1.97676
3 4 1 1 4014 1.97676
4 5 1 1 4014 1.97676
5 6 1 1 4014 1.97676
6 7 1 1 4014 1.97676
7 8 1 1 4014 1.97676
8 9 1 1 4014 1.97676
9 10 1 1 4014 1.97676
答案 3 :(得分:0)
使用Bash:
struct foo
答案 4 :(得分:0)
也很好。
sed -E 's/[^0-9.]+/\t/g;s/\t//' infile