【问题标题】:Spread and sort concatenated factor variable in data.frame [duplicate]在data.frame中传播和排序连接的因子变量[重复]
【发布时间】:2019-03-06 13:53:55
【问题描述】:

我有一个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

AB 列(以及我的真实数据中的更多)设置为 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

是否有更简洁的选项来实现我想要的?


在@Sonny 发表评论后编辑

我也想过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 并没有真正起作用..

我错过了什么?

【问题讨论】:

  • 可以使用tidyr::separate将C拆分成多个字段,然后使用spread
  • @Sonny 感谢您的提示。我还认为tidyr 应该提供一个简单的解决方案,但无法到达那里,请参阅我的编辑。我错过了什么?

标签: r dataframe tidyr


【解决方案1】:
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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多