有效地连接多个文件

有效地连接多个文件

我知道有一些帖子可以加入多个文件,但花了很多时间。我有多个文件,其中第一列用于患者 ID,然后我想根据第一列中的 ID 号加入多个文件。

下面的代码仍然有效,但花了很多时间。因此,有人知道执行此过程的更有效方法吗?

for PHENO in A B C D E F G H I J K L M
do
    join -a1 -a2 -e 1 -o auto chr2_${PHENO} chr3_${PHENO} >${PHENO}
done

for PHENO in A B C D E F G H I J K L M
do
    for file in chr5_${PHENO} chr11_${PHENO} chr14_${PHENO} chr20_${PHENO} \
    chr21_${PHENO} chr22_${PHENO} chr6_${PHENO} chr9_${PHENO} chr13_${PHENO} \
    chr18-1_${PHENO} chr18-2_${PHENO} chr1-1_${PHENO} chr1-2_${PHENO} \
    chr1-3_${PHENO} chr8-1_${PHENO} chr8-2_${PHENO} chr17-1_${PHENO} \
    chr17-2_${PHENO} chr19-1_${PHENO} chr19-2_${PHENO} chr19-3_${PHENO} \
    chr19-4_${PHENO} chr4-1_${PHENO} chr4-2_${PHENO} chr4-3_${PHENO} \
    chr4-4_${PHENO} chr7-1_${PHENO} chr7-2_${PHENO} chr7-3_${PHENO} \
    chr10-1_${PHENO} chr10-2_${PHENO} chr10-3_${PHENO} chr10-4_${PHENO} \
    chr12-1_${PHENO} chr12-2_${PHENO} chr12-3_${PHENO} chr12-4_${PHENO} \
    chr15-1_${PHENO} chr15-2_${PHENO} chr15-3_${PHENO} chr16-1_${PHENO} \
    chr16-2_${PHENO} chr16-3_${PHENO}; do
        join -a1 -a2 -e 1 -o auto ${PHENO} "$file" >${PHENO}.1
        mv ${PHENO}.1 ${PHENO}
    done
done

所有文件如下。 150001名患者,是否患病显示为0或1。例如chr2_${PHENO}

ID Disease
1 0
2 1
3 0 
4 1
5 1
....

150000 0 
150001 1

例如,chr3_${PHENO}

ID Disease
1 1
2 1
3 1 
4 0
5 0
....

150000 0 
150001 0

先感谢您!

答案1

好的。这是本身不是答案,但也许是为了澄清事情的帖子。

将您需要的内容纳入您的问题中。

(抱歉,知道这不是通常做事的方式,但是......)


这与您的文件和所需的结果相似吗?

这是两个示例脚本。首先生成虚拟文件:

  • chr1_Achr6_A
  • 字符1_Bchr6_B
  • chr1_Cchr6_C

按使用排序LC_ALL=C sort -k 1b,1

#! /bin/bash
for p in A B C; do
    for i in $(seq 1 6); do
        f="chr${i}_$p"
        printf 'ID %s\n' "$i.$p" >"$f"
        paste <(shuf -n 24 -i 1-222) <(shuf -n 24 -i 0-1 -r) | \
            LC_ALL=C sort -k 1b,1 >>"$f"
    done
done

给出一个样本组,例如:paste chr* | column -t

ID   1.A  ID   1.B  ID   1.C  ID   2.A  ID   2.B  ID   2.C  ...
116  1    107  1    101  0    110  1    105  1    111  0    ...
126  1    11   1    105  0    111  1    106  1    117  1    ...
131  1    111  0    106  0    121  0    113  0    121  0    ...
141  0    133  0    110  0    124  0    147  0    145  0    ...
167  1    135  1    113  1    135  0    154  0    146  1    ...
...

不确定这是否正确,您决定。


第二个脚本是您的修改版本(例如,使用破折号表示缺失,以便将其与真实数据区分开来):

#! /bin/bash

for PHENO in A B C; do
    join -a1 -a2 -e - -o auto chr1_${PHENO} chr2_${PHENO} >${PHENO}
done

for PHENO in A B C; do
    for n in 3 4 5 6; do
        file="chr${n}_$PHENO"
        join -a1 -a2 -e - -o auto ${PHENO} "$file" >${PHENO}.1
        mv ${PHENO}.1 ${PHENO}
    done
done

生成三个文件 A、B 和 C:

$ paste A B C | column -t
ID   1.A  2.A  3.A  4.A  5.A  6.A  ID   1.B  2.B  3.B  4.B  5.B  6.B  ID   1.C  2.C  3.C  4.C  5.C  6.C
10   -    -    1    1    -    -    101  -    -    1    -    -    1    101  0    -    0    -    -    1
100  -    -    -    0    -    -    102  -    -    -    -    -    0    103  -    -    -    -    -    0
102  -    -    1    -    0    -    105  -    1    0    -    0    -    105  0    -    -    -    -    -
108  -    -    0    -    -    -    106  -    1    -    -    -    1    106  0    -    -    -    1    -
109  -    -    -    -    -    1    107  1    -    -    -    -    -    107  -    -    -    -    -    0
110  -    1    -    -    -    -    109  -    -    -    -    -    0    108  -    -    -    -    -    0
111  -    1    -    -    -    -    11   1    -    -    -    -    -    109  -    -    -    1    0    -
116  1    -    -    -    -    -    111  0    -    -    -    -    -    110  0    -    -    -    -    -
117  -    -    -    -    1    -    113  -    0    -    -    -    -    111  -    0    -    -    -    -

...

# or
# paste <(sort -n A) <(sort -n B) <(sort -n C) | column -t

答案2

我建议采用不同的方法:

  1. 确保所有文件都chr1_A包含完整的 15000 个条目,并且已排序!这还包括在缺失的地方填充“1”。
  2. 将这些文件中的每一个仅减少到“疾病”列。
  3. 为每个 PHENO 创建一个包含“ID”列的文件。
  4. 粘贴而不是将现在减少的文件与 ID 列文件连接起来。 (它们已排序并且行必须从第 1 点开始匹配)
  5. 创建脚本以进行并行化。

如何:

  1. +2。通过awk-script,将其命名为例如fillrows.awk

    NR>1 {disease[$1]=$2}
    END {print FILENAME
         for (i=1;i<=15000;i++) {
           if (disease[i]!="")
              {print disease[i] > FILENAME"_red"}
           else {print "1" > FILENAME"_red"}
         }
    }
    

这会生成一个chr1_A类似的文件

 ID Disease
 2  0
 5  1

chr1_A_red(最多显示 6 行)

 chr1_A
 1
 0
 1
 1
 1
 1

当执行为:awk -f fillrows.awk chr1_A

  1. ID 列始终相同

    { echo ID ; seq 1 15000 ;} > ID_col
    
  2. 粘贴在一起 - 这可能会受到 RAM 的限制:

    for PHENO in {A..M} ; do
      paste ID_col chr*_$PHENO > $PHENO
    done
    
  3. 一些并行化通过gnu并行

     #!/bin/bash
     ##get chrX-Y list without PHENO
     find -name 'chr*' | sed 's/_.$//' | sort -u > chrlist
     parallel awk -f rowfill ::: chr*{A..M}
     { echo ID ; seq 1 15000 ;} > ID_col
     parallel paste ID_col '{1}_{2}_red' '>' '{2}' :::: chrlist ::: {A..M}
    

答案3

我想出了一个递归函数来连接任意数量的文件:

join_all() {
    local -a join_opts
    local arg
    while :; do
        arg=$1
        shift
        [[ $arg == '--' ]] && break
        join_opts+=("$arg")
    done

    if (($# == 1)); then
        cat "$1"
    else
        join "${join_opts[@]}" "$1" "$2" | join_all "${join_opts[@]}" -- '-' "${@:3}"
    fi
}


for PHENO in A B C D E F G H I J K L M
do
    files=()
    # use brace expansion to generate the list of files
    files+=( chr{2,3,5,11,14,20,21,22,6,9,13}_${PHENO} )
    files+=( chr{18,8,17}-{1,2}_${PHENO} )
    files+=( chr{1,7,15,16}-{1,2,3}_${PHENO} )
    files+=( chr{19,4,10,12}-{1,2,3,4}_${PHENO} )

    join_all -a1 -a2 -e 1 -o auto -- "${files[@]}" > ${PHENO}
done

相关内容