我有一个data.frame
,看起来像这样:
df <- data.frame(A = NA, B = NA, C = c("a,b,c", "c,b", "d,a"), stringsAsFactors = FALSE)
df
A B C
1 NA NA a,b,c
2 NA NA c,b
3 NA NA d,a
A
和B
列(以及我的真实数据中的其他列)被设置为NA
,以表示对于问题而言,它们的条目不是必需的。
目标应该是:
df_goal <- data.frame(A = NA, B = NA, a = c(TRUE, FALSE, TRUE), b = c(TRUE,
TRUE, FALSE), c = c(TRUE, TRUE, FALSE), d = c(FALSE, FALSE, TRUE))
df_goal
A B a b c d
1 NA NA TRUE TRUE TRUE FALSE
2 NA NA FALSE TRUE TRUE FALSE
3 NA NA TRUE FALSE FALSE TRUE
我做到了这一点:
df <- cbind(df[, 1:2], as.data.frame(t(apply(read.table(text = df$C, sep = ",", as.is = TRUE, fill = TRUE, na.strings = "")
, 1,
FUN = function(x) sort(x, decreasing= FALSE, na.last = TRUE))), stringsAsFactors = FALSE))
df <- cbind(df[, 1:2], as.data.frame(sapply(c("a", "b", "c", "d"), function(y) {sapply(1:nrow(df), function(x) {ifelse(y %in% df[x, ], TRUE, FALSE)})})))
df
A B a b c d
1 NA NA TRUE TRUE TRUE FALSE
2 NA NA FALSE TRUE TRUE FALSE
3 NA NA TRUE FALSE FALSE TRUE
identical(df, df_goal)
# [1] TRUE
是否有更简洁的选择可以实现我想要的?
编辑:
我还考虑了一个tidyr
选项,但未能实现:
library(tidyr)
df %>% separate(C, c("a", "b", "c", "d"))
A B a b c d
1 NA NA a b c <NA>
2 NA NA c b <NA> <NA>
3 NA NA d a <NA> <NA>
这仍然是未排序的,因此spread
并没有真正起作用。
我想念什么?
答案 0 :(得分:2)
library(tidyverse)
df %>%
mutate(C = map(C, ~strsplit(., ',')[[1]] %>% sort),
I = row_number()) %>%
unnest(C) %>%
spread(C, C) %>%
mutate_at(-(1:3), ~!is.na(.)) %>%
select(-I)
# A B a b c d
# 1 NA NA TRUE TRUE TRUE FALSE
# 2 NA NA FALSE TRUE TRUE FALSE
# 3 NA NA TRUE FALSE FALSE TRUE
或者使用data.table(+ purrr)
library(data.table)
library(purrr)
setDT(df)
# Split strings and sort them
df[, C := map(C, ~ strsplit(., ',')[[1]] %>% sort)][]
# add row number column
df[, I := .I]
# unlist C and dcast (spread) to wide
df[, .(C = unlist(C)), setdiff(names(df), 'C')] %>%
dcast(A + B + I ~ C) %>%
# convert to logical
.[, lapply(.SD, Negate(is.na)), .(A, B)] %>%
# remove row number column
.[, -'I']
# A B a b c d
# 1: NA NA TRUE TRUE TRUE FALSE
# 2: NA NA FALSE TRUE TRUE FALSE
# 3: NA NA TRUE FALSE FALSE TRUE