tidyr ::跨列模式联合

时间:2016-03-15 03:33:57

标签: r dplyr tidyr

我有一个看起来像这样的数据集

site <- c("A", "B", "C", "D", "E")
D01_1 <- c(1, 0, 0, 0, 1)
D01_2 <- c(1, 1, 0, 1, 1)
D02_1 <- c(1, 0, 1, 0, 1)
D02_2 <- c(0, 1, 0, 0, 1)
D03_1 <- c(1, 1, 0, 0, 0)
D03_2 <- c(0, 1, 0, 0, 1)
df <- data.frame(site, D01_1, D01_2, D02_1, D02_2, D03_1, D03_2)

我正在尝试联合D0x_1D0x_2列,以便列中的值以斜杠分隔。我可以使用以下代码执行此操作,它可以正常工作:

library(dplyr)
library(tidyr)

df.unite <- df %>%
  unite(D01, D01_1, D01_2, sep = "/", remove = TRUE) %>%
  unite(D02, D02_1, D02_2, sep = "/", remove = TRUE) %>%
  unite(D03, D03_1, D03_2, sep = "/", remove = TRUE)

...但问题是它要求我多次输入每个unite对,并且在我的数据集中的大量列中它很难处理。在dplyr中是否有一种方法可以在相似的图案列名中联合,然后在列中循环? unite_each似乎不存在。

3 个答案:

答案 0 :(得分:4)

两个选项,实际上是重新排列的相同内容。

选项1.嵌套调用

首先,您可以使用lapply以编程方式跨列应用unite_(可以传递字符串的标准评估版)。为此,您需要构建一个名称列表供其使用,然后将lapply包裹在do.call(cbind中以捕获列,cbind {{1}回到它。总而言之:

site

选项2:链式

或者,如果你真的喜欢管道,你实际上可以把整个东西整理成一个链(cols <- unique(substr(names(df)[-1], 1, 3)) cbind(site = df$site, do.call(cbind, lapply(cols, function(x){unite_(df, x, grep(x, names(df), value = TRUE), sep = '/', remove = TRUE) %>% select_(x)}) )) # site D01 D02 D03 # 1 A 1/1 1/0 1/0 # 2 B 0/1 0/1 1/1 # 3 C 0/0 1/0 0/0 # 4 D 0/1 0/0 0/0 # 5 E 1/1 1/1 0/1 包含!),换掉lapply个的一些基本函数:

dplyr

查看中间产品以了解它是如何组合在一起的,但它与基本方法的逻辑基本相同。

答案 1 :(得分:3)

这是一个具有基本功能的解决方案。首先,我在列中查找*** _ 1的索引。我还使用gsub()unique()为最终流程的列创建了名称。 sapply部分使用/粘贴两列。如果x = 1,则x + 1 = 2.因此,您始终选择彼此相邻的两列并处理粘贴作业。然后,我添加了site cbind()并创建了一个数据框。最后一项工作是分配列名。

library(magrittr)

ind <- grep(pattern = "1$", x = names(df))

names <- unique(gsub(pattern = "_\\d+$",
                replacement = "", x = names(df)))

sapply(ind, function(x){
        foo <- paste(df[,x], df[, x+1], sep = "/")
        foo
       }) %>%
cbind(as.character(df$site), .) %>%
data.frame -> out

names(out) <- names

#  site D01 D02 D03
#1    A 1/1 1/0 1/0
#2    B 0/1 0/1 1/1
#3    C 0/0 1/0 0/0
#4    D 0/1 0/0 0/0
#5    E 1/1 1/1 0/1

答案 2 :(得分:0)

您也可以使用简单的基础R方法:

cols <- split(names(df)[-1], sub("_\\d+", "", names(df)[-1]))

cbind(df[1], sapply(names(cols), function(col) {
  do.call(paste, c(df[cols[[col]]], sep = "/"))
}))
#  site D01 D02 D03
#1    A 1/1 1/0 1/0
#2    B 0/1 0/1 1/1
#3    C 0/0 1/0 0/0
#4    D 0/1 0/0 0/0
#5    E 1/1 1/1 0/1