【问题标题】:Calculating mean from values in columns specified on the first line using awk使用 awk 从第一行指定的列中的值计算平均值
【发布时间】:2018-01-26 12:11:37
【问题描述】:

我有一个像这样结构的巨大文件(数百行,大约 4,000 列)

locus   1   1   1   2   2   3   3   3
exon    1   2   3   1   2   1   2   3
data1   17.07   7.11    10.58   10.21   19.34   14.69   3.32    21.07
data2   21.42   11.46   7.88    9.89    27.24   12.40   0.58    19.82

并且我需要从具有相同基因座编号(即第一行中的相同编号)的所有值(分别在每个数据行上)计算平均值,即

data1:前三个值的平均值(三列的轨迹为“1”: 17.07, 7.11, 10.58),接下来的两个值 (10.21, 19.34) 和接下来的三个值 (14.69, 3.32, 21.07)

我想要这样的输出

data1   mean1   mean2   mean3
data1   mean1   mean2   mean3

我正在考虑使用 bash 和 awk... 谢谢你的建议。

【问题讨论】:

  • bash 用于操作文件和进程,而不是用于文本处理 - 您只需要 awk 即可。 edit 您的问题是在给定输入的情况下显示您想要的确切输出,以及您希望如何调用可以做到这一点的工具。还包括您迄今为止尝试过的内容,即使它只是伪代码。

标签: bash awk


【解决方案1】:

如果是我,我会使用R,而不是awk

library(data.table)
x = fread('data.txt')

#> x
#      V1    V2    V3    V4    V5    V6    V7   V8    V9
#1: locus  1.00  1.00  1.00  2.00  2.00  3.00 3.00  3.00
#2:  exon  1.00  2.00  3.00  1.00  2.00  1.00 2.00  3.00
#3: data1 17.07  7.11 10.58 10.21 19.34 14.69 3.32 21.07
#4: data2 21.42 11.46  7.88  9.89 27.24 12.40 0.58 19.82

# save first column of names for later
cnames = x$V1

# remove first column
x[,V1:=NULL]

# matrix transpose: makes rows into columns
x = t(x)

# convert back from matrix to data.table
x = data.table(x,keep.rownames=F)

# set the column names
colnames(x) = cnames

#> x
#   locus exon data1 data2
#1:     1    1 17.07 21.42
#...

# ditch useless column
x[,exon:=NULL]

#> x
#   locus data1 data2
#1:     1 17.07 21.42

# apply mean() function to each column, grouped by locus
x[,lapply(.SD,mean),locus]

#   locus    data1    data2
#1:     1 11.58667 13.58667
#2:     2 14.77500 18.56500
#3:     3 13.02667 10.93333

为方便起见,这里还是没有 cmets 的全部内容:

library(data.table)
x = fread('data.txt')
cnames = x$V1
x[,V1:=NULL]
x = t(x)
x = data.table(x,keep.rownames=F)
colnames(x) = cnames
x[,exon:=NULL]
x[,lapply(.SD,mean),locus]

【讨论】:

    【解决方案2】:
    awk '   NR==1{for(i=2;i<NF+1;i++) multi[i]=$i} 
            NR>2{
                for(i in multi)
                {   
                    data[multi[i]] = 0 
                    count[multi[i]] = 0 
                }   
                for(i=2;i<NF+1;i++) 
                {    
                    data[multi[i]] += $i    
                    count[multi[i]] += 1
                }; 
    
                printf "%s ",$1; 
                for(i in data) 
                    printf "%s ", data[i]/count[i]; 
                print ""  
            }' <file_name>
    

    用您的数据文件替换&lt;file_name&gt;

    【讨论】:

    • 感谢漂亮的代码,但是,它只适用于第一行数据,第二行的值不正确。正确的值是 data1 11.587 14.775 13.027 data2 13.587 18.565 10.933 但是上面的代码是 data1 11.5867 14.775 13.0267 data2 12.5867 16.67 11.98
    • 是的,我刚刚注意到.. 似乎 datacount 没有每行设置为零。相应地编辑了代码
    【解决方案3】:

    您可以使用GNU datamash 1.1.0 或更高版本(我使用的是最新版本 - 1.1.1):

    #!/bin/bash
    
    lines=$(wc -l < "$1")
    
    datamash -W transpose < "$1" |
    datamash -H groupby 1 mean 3-"$lines" |
    datamash transpose 
    

    用法: mean_value.sh input.txt | column -tcolumn -t 需要漂亮的视图,没有必要)

    输出:

    GroupBy(locus)  1                2       3
    mean(data1)     11.586666666667  14.775  13.026666666667
    mean(data2)     13.586666666667  18.565  10.933333333333
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-13
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-03
      • 2022-01-08
      相关资源
      最近更新 更多