在带有变量的 2 行上使用 melt 或 pivot_longer

Using melt or pivot_longer over 2 rows with variables

我的这个输出包含不同 'places' (bel..tej) 中基因家族(例如 family01、family21)的值,但它还包含一些与这些站点相关的元数据(类型环境)。我知道数据没有我希望的那么整齐,所以我想知道是否有一种优雅的方法可以使用 pivot_longer 以长格式整理它以便稍后制作热图。

这是数据集。

Sample  bel buc mal man pen poc tej
Environment C_3 C_1 C_3 C_3 C_2 C_1 C_3
family01    1.962   20.790  0.000   0.000   0.000   0.000   1.962
family03    0.000   3.150   0.000   0.000   152.614 0.089   0.000
family08    4.482   12.603  0.168   0.460   0.000   2.917   4.482
family13    0.000   1.697   0.000   0.000   169.841 0.000   0.000
family17    0.462   10.689  0.000   0.000   0.000   1.387   0.462
family21    0.000   0.410   0.000   0.000   122.959 0.000   0.000

我搜索了函数 pivot_longer 的帮助,有几个问题涉及多个 而不是 而不是关于 'simultaneously' 将函数应用于两组变量。首先我尝试了这个 long <- pivot_longer(data = output.txt, cols = -c(Family), names_to = "site", values_to = "rpkm") 但我得到了这个结果

# A tibble: 49 x 3
   Sample      site  rpkm  
   <chr>       <chr> <chr> 
 1 Environment bel   C_3    
 2 Environment buc   C_1    
 3 Environment mal   C_3    
 4 Environment man   C_3    
 5 Environment pen   C_2    
 6 Environment poc   C_1    
 7 Environment tej   C_3    
 8 family1     bel   1.962 
 9 family1     buc   20.790
10 family1     mal   0.000 

这是预期的格式

  Family  site  Env  rpkm
  family1   bel  3   1.962      
  family1   buc  1   20.790 
  family1   mal  3   0.000  

我想如果第一行不存在我可以做

output.txt %>%
  pivot_longer(
    -Environment,
    names_to = c(".value", "Env"),
    names_sep = "_")

为了获得将环境类型存储为变量的列 'Env',然后我需要 'another' 转换为长格式。

我想两个连续的 pivot_longer 轮可以解决这个问题或使用其他策略 melt (例如,在网站上和网站类型作为前 2 行)。这是一个很长的 table,所以我想避免对其进行排序或手动编辑。

这是dput的输出:

structure(list(Sample = c("Environment", "family01", "family03", 
"family08", "family13", "family17", "family21"), bel = c("C__3", 
"1.962", "0", "4.482", "0", "0.462", "0"), buc = c("C_1", "20.79", 
"3.15", "12.603", "1.697", "10.689", "0.41"), mal = c("C_3", 
"0", "0", "0.168", "0", "0", "0"), man = c("C_3", "0", "0", "0.46", 
"0", "0", "0"), pen = c("C_2", "0", "152.614", "0", "169.841", 
"0", "122.959"), poc = c("C_1", "0", "0.089", "2.917", "0", "1.387", 
"0"), tej = c("C_3", "1.962", "0", "4.482", "0", "0.462", "0"
)), row.names = c(NA, -7L), class = c("tbl_df", "tbl", "data.frame"
))

附录 如果有人想使用解决方案,我不得不使用解决方法保存(xlsx 或 csv)并再次加载 tibble 并指定值(rpkm)是数字.

这是一个选项,我们通过 pasteing (str_c) 删除 C_ 后的第一行元素来更改第一行以外的列名称,然后删除第一行(slice(-1)),转换 type.convert 列的 type,从 'wide' 重塑为 'long' (pivot_longer),separate 通过在小写字母和数字之间的边界处拆分,将 'name' 列一分为二((?<=[a-z])(?=\d) - 正则表达式环视)

library(dplyr)
library(tidyr)
library(stringr)
output.txt %>% 
    rename_at(-1, ~ str_c(., unlist(output.txt %>% 
                                       slice(1) %>% 
                                       select(-Sample) %>% 
                                       unlist %>% 
                                       str_remove('C_+')))) %>% 
    slice(-1) %>%
    type.convert(as.is = TRUE) %>%
    pivot_longer(cols = -Sample, values_to = 'rpkm') %>% 
    separate(name, into = c('site', 'Env'), sep='(?<=[a-z])(?=\d)')
# A tibble: 42 x 4
#   Sample   site  Env    rpkm
#   <chr>    <chr> <chr> <dbl>
# 1 family01 bel   3      1.96
# 2 family01 buc   1     20.8 
# 3 family01 mal   3      0   
# 4 family01 man   3      0   
# 5 family01 pen   2      0   
# 6 family01 poc   1      0   
# 7 family01 tej   3      1.96
# 8 family03 bel   3      0   
# 9 family03 buc   1      3.15
#10 family03 mal   3      0   
# … with 32 more rows

这是另一个与您的想法类似的解决方案。基本上,我将第一行重塑为更长的格式,并对其余行执行相同的操作;然后我在 site 列加入两者。

library(dplyr)
library(tidyr)
library(stringr)

output.txt %>% 
  slice(1) %>% 
  pivot_longer(-Sample, names_to = "site", values_to = "Env") %>% 
  mutate(Env = str_remove(Env, 'C_+'))  %>% 
  select(-Sample) %>% 
 right_join(., 
             {output.txt %>% 
                  slice(-1) %>% 
                  pivot_longer(-Sample, names_to = "site", values_to = "rpkm")},
            by = "site") %>% 
 select(Family = Sample, site, Env, rpkm)

#> # A tibble: 42 x 4
#>    Family   site  Env   rpkm 
#>    <chr>    <chr> <chr> <chr>
#>  1 family01 bel   3     1.962
#>  2 family01 buc   1     20.79
#>  3 family01 mal   3     0    
#>  4 family01 man   3     0    
#>  5 family01 pen   2     0    
#>  6 family01 poc   1     0    
#>  7 family01 tej   3     1.962
#>  8 family03 bel   3     0    
#>  9 family03 buc   1     3.15 
#> 10 family03 mal   3     0    
#> # ... with 32 more rows