使用tidyr unite将列名与列值组合

6

我有一个包含多列的data.frame

set.seed(1)
df <- data.frame(cluster=LETTERS[1:4],group=c(rep("m",2),rep("f",2)),point=rnorm(4),err=runif(4,0.1,0.3))

我会添加另一列,该列使用"\n"将其相应行的所有列连接起来,其中列名称在值之前。

我知道这点:

library(tidyr)
library(dplyr)
tidyr::unite(df,text,sep="\n")

这给了我这个tibble

                                         text
1  A\nm\n0.487429052428485\n0.286941046221182
2  B\nm\n0.738324705129217\n0.142428504256532
3  C\nf\n0.575781351653492\n0.230334753217176
4 D\nf\n-0.305388387156356\n0.125111019192263

但我想要的是这个tibble

                                         text
1  cluster: A\ngroup: m\npoint: 0.487429052428485\nerr: 0.286941046221182
2  cluster: B\ngroup: m\npoint: 0.738324705129217\nerr: 0.142428504256532
3  cluster: C\ngroup: f\npoint: 0.575781351653492\nerr: 0.230334753217176
4 cluster: D\ngroup: f\npoint: -0.305388387156356\nerr: 0.125111019192263

有什么想法吗?
2个回答

6
我们可以使用do.callMap进行操作。
data.frame(text = do.call(paste, c(Map(function(x, y) 
                 paste(x, y, sep=": "), names(df), df), sep="\n")))

或者使用 tidyverse,通过列进行映射(imap - 提供.y作为列名),然后执行unite操作。

library(tidyverse)
imap(df, ~ paste(.y, .x, sep=": ")) %>%
              as_tibble %>%
              unite(text, sep="\n")
# A tibble: 4 x 1
#  text                                                                     
#  <chr>                                                                    
#1 "cluster: A\ngroup: m\npoint: -0.626453810742332\nerr: 0.225822808779776"
#2 "cluster: B\ngroup: m\npoint: 0.183643324222082\nerr: 0.112357254093513" 
#3 "cluster: C\ngroup: f\npoint: -0.835628612410047\nerr: 0.14119491497986" 
#4 "cluster: D\ngroup: f\npoint: 1.59528080213779\nerr: 0.135311350505799"  

或者像@DanChaltiel提到的那样。
imap_dfr(df, ~ paste(.y, .x, sep = "; ")) %>%
      unite(text, sep = "\n")

1
我们还可以通过使用aggregate(do.call(paste,c(sep=" :",rev(stack(df)))),list(c(row(df))),paste,collapse="\n")来避免循环。 - Onyambu
@Onyambu 是的,但是如果你检查这些函数,它会执行“aggregation”、“stack”等操作,这会增加额外的开销。 - akrun
1
你甚至可以通过使用 imap_dfr() 并删除 as_tibble 来节省一次调用。 - Dan Chaltiel

0
感谢@jared_mamrot的解决方案这里,另一个选项是首先使用across将列转换为“列名+列值”,然后再使用unite,如下所示:
df %>% mutate(across(names(df), ~paste0(cur_column(), ": ", .x))) %>% unite(text, sep = "\n")

                                                                     text
1 cluster: A\ngroup: m\npoint: -0.626453810742332\nerr: 0.225822808779776
2  cluster: B\ngroup: m\npoint: 0.183643324222082\nerr: 0.112357254093513
3  cluster: C\ngroup: f\npoint: -0.835628612410047\nerr: 0.14119491497986
4   cluster: D\ngroup: f\npoint: 1.59528080213779\nerr: 0.135311350505799

此选项还允许轻松选择感兴趣的列。请参考@jared_mamrot的solution


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接