我正在处理数据这种晦涩的文件格式:
SNP A1 A2 F1 I1 F2 I2 F3 I3
rs0001 A C 0.02 0.00 1.99
(注意前三个字段周围的空格)
标题很长(500k 条目),我想将其转换为如下内容:
SNP A1 A2 F1_I1 F2_I2 F3_I3
rs0001 A C 0.02 0.00 1.99
...这样无论是否删除不规则的空白,都更容易使用。作为参考,这也是可以接受的,只要它是一致的:
SNP A1 A2 F1_I1 F2_I2 F3_I3
rs0001 A C 0.02 0.00 1.99
有什么方法可以在 Unix/Linux 中重新格式化它吗?谢谢
答案1
您链接到的 plink 文件格式规范包含许多奇怪的细节。
首先,有一些示例,其中“F1 I1”和“F2 I2”清楚地表示两个不同(但相关)列的标题:
SNP A1 A2 F1 I1 F2 I2 F3 I3
rs0001 A C 0.98 0.02 1.00 0.00 0.00 0.01
rs0002 G A 0.00 1.00 0.00 0.00 0.99 0.01
Ix
但是,您还给出了一个示例,尽管存在标题,但看起来似乎缺少列值:
SNP A1 A2 F1 I1 F2 I2 F3 I3
rs0001 A C 0.02 0.00 1.99
对我来说,不清楚这个例子是否是错误的,或者数据实际上可以这样格式化。与该选项相关的评论dose1
似乎暗示可以使用一列剂量数据,而不是明显正常的两列格式:“剂量数据是 0..1,而不是 0..2 比例”。根据我的直觉,看起来只给出一个值的示例数据的标题混淆了。
如何处理不精确的规范和仅部分符合您对规范的理解的数据总是很困难。您需要决定数据解析器的宽容程度,以便它正确处理具有轻微标题问题的文件,同时仍然标记无效数据。
关于您的实际文件处理问题:如果有一些外部指示器告诉文件是否具有单值或双值剂量数据,我会Ix
使用您熟悉的任何脚本或文本处理语言完全删除标题,无论是sed
,awk
,perl
,python
管他呢。
答案2
您可以使用sed
以下内容覆盖第一行:
sed -E 's/(F[[:digit:]]+) (I[[:digit:]])/\1_\2/g;q' < file 1<> file
这很有效,因为我们只读取和写入第一行。这只是一件有效的事情,因为我们正在编写的一行与我们所读取的行的长度完全相同。如果Fn
和之间可能有多个空格,In
并且您只想用一个替换它们_
,则无法使用该方法,并且必须重写整个文件,例如:
perl -pi -e 's/(F\d+)\s+(I\d)/${1}_${2}/g if $. == 1' file
这将创建一个新的file
作为原始版本的编辑副本。一些sed
实现已经-i
从perl
.例如,使用 GNU sed
:
sed -Ei '1s/(F[[:digit:]]+)\s+(I[[:digit:]])/\1_\2/g' file
也会起作用。对于其他一些sed
实现,您需要-i ''
.您可能还需要替换\s
为[[:space:]]
.
要将一个或多个空白字符的任何序列替换为单个空格,您可以执行以下操作s/[[:space:]]+/ /g
(使用perl
,您需要添加该-l
选项,否则行分隔符(也是空白)将包含在模式空间中并最终被替换带空格)。
请注意,正则表达式匹配不是很严格,如果F<digits> I<digit>
在行中的任何位置查找,那么就会在例如中找到它。可以通过以下方式完成更严格的匹配:PAF12 I0ther
perl
perl -pi -e 's/(?<!\S)(F\d+)\s+(I\d+)(?!\S)/${1}_${2}/g if $. == 1' file
我们使用否定环顾运算符来检查前面和后面的内容是否不是非空白字符。