R - 数据框中两组之间的差异
R - difference between 2 sets in data frame
我有 2 个因子列,我想创建第三列,告诉我第二列有什么,而第一列没有。
它与这个 post 非常相似,但我在从 df
到使用 setdiff()
函数时遇到了麻烦。
例如:
library(dplyr)
y1 <- c("a.b.","a.","b.c.d.")
y2 <- c("a.b.c.","a.b.","b.c.d.")
df <- data.frame(y1,y2)
第 y1
列有 a.b.
,第 y2
列有 a.b.c.
。我想要 return c.
或只是 c
的三分之一列。
> df
y1 y2 col3
1 a.b. a.b.c. c.
2 a. a.b. b.
3 b.c.d. b.c.d.
我认为这应该是 strsplit
和 setdiff
的组合,但我无法让它工作。
我尝试将 factor
转换为 character
,然后我尝试将 strsplit()
应用于结果,但输出对我来说似乎很奇怪。它似乎在列表中创建了一个列表,这使得它很难传递给 setdiff()
#convert factor to character
df <- df %>% mutate_if(is.factor, as.character)
lapply(df$y1,function(x)(strsplit(x,split = "[.]")))
> lapply(df$y1,function(x)(strsplit(x,split = "[.]")))
[[1]]
[[1]][[1]]
[1] "a" "b"
[[2]]
[[2]][[1]]
[1] "a"
[[3]]
[[3]][[1]]
[1] "b" "c" "d"
更新
当差异超过 1 个字符时出现问题,它创建了一个额外的行。为了克服这一点,我们 paste
将所有元素放在一起以解决每个差异。这也使我们免于 unlist
这一步。
df$col3 <- mapply(function(x, y) paste0(setdiff(y, x), collapse = ""),
strsplit(as.character(df$y1), "\."), strsplit(as.character(df$y2), "\."))
原答案
我们可以使用 mapply
并在“.”上拆分两列。使用 strsplit
然后使用 setdiff
.
计算它们之间的差异
df$col3 <- mapply(function(x, y) setdiff(y, x),
strsplit(as.character(df$y1), "\."), strsplit(as.character(df$y2), "\."))
df
# y1 y2 col3
#1 a.b. a.b.c. c
#2 a. a.b. b
#3 b.c.d. b.c.d.
如果我们不想 col3
作为列表,我们可以 unlist
但是,其中一个问题是如果我们 unlist
它从中删除 character(0)
值它。为了保留该值,我们需要对其执行额外的检查。摘自 .
unlist(lapply(df$col3,function(x) if(identical(x,character(0))) ' ' else x))
#[1] "c" "b" " "
你也可以使用purrr:map2
:
df %>%
mutate_if(is.factor, as.character) %>%
mutate(col3 = map2(strsplit(y2, "\."), strsplit(y1, "\."), setdiff))
# y1 y2 col3
#1 a.b. a.b.c. c
#2 a. a.b. b
#3 b.c.d. b.c.d.
说明:将factor
s 转换为character
向量,在"."
-拆分列y2
和y1
上使用setdiff
。请注意 col3
是 list
.
更新
unnest
似乎删除了 list
中的零长度 character
条目。因此,要将 col3
从 list
转换为 character
向量,您可以执行以下操作:
df %>%
mutate_if(is.factor, as.character) %>%
mutate(col3 = map2(strsplit(y2, "\."), strsplit(y1, "\."), setdiff)) %>%
rowwise() %>%
mutate(col3 = paste(col3, collapse = "."))
## A tibble: 3 x 3
# y1 y2 col3
# <chr> <chr> <chr>
#1 a.b. a.b.c. c
#2 a. a.b. b
#3 b.c.d. b.c.d. ""
这里的想法是字符串连接 col3
个条目(如果有多个);使用 rowwise()
确保按行 paste
.
根据您的评论更新示例数据:
y1 <- c("a.b.","a.","b.c.d.")
y2 <- c("a.b.c.e.","a.b.","b.c.d.")
df <- data.frame(y1,y2)
df %>%
mutate_if(is.factor, as.character) %>%
mutate(col3 = map2(strsplit(y2, "\."), strsplit(y1, "\."), setdiff)) %>%
rowwise() %>%
mutate(col3 = paste(col3, collapse = "."))
## A tibble: 3 x 3
# y1 y2 col3
# <chr> <chr> <chr>
#1 a.b. a.b.c.e. c.e
#2 a. a.b. b
#3 b.c.d. b.c.d. ""
一个很简单但不严谨的方法就是将y1中的所有内容都替换为y2中的“”。
这不会处理订单不同的情况,或者如果 y1 有任何附加到 y2 而不是相反的情况。
df %>% rowwise() %>% mutate(col3 = gsub(y1,"",y2))
我有 2 个因子列,我想创建第三列,告诉我第二列有什么,而第一列没有。
它与这个 post 非常相似,但我在从 df
到使用 setdiff()
函数时遇到了麻烦。
例如:
library(dplyr)
y1 <- c("a.b.","a.","b.c.d.")
y2 <- c("a.b.c.","a.b.","b.c.d.")
df <- data.frame(y1,y2)
第 y1
列有 a.b.
,第 y2
列有 a.b.c.
。我想要 return c.
或只是 c
的三分之一列。
> df
y1 y2 col3
1 a.b. a.b.c. c.
2 a. a.b. b.
3 b.c.d. b.c.d.
我认为这应该是 strsplit
和 setdiff
的组合,但我无法让它工作。
我尝试将 factor
转换为 character
,然后我尝试将 strsplit()
应用于结果,但输出对我来说似乎很奇怪。它似乎在列表中创建了一个列表,这使得它很难传递给 setdiff()
#convert factor to character
df <- df %>% mutate_if(is.factor, as.character)
lapply(df$y1,function(x)(strsplit(x,split = "[.]")))
> lapply(df$y1,function(x)(strsplit(x,split = "[.]")))
[[1]]
[[1]][[1]]
[1] "a" "b"
[[2]]
[[2]][[1]]
[1] "a"
[[3]]
[[3]][[1]]
[1] "b" "c" "d"
更新
当差异超过 1 个字符时出现问题,它创建了一个额外的行。为了克服这一点,我们 paste
将所有元素放在一起以解决每个差异。这也使我们免于 unlist
这一步。
df$col3 <- mapply(function(x, y) paste0(setdiff(y, x), collapse = ""),
strsplit(as.character(df$y1), "\."), strsplit(as.character(df$y2), "\."))
原答案
我们可以使用 mapply
并在“.”上拆分两列。使用 strsplit
然后使用 setdiff
.
df$col3 <- mapply(function(x, y) setdiff(y, x),
strsplit(as.character(df$y1), "\."), strsplit(as.character(df$y2), "\."))
df
# y1 y2 col3
#1 a.b. a.b.c. c
#2 a. a.b. b
#3 b.c.d. b.c.d.
如果我们不想 col3
作为列表,我们可以 unlist
但是,其中一个问题是如果我们 unlist
它从中删除 character(0)
值它。为了保留该值,我们需要对其执行额外的检查。摘自
unlist(lapply(df$col3,function(x) if(identical(x,character(0))) ' ' else x))
#[1] "c" "b" " "
你也可以使用purrr:map2
:
df %>%
mutate_if(is.factor, as.character) %>%
mutate(col3 = map2(strsplit(y2, "\."), strsplit(y1, "\."), setdiff))
# y1 y2 col3
#1 a.b. a.b.c. c
#2 a. a.b. b
#3 b.c.d. b.c.d.
说明:将factor
s 转换为character
向量,在"."
-拆分列y2
和y1
上使用setdiff
。请注意 col3
是 list
.
更新
unnest
似乎删除了 list
中的零长度 character
条目。因此,要将 col3
从 list
转换为 character
向量,您可以执行以下操作:
df %>%
mutate_if(is.factor, as.character) %>%
mutate(col3 = map2(strsplit(y2, "\."), strsplit(y1, "\."), setdiff)) %>%
rowwise() %>%
mutate(col3 = paste(col3, collapse = "."))
## A tibble: 3 x 3
# y1 y2 col3
# <chr> <chr> <chr>
#1 a.b. a.b.c. c
#2 a. a.b. b
#3 b.c.d. b.c.d. ""
这里的想法是字符串连接 col3
个条目(如果有多个);使用 rowwise()
确保按行 paste
.
根据您的评论更新示例数据:
y1 <- c("a.b.","a.","b.c.d.")
y2 <- c("a.b.c.e.","a.b.","b.c.d.")
df <- data.frame(y1,y2)
df %>%
mutate_if(is.factor, as.character) %>%
mutate(col3 = map2(strsplit(y2, "\."), strsplit(y1, "\."), setdiff)) %>%
rowwise() %>%
mutate(col3 = paste(col3, collapse = "."))
## A tibble: 3 x 3
# y1 y2 col3
# <chr> <chr> <chr>
#1 a.b. a.b.c.e. c.e
#2 a. a.b. b
#3 b.c.d. b.c.d. ""
一个很简单但不严谨的方法就是将y1中的所有内容都替换为y2中的“”。 这不会处理订单不同的情况,或者如果 y1 有任何附加到 y2 而不是相反的情况。
df %>% rowwise() %>% mutate(col3 = gsub(y1,"",y2))