tidyr::unite 跨列模式
tidyr::unite across column patterns
我有一个看起来像这样的数据集
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_1
和 D0x_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
好像不存在。
这是一个具有基本功能的解决方案。首先,我在列中查找 ***_1 的索引。我还使用 gsub()
和 unique()
为最终过程的列创建了名称。应用部分使用 /
粘贴两列。如果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
两个选项,其实是同一件事重新排列。
选项 1. 嵌套调用
首先,您可以使用 lapply
以编程方式跨列应用 unite_
(您可以向其传递字符串的标准评估版本)。为此,您需要构建一个名称列表供其使用,然后将 lapply
包装在 do.call(cbind
中以捕获列,然后将 cbind
site
包装回去给它。总计:
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
选项 2:连锁
或者,如果您真的喜欢管道,您实际上可以将整个东西破解成一条链(包括 lapply
!),将一些基本功能换成 dplyr
个:
df %>% select(-site) %>% names() %>% substr(1,3) %>% unique() %>%
lapply(function(x){unite_(df, x, grep(x, names(df), value = TRUE),
sep = '/', remove = TRUE) %>% select_(x)}) %>%
bind_cols() %>% mutate(site = as.character(df$site)) %>% select(site, starts_with('D'))
# Source: local data frame [5 x 4]
#
# site D01 D02 D03
# (chr) (chr) (chr) (chr)
# 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
查看中间产品以了解它们是如何组合在一起的,但它与基本方法的逻辑几乎相同。
您可以使用简单的基础 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
我有一个看起来像这样的数据集
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_1
和 D0x_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
好像不存在。
这是一个具有基本功能的解决方案。首先,我在列中查找 ***_1 的索引。我还使用 gsub()
和 unique()
为最终过程的列创建了名称。应用部分使用 /
粘贴两列。如果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
两个选项,其实是同一件事重新排列。
选项 1. 嵌套调用
首先,您可以使用 lapply
以编程方式跨列应用 unite_
(您可以向其传递字符串的标准评估版本)。为此,您需要构建一个名称列表供其使用,然后将 lapply
包装在 do.call(cbind
中以捕获列,然后将 cbind
site
包装回去给它。总计:
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
选项 2:连锁
或者,如果您真的喜欢管道,您实际上可以将整个东西破解成一条链(包括 lapply
!),将一些基本功能换成 dplyr
个:
df %>% select(-site) %>% names() %>% substr(1,3) %>% unique() %>%
lapply(function(x){unite_(df, x, grep(x, names(df), value = TRUE),
sep = '/', remove = TRUE) %>% select_(x)}) %>%
bind_cols() %>% mutate(site = as.character(df$site)) %>% select(site, starts_with('D'))
# Source: local data frame [5 x 4]
#
# site D01 D02 D03
# (chr) (chr) (chr) (chr)
# 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
查看中间产品以了解它们是如何组合在一起的,但它与基本方法的逻辑几乎相同。
您可以使用简单的基础 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