R 将结果组织在一个表格中,就像关联矩阵一样

R 将结果组织在一个表格中,就像关联矩阵一样,r,unix,awk,R,Unix,Awk,例如,我需要在矩阵中组织我的相关结果。我有这样一个文件: trait1 trait2 GeCor PCor a b -1.00 0.28 b c 0.40 0.45 d e -0.39 0.35 a c -0.39 0.50 b d 0.36 0.30 a d -0.35 0.30 b e -0

例如,我需要在矩阵中组织我的相关结果。我有这样一个文件:

trait1  trait2  GeCor   PCor
     a       b  -1.00   0.28
     b       c   0.40   0.45
     d       e  -0.39   0.35
     a       c  -0.39   0.50
     b       d   0.36   0.30
     a       d  -0.35   0.30
     b       e  -0.29   0.36
     a       e   0.26   0.33
     c       e   0.18   0.38
     c       d   0.04   0.31
我需要文件保持这样:

        a      b       c       d       e
a      -    0.28    0.50    0.30    0.33
b   -1.00     -     0.45    0.30    0.36
c   -0.39   0.40     -      0.31    0.38
d   -0.35   0.36    0.04      -     0.35
e    0.26  -0.29    0.18   -0.39     -

对角线上的符号(
-
)仅表示此空格应留空。<代码> GECOR 在<代码> TRAIT1和<代码> TRAIT2之间的遗传相关,这些应在空白对角线之下,而 PCOR 是<>代码> TRAIT1和 TRAIT2之间的表型相关性,并且应该在空白对角线之上。好吧,我要说的是,这个数据库只是一个样本,我有更多的特点。我接受unix或R的编程建议。非常感谢。

不幸的是,没有一个GNU核心实用程序能够轻松解决这个问题。数据结构的操作不是简单的重新安排。让我提供一个通用的解决方案,然后给您一个使用python的解决方案;哪种语言最容易实现(最少需要几行代码)

本质上,如果将trait1和trait2列作为矩阵索引,则需要创建一个大小为NxN的矩阵。N是唯一“特征”的数量-(即a、b、c、d-N=4)。然后使用原始数据结构,单元格[a,b]=Pcor,而[b,a]=GeCor。您从未指定任何其他订单,因此我假设没有。因此,我们需要假设一行到另一行的顺序之间没有结构或相关性。这意味着我们需要使用哈希索引来存储具有正确键的正确值,即ab=0.28和ba=-1.00。一旦我们构建了整个字典结构,我们只需展开它(按字母顺序)并输出最终的数据结构

一个简单的功能分解(非面向对象)会将其分解为三个不同的块。读入原始表格,填充对角线单元格,输出新的数据结构

以下是此功能的python2实现:

#!/usr/bin/python2

import fileinput

finalStruct = {}
diagCh = '-'
delimiter = '\t'


# Build initial structure
for line in fileinput.input():
    line = line.rstrip()
    columns = line.split(delimiter)

    # Create first layer of dictionary inside dictionary
    if columns[0] not in finalStruct:
        finalStruct[columns[0]] = {}

    finalStruct[columns[0]][columns[1]] = columns[3]

    if columns[1] not in finalStruct:
        finalStruct[columns[1]] = {}

    finalStruct[columns[1]][columns[0]] = columns[2]

# Add '-' for diagonals
for currKey in finalStruct.keys():
    finalStruct[currKey][currKey] = diagCh


# Output final structure
for rowIndex in sorted(finalStruct.keys()):
    for colIndex in sorted(finalStruct[rowIndex].keys()):
        print finalStruct[rowIndex][colIndex], delimiter,

    print
如果此代码文件为solution.py,而我们的输入文件为:

a   b   -1.00   0.28
b   c   0.40    0.45
d   e   -0.39   0.35
a   c   -0.39   0.50
b   d   0.36    0.30
a   d   -0.35   0.30
b   e   -0.29   0.36
a   e   0.26    0.33
c   e   0.18    0.38
c   d   0.04    0.31
我们的输入文件是input.txt。我们可以按如下方式运行此示例:

cat input.txt | ./solution.py

-   0.28    0.50    0.30    0.33    
-1.00   -   0.45    0.30    0.36    
-0.39   0.40    -   0.31    0.38    
-0.35   0.36    0.04    -   0.35    
0.26    -0.29   0.18    -0.39   -   

我想是时候用R发布我的解决方案了

首先,使用
read.table
,将原始数据读入数据框,例如
x
。然后

n <- ceiling(sqrt(2 * nrow(x)))
NAME <- with(x, sort(union(unique(trait1), unique(trait2))))

z <- matrix(NA_real_, n, n, dimnames = list(NAME, NAME))
z[lower.tri(z)] <- with(x, GeCor[order(trait1, trait2)])
z[upper.tri(z)] <- with(x, PCor[order(trait2, trait1)])

#      a     b    c     d    e
#a    NA  0.28 0.50  0.30 0.33
#b -1.00    NA 0.45  0.30 0.36
#c -0.39  0.40   NA  0.31 0.38
#d -0.35  0.36 0.04    NA 0.35
#e  0.26 -0.29 0.18 -0.39   NA

## write to file "z.txt"
write.table(z, file = "z.txt", na = "-", sep = "\t", quote = FALSE)

a   b       c       d       e
a   -       0.28    0.5     0.3     0.33
b   -1      -       0.45    0.3     0.36
c   -0.39   0.4     -       0.31    0.38
d   -0.35   0.36    0.04    -       0.35
e   0.26    -0.29   0.18    -0.39   -  

nR中的另一种方法,使用包
data.table
读取数据和
dplyr

library(data.table)
df <- fread("trait1  trait2  GeCor   PCor
a       b  -1.00   0.28
b       c   0.40   0.45
d       e  -0.39   0.35
a       c  -0.39   0.50
b       d   0.36   0.30
a       d  -0.35   0.30
b       e  -0.29   0.36
a       e   0.26   0.33
c       e   0.18   0.38
c       d   0.04   0.31")
#or df <- fread("myfile.txt")

library(dplyr)
data.frame(trait1=unique(c(df$trait1,df$trait2)), trait2=unique(c(df$trait1,df$trait2)),cor=NA, stringsAsFactors = FALSE) %>% 
  bind_rows(df %>% mutate(trait1=trait1, trait2=trait2, cor=GeCor, GeCor=NULL, PCor=NULL )) %>% 
  bind_rows(df %>% mutate(temp=trait2, trait2=trait1, trait1=temp, temp=NULL, cor=PCor, GeCor=NULL, PCor=NULL )) %>% 
  arrange(trait1, trait2) -> df_long

print.table(matrix(df_long$cor, nrow=5, dimnames=list(unique(df_long$trait1),unique(df_long$trait1))), na.print='-')

      a     b     c     d     e
a     -  0.28  0.50  0.30  0.33
b -1.00     -  0.45  0.30  0.36
c -0.39  0.40     -  0.31  0.38
d -0.35  0.36  0.04     -  0.35
e  0.26 -0.29  0.18 -0.39     -
库(data.table)
df%突变(trait1=trait1,trait2=trait2,cor=GeCor,GeCor=NULL,PCor=NULL))%>%
绑定行(df%>%突变(temp=trait2,trait2=trait1,trait1=temp,temp=NULL,cor=PCor,GeCor=NULL,PCor=NULL))%>%
排列(trait1,trait2)->df_long
print.table(矩阵(df_long$cor,nrow=5,dimnames=list(unique(df_long$trait1),unique(df_long$trait1)),na.print='-'))
a、b、c、d、e
a-0.28 0.50 0.30 0.33
b-1.00-0.45 0.30 0.36
c-0.39 0.40-0.31 0.38
d-0.35 0.36 0.04-0.35
e 0.26-0.29 0.18-0.39-
使用
perl

$ perl -ae '
if($. > 1)
{
    $h{"$F[0]$F[1]"} = $F[3]; $h{"$F[1]$F[0]"} = $F[2];
    push(@hh,$F[0]) if !$done{$F[0]}++;
    push(@hh,$F[1]) if !$done{$F[1]}++;
}
END
{
    print "\t".join("\t",sort @hh);
    foreach (sort keys %h)
    {
        ($k1,$k2) = /./g;
        print "\n$k1" if !$seen{$k1}++;
        print "\t-" if $k2 eq ++$k1;
        print "\t$h{$_}";
    }
    print "\t-\n";
}' ip.txt
    a   b   c   d   e
a   -   0.28    0.50    0.30    0.33
b   -1.00   -   0.45    0.30    0.36
c   -0.39   0.40    -   0.31    0.38
d   -0.35   0.36    0.04    -   0.35
e   0.26    -0.29   0.18    -0.39   -
  • 输入行根据空间分割并保存到
    @F
    数组中
  • 如果输入行大于1,则将第3列和第4列保存在哈希中,并将第1列和第2列的两个组合作为键
  • 还可以在数组中保存所有唯一的第1列或第2列值
  • 最后,以所需格式打印

带有GNU awk,用于分类输入:

$ cat tst.awk
NR>1 {
    cell[$2,$1] = $3
    cell[$1,$2] = $4
    keys[$1]
    keys[$2]
}
END {
    PROCINFO["sorted_in"] = "@ind_str_asc"

    printf "%5s", ""
    for (col in keys) {
        printf "  %-5s", col
    }
    print ""

    for (row in keys) {
        printf "%s", row
        for (col in keys) {
            printf "  %5s", ((row,col) in cell ? cell[row,col] : "- ")
        }
        print ""
    }
}

$ awk -f tst.awk file
       a      b      c      d      e
a     -    0.28   0.50   0.30   0.33
b  -1.00     -    0.45   0.30   0.36
c  -0.39   0.40     -    0.31   0.38
d  -0.35   0.36   0.04     -    0.35
e   0.26  -0.29   0.18  -0.39     -

与您似乎相信的相反,StackOverflow不是免费的编码服务。您需要显示您的代码,以及相关的示例输入、预期的输出、实际的错误MSG以及您对所处位置的注释。请尽最大努力解决这个问题,人们可能会帮助你。祝你好运。事实上,这只是问题的一小部分,我通过linux编程一个接一个地提取了其他几个文件的结果,由于我对linux的模糊知识,我没有通过这一部分。我尝试了一种超现实的环境。好的,所以我没有解释,但不知为什么我做了很大的努力,但我只是简化了我的问题。是的,你是对的,我不认为在这种情况下,我似乎在努力轻松地赚取这笔钱。谢谢你,下次我会改进我的问题。谢谢你的关注,很抱歉我会重新表述我的问题。我认为你的脚本是在计算行和列索引的名称,而不是从输入文件中读取它们,对吗?为什么不直接使用输入中的任何行/列名?@EdMorton如果特征(1和2)不是从“a”开始的连续字母,那么这确实可能是个问题。它也可以通过使用
order(x$trait1)
order(x$trait2)
代替
字母[1:n]
以低成本完成。是的,文件上有名字。我试过了,效果很好。感谢您提供了一种新的方法。wrt
没有一个GNU核心实用程序能够轻松地解决这个问题
-不知道为什么这是一个考虑因素,但使用标准UNIX工具awk来解决这个问题绝对是微不足道的,请参阅,而且显然可以用比python FWIW更少的代码行来完成。@EdMorton-我同意awk;不必迂腐,但awk不是一个核心实用程序。我曾考虑过使用awk,但我认为python将更具可读性——可移植到其他系统。最后,我的python代码比您的awk代码短两行(不包括空格、shebang或注释)。然而,我同意awk/perl肯定可以以牺牲可读性的方式用更少的代码行来解决这个问题。我不是说awk是GNU核心实用程序(因为我不知道它是不是),只是没有理由关注工具的子集。我无法想象为什么您会认为python比awk更具可移植性或可读性。您的脚本更简短,因为它不会生成发布的预期输出。显然,我可以通过删除不必要的花括号使awk代码更简洁,也可以通过删除打印行标签和l