Deb*_*raj 5 command-line awk text-processing bioinformatics
我有几个大的 .csv 文件,我想将它们转换为二进制(1 和 0)格式。其中,除前两个字段外,所有包含文本的单元格都将变为 1,0 将保持为 0。
head Test.csv
Iss1,1,0,0,Hsapiens-I34,0,0,0,Mmusculus-H01,0,0
Iss1,11,0,Scerevisiae-U09,Hsapiens-I05,0,0,0,0,0,0
Iss1,21,0,0,Hsapiens-I05,0,0,0,Hsapiens-I31,0,0
Iss1,31,0,0,Mmusculus-H13,0,0,0,0,0,Hsapiens-I31
Iss1,41,0,Scerevisiae-U09,0,0,0,0,0,0,Hsapiens-I21
Iss1,51,0,0,0,0,0,0,Scerevisiae-U25,0,Hsapiens-I21
Iss1,61,0,0,Hsapiens-I34,0,0,0,Mmusculus-H13,0,0
Run Code Online (Sandbox Code Playgroud)
预期结果是
head Test.csv
Iss1,1,0,0,1,0,0,0,1,0,0
Iss1,11,0,1,1,0,0,0,0,0,0
Iss1,21,0,0,1,0,0,0,1,0,0
Iss1,31,0,0,1,0,0,0,0,0,1
Iss1,41,0,1,0,0,0,0,0,0,1
Iss1,51,0,0,0,0,0,0,1,0,1
Iss1,61,0,0,1,0,0,0,1,0,0
Run Code Online (Sandbox Code Playgroud)
其中文件中的所有文本都转换为 1。
如果有人能给我一些关于如何克服这个问题的建议,我将不胜感激。
谢谢
Fel*_*xJN 12
和awk你一起可以做:
awk 'BEGIN {FS=OFS=","} {for (i=3;i<=NF;i++) {$i==0?1:$i=1}} 1' test.csv
Run Code Online (Sandbox Code Playgroud)
BEGIN {FS=OFS=","}- 将输入和输出分隔符设置为逗号for (i=3;i<=NF;i++)- 我们将循环字段 3 直到最大字段数NF$i==0?1:$i=1- 如果字段i为0,则不执行任何操作 ( 1),否则将字段设置i为11-awk将 1 解释为 true 并默认打印记录正如 @EdMorton 的评论中所建议的,使用 is$1=($i!=0)是一个更短的替代方案$i==0?1:$i=1
$i!=0如果 field 不是i则为逻辑测试。将返回for和for并相应地覆盖字段值 0awk1true0false使用 Perl:
$ perl -F, -lne 'my @out = map { /^0$/ ? 0 : 1 } splice @F,2;
unshift @out, @F;
print join(",",@out)' Test.csv
Iss1,1,0,0,1,0,0,0,1,0,0
Iss1,11,0,1,1,0,0,0,0,0,0
Iss1,21,0,0,1,0,0,0,1,0,0
Iss1,31,0,0,1,0,0,0,0,0,1
Iss1,41,0,1,0,0,0,0,0,0,1
Iss1,51,0,0,0,0,0,0,1,0,1
Iss1,61,0,0,1,0,0,0,1,0,0
Zed227,28897871,0,0,1,0,0,0,1,0,0
Zed227,28897881,0,1,1,0,0,0,0,0,0
Zed227,28897891,0,0,1,0,0,0,1,0,0
Zed227,28897901,0,0,0,0,0,0,0,0,1
lad1,1,0,1,0,0,0,0,0,0,1
lad1,11,0,1,0,0,0,0,1,0,0
lad1,21,0,0,1,0,0,0,0,0,0
Run Code Online (Sandbox Code Playgroud)
怎么运行的:
Perl 命令行选项:
-F,选项告诉 perl 使用逗号作为字段分隔符。 -F还触发每个输入行的自动拆分,字段进入名为的数组@F- 这类似于 awk 自动拆分字段为 $1、$2、$3 等。-l告诉 perl 自动处理行结束符,例如从输入中删除换行符并将它们添加回 的输出中print。-n使 perl 运行类似于sed -n- 即读取并处理每一行,但仅打印明确告知的内容。-e告诉 perl 下一个参数是要运行的脚本。剧本:
perlsplice()删除数组的一部分,并将该部分返回给调用者...因此splice @F,2删除并返回除数组的前两个元素之外的所有元素@F。实际上,splice可以做的事情远不止这些,但这就是我在这里使用它的全部目的。perldoc -f splice详情请参阅。
perl 的map函数将表达式应用于数组(列表)的每个元素。在这种情况下,列表是 splice 函数返回的元素。如果元素与正则表达式匹配,则此处使用的表达式map返回;如果不匹配,则返回 1。 返回一个数组,该数组被分配给数组变量。详情请参阅。0/^0$/map@outperldoc -f map
顺便说一句,我可以使用eq带有三元运算符(即 )的字符串相等比较( )$_ eq "0" ? 0 : 1而不是正则表达式。字符串比较会比像这样的简单正则表达式更快,但除非您的 .csv 文件很大(数千行),否则不会明显如此。即便如此,最好还是使用eq——我使用的唯一原因/^0$/是它是我首先想到的。
数字比较(==, ie $_ == 0 ? 0 : 1)无法满足您的需求,因为不以数字开头的字符串(忽略任何前导空格)将计算为 0,而您需要将它们变为 1。
unshift与此相反shift- 它将元素添加到数组的开头。在本例中,它将数组的剩余内容@F(即未被 删除的前两个元素splice)添加到数组的开头@out。看perldoc -f unshift。
最后,该@out数组用逗号连接并打印。有关join所使用函数的详细信息,请参见perldoc -f join。
这可以简化为只有一个语句:
perl -F, -lne 'print join ",", @F[0..1], map { /^0$/ ? 0 : 1 } splice @F,2' Test.csv
Run Code Online (Sandbox Code Playgroud)
不需要作为@out临时变量,也不需要unshift。
它的工作原理完全相同,但更难理解,特别是对于不熟悉 perl 的人......你必须从后到前阅读它,这样你才能知道每个函数正在获得什么输入。