我有一个df
,其中一列feature_service
包含一对或多对具有服务( A或B 的要素( a-d ))。功能和服务使用:
分隔,成对的使用,
分隔。
df
如下:
df <- data.frame(feature_service = c("a:A", "a:A, b:A", "a:A, a:B", "a:B, b:B, c:B", "d:A, d:B"), stringsAsFactors = FALSE)
df
feature_service
1 a:A
2 a:A, b:A
3 a:A, a:B
4 a:B, b:B, c:B
5 d:A, d:B
现在,我想将服务和功能分成单独的逻辑列。 目标是使data.frame
看起来像:
df_goal <- data.frame(feature_a = c(TRUE, TRUE, TRUE, TRUE, FALSE), feature_b = c(FALSE, TRUE, FALSE, TRUE, FALSE), feature_c = c(FALSE, FALSE, FALSE, TRUE, FALSE)
, feature_d = c(FALSE, FALSE, FALSE, FALSE, TRUE), service_A = c(TRUE, TRUE, TRUE, FALSE, TRUE), service_B = c(FALSE, FALSE, TRUE, TRUE, TRUE))
df_goal
feature_a feature_b feature_c feature_d service_A service_B
1 TRUE FALSE FALSE FALSE TRUE FALSE
2 TRUE TRUE FALSE FALSE TRUE FALSE
3 TRUE FALSE FALSE FALSE TRUE TRUE
4 TRUE TRUE TRUE FALSE FALSE TRUE
5 FALSE FALSE FALSE TRUE TRUE TRUE
我该如何实现?
答案 0 :(得分:3)
Base R解决方案:
foo <- strsplit(df$feature_service, ",")
# Get all possible features
feature <- unique(unlist(lapply(foo, function(x) trimws(sub(":.*", ":", x)))))
# Get all possible services
service <- unique(unlist(lapply(foo, function(x) trimws(sub(".*:", ":", x)))))
# Generate occurrence table
result <- sapply(c(feature, service), grepl, df$feature_service)
# Name final result
colnames(result) <- c(paste0("feature_", sub(":", "", feature)),
paste0("service_", sub(":", "", service)))
如果您已经拥有所有可能的功能和服务,则只需要sapply
部分。
答案 1 :(得分:2)
用定界符分割“ feature_service”列后,mtabulate
的一个选项
library(qdapTools)
out <- mtabulate(strsplit(df$feature_service, "[:, ]"))[-1] > 0
或者使用tidyverse
,创建一个行名称列,用separate_rows
中的定界符分割'feature_service',获得唯一行(distinct
),创建逻辑列TRUE ,并将spread
设置为“宽”格式
library(tidyverse)
df %>%
rownames_to_column('rn') %>%
separate_rows(feature_service) %>%
distinct(rn, feature_service) %>%
mutate(n = TRUE) %>%
spread(feature_service, n, fill = FALSE)
如果我们需要指定的列名,则在,
进行拆分后,再将separate
分为两列('key','val'),gather
从“宽”到“长”,unite
的“键/值”列成一个,spread
如上
df %>%
rownames_to_column('rn') %>%
separate_rows(feature_service, sep = ", ") %>%
separate(feature_service, into = c('feature', 'service')) %>%
gather(key, val, feature:service) %>%
distinct() %>%
unite(keyval, key, val) %>%
mutate(n = TRUE) %>%
spread(keyval, n, fill = FALSE) %>%
select(-rn)
# feature_a feature_b feature_c feature_d service_A service_B
#1 TRUE FALSE FALSE FALSE TRUE FALSE
#2 TRUE TRUE FALSE FALSE TRUE FALSE
#3 TRUE FALSE FALSE FALSE TRUE TRUE
#4 TRUE TRUE TRUE FALSE FALSE TRUE
#5 FALSE FALSE FALSE TRUE TRUE TRUE
答案 2 :(得分:1)
要完成三重奏(baseR
,tidyverse
,data.table
),这是我对data.table
的尝试,
library(data.table)
dt1 <- setDT(df)[, tstrsplit(feature_service, ", |:")]
dcast(melt(dt1, measure = names(dt1)), rowid(variable) ~ value, length)[,variable := NULL][] > 0
给出,
A B a b c d NA [1,] TRUE FALSE TRUE FALSE FALSE FALSE TRUE [2,] TRUE FALSE TRUE TRUE FALSE FALSE TRUE [3,] TRUE TRUE TRUE FALSE FALSE FALSE TRUE [4,] FALSE TRUE TRUE TRUE TRUE FALSE FALSE [5,] TRUE TRUE FALSE FALSE FALSE TRUE TRUE
注意::它也可以使NA
无效,因此在末尾增加了一列。