我有多个格式为:chr 位置值的文件。
我想将它们以格式“chr”,“position”,“samp1”,“samp2”,“samp3”,“samp4”,......
例如:
样本1:
chr position value
1 3774318 1
1 3774319 1
1 3775200 2
1 3775201 7
1 3775202 70
1 3775203 7
1 3775204 270
1 3775205 3
1 3775206 5
样本 2:
chr position value
1 3775200 1
1 3775201 1
1 3775202 10
1 3775203 1
1 3775204 12
1 3775205 1
1 3775206 13
1 3775207 1
1 3775208 1
1 3775209 18
(等等 ...)
所需的输出文件:/我在输出文件中放入随机值
chr, position, value-samp1, value-samp2, value-samp3, value-samp4
1 50204 2 17 5 2
1 50205 2 17 5 2
1 50206 2 18 5 2
1 50207 2 19 5 3
1 50208 3 19 5 3
1 50209 3 19 5 3
我尝试了 join、merge、cat,但它没有按我的预期工作。我是初学者。您有什么想法可以做到吗?
(编者注:这是使用您提供的实际数据描述的操作示例。)
chr position samp1 samp2
1 3774318 1 0
1 3774319 1 0
1 3775200 2 1
1 3775201 0 1
1 3775202 70 10
1 3775203 7 1
1 3775204 270 12
1 3775205 3 1
1 3775206 5 13
1 3775207 7 1
1 3775208 0 1
1 3775209 0 18
答案1
另一种awk
方法。NA
对于输入文件之一中不存在特定变体的情况,将打印此文件:
awk '{ if(FNR==1){files[fnum++]=FILENAME}else{var[$1"\t"$2][FILENAME]=$3}} END{ for(v in var){for(file in files){if(! var[v][files[file]]){var[v][files[file]]="NA"}}}printf "chr\tposition "; for(i=1;i<=fnum;i++){printf "value-samp%s\t",i;} print "";for(v in var){ printf "%s ",v; for(file in var[v]){if(file in var[v]); else{var[v][file]="NA";} printf "%s\t", var[v][file] } print ""}}' s1 s2
或者,如果你不太喜欢简洁的话:
awk '{
if(FNR==1){
files[fnum++]=FILENAME
}
else{
var[$1"\t"$2][FILENAME]=$3
}
}
END{
for(v in var){
for(file in files){
if(! var[v][files[file]]){
var[v][files[file]]="NA"
}
}
}
printf "chr\tposition ";
for(i=1;i<=fnum;i++){
printf "value-samp%s\t",i;
}
print "";
for(v in var){
printf "%s ",v;
for(file in var[v]){
if(file in var[v]);
else{
var[v][file]="NA";
}
printf "%s\t", var[v][file];
}
print "";
}
}' s1 s2
s1
将和更改s2
为您正在使用的实际文件名。在示例输入上运行上述命令将返回:
chr position value-samp1 value-samp2
1 3774318 1 NA
1 3775200 2 1
1 3774319 1 NA
1 3775201 7 1
1 3775202 70 10
1 3775203 7 1
1 3775204 270 12
1 3775205 3 1
1 3775206 5 13
1 3775207 NA 1
1 3775208 NA 1
1 3775209 NA 18
答案2
服用这个解决方案对于与基础类似的问题,我们需要对其进行微调以获得您想要的结果。这不是答案,只是一个大纲,并使用了一些伪代码(原文如此?)概述必须做什么。
Linux 的回顾加入命令和它的能力对于成功的解决方案至关重要。请注意,在加入之前,必须按特定字段(此处使用染色体编号,字段 2)对每个输入文件进行排序。
因为 join 只能连接两个文件,所以我们需要多次单步执行 join,因此需要一些编程结构和控制机制。我们还需要修改数据本身,因为您指定的空白(空)值应替换为 0。
1)将第一个数据文件复制到不同的名称,也许样本_0
2)检查每一行样本_0 字段 3 的值。如果为 null,则替换为 0 。
3)初始化值X以匹配数据文件的编号。
4) 创建一个 for/next 循环来连续使用每个数据文件。您有多少个数据文件?那么,为了使这项工作无需每次运行脚本时都对其进行编辑,请使用 for/next 循环运行脚本,直到用完数据文件为止。
5) 在 for/next 循环中,做两件事。
5A) 检查下一个文件的每一行中字段 3 的值。如果为 null,则替换为 0 。
5B) 执行加入包括不可配对的线路(与-A选项)在文件的染色体编号(字段 2)上样本_0和文件样本_x 具有自动格式化功能(使用选项-o 自动)所以它合并所有染色体的数据行,而不仅仅是那些在两个文件中都有数据的染色体样本_0和文件样本_x。将输出写入文件样本_0。
6) 如果还有另一个数据文件,则增加X然后返回并再次执行3)。如果所有数据文件都已连接,请退出 for/next 循环,因为您已完成。
答案3
chr
我暂时忽略了它,因为如果它始终为 1,那么就可以安全地忽略它,否则 OP 需要解释它是如何适应的。
awk 'BEGIN {printf "position " }
FNR>1{
if (FNR==2) {nof+=1; printf ("%s%s " ,"Sam", nof )};
pos[$2]=$2; data[$2, nof]=$3}
END { printf "\n"; for (p in pos) {printf ("%s ", pos[p]);
for (d=1;d<=nof;d++) printf ("%s ", data[p,d]+0); print "\n"}
}' file1 file2 | column -t
输出
position Sam1 Sam2
3774318 1 0
3774319 1 0
3775200 2 1
3775201 7 1
3775202 70 10
3775203 7 1
3775204 270 12
3775205 3 1
3775206 5 13
3775207 0 1
3775208 0 1
3775209 0 18
演练
开始时打印第一个列标题
awk 'BEGIN {printf "position " }
忽略所有第一行作为标题
FNR>1{
在每个文件的第二行增加文件数并打印标题
if (FNR==2) {nof+=1; printf ("%s%s " ,"Sam", nof )};
对于标题之后的每一行,将位置放入数组中pos
;设置另一个数组data
,其中包含由文件(样本)编号sam
索引的值pos
pos[$2]=$2; data[$2, nof]=$3}
读入所有文件后,newline
在标题上打印 a,然后迭代pos
打印每个位置
END { printf "\n"; for (p in pos ) {printf ("%s ", pos[p]);
然后迭代data
按p
和sam
/file 编号索引的数组,将 0 添加到任何空data
值,这样即使没有数据也会打印一些内容;然后打印一个newline
for (d=1;d<=nof;d++) printf ("%s ", data[p,d]+0); print "\n"}
只需输入文件并通过管道输出column
即可使其看起来不错
}' file1 file2 | column -t
添加了字符假设它是另一个索引
awk 'BEGIN {printf "chr position " }
FNR>1{
if (FNR==2) {nof+=1; printf ("%s%s " ,"Sam", nof )};
chr[$1]=$1; pos[$2]=$2; data[$1, $2, nof]=$3}
END { printf "\n"; for (c in chr) {for (p in pos ) {printf ("%s %s ", chr[c], pos[p]);
for (d=1;d<=nof;d++) printf ("%s ", data[c, p, d]+0); print "\n"}
}}' file1 file2 | column -t
答案4
使用米勒(https://github.com/johnkerl/miller)你可以运行
mlr --c2p --ifs ' ' --repifs \
sort -f chr,position,value \
then nest --implode --values --across-records -f value \
then nest --explode --across-fields --values -f value \
then unsparsify then clean-whitespace input0*.csv >output.csv
并获得
chr position value_1 value_2
1 3774318 1 -
1 3774319 1 -
1 3775200 1 2
1 3775201 1 7
1 3775202 10 70
1 3775203 1 7
1 3775204 12 270
1 3775205 1 3
1 3775206 13 5
1 3775207 1 -
1 3775208 1 -
1 3775209 18 -
笔记:
- 您必须使命令适应输入文件的名称。在我的例子中我使用了
input0*.csv
- 如果您想要真正的 CSV 输出,请更改
--c2p
为--csv
.