我最近已从case_when
从ifelse转换为dplyr
。
目标
我希望能够使用case_when
从数据框中的一条语句中检测到多个正则表达式,如下所示:
输入
statement<-data.frame(statement = c("I have performed APC and RFA",
"An EMR was done","I didn't do anything"),stringsAsFactors=FALSE)
所需的输出
statement out
I have performed APC and RFA APC,RFA
An EMR was done EMR
I didn't do anything No Event
尝试
library(dplyr)
library(stringr)
dataframe <-
dataframe %>%
mutate(
EVENT = case_when(
str_detect(statement,"EMR") ~ "EMR",
str_detect(statement, "HALO|RFA") ~ "RFA",
str_detect(statement, "APC") ~ "APC",
TRUE ~ "No Event"
)
)
问题
每个语句仅提供一个输出,如果存在多个字符串,则不会提供多个输出。有没有办法检测多个字符串?
答案 0 :(得分:1)
1)gsubfn :: strapply @Override
public List<RowType> getRows() {
return Collections.unmodifiableList(implList);
}
可以一次完成提取和翻译。对于strapply
的每个组成部分,strapply
将与模式stmt
匹配,所有匹配项将使用L进行翻译,然后返回。 pat
参数定义了empty
没有匹配项的组件返回的内容。这样就给出了一个匹配项列表,每行一个列表项,在其上应用stat
将它们转换为逗号分隔的字符串。这是这里提出的3种选择中最短的一种。
toString
给予:
library(gsubfn)
L <- list(APC = "APC", EMR = "EMR", HALO = "RFA", RFA = "RFA")
pat <- paste(names(L), collapse = "|")
transform(statement,
out = sapply(strapply(stmt, pat, L, empty = "No Event"), toString),
stringsAsFactors = FALSE)
2)基数R 从上方使用 stmt out
1 I have performed APC and RFA APC, RFA
2 An EMR was done EMR
3 I didn't do anything No Event
和L
,创建一个函数,该函数采用单词pat
的字符向量并提取出匹配的单词由x
变成pat
。如果g
的长度非零,则使用g
转换其元素,然后使用L
将其压缩为单个字符串;否则,返回toString
。
现在使用No Event
将stmt
的每个元素分解为单词,并将strsplit
应用于每个这样的字符向量。
process
3)dplyr / tidyr 使用(1)中的process <- function(x) {
g <- grep(pat, x, value = TRUE)
if (length(g)) toString(L[g]) else "No Event"
}
transform(statement, out = sapply(strsplit(stmt, "\\s+"), process),
stringsAsFactors = FALSE)
按行号和L
分组,并将单词分成不同的行。过滤掉stmt
中的这些单词,并将所有行折叠到一个names(L)
组中,这些行通过stmt
转换并使用L
生成逗号分隔的字符串。删除toString
列。在这一点上,我们得到了理想的结果,只是仍然缺少n
行,因此请用No Event
正确加入我们的行,并用statement
替换NA。
No Event
给予:
library(dplyr)
library(tidyr)
statement %>%
group_by(n = 1:n(), out = stmt) %>%
separate_rows(out) %>%
filter(out %in% names(L)) %>%
summarize(stmt = stmt[1], out = toString(L[out])) %>%
ungroup %>%
select(-n) %>%
right_join(statement, by = "stmt") %>%
mutate(out = if_else(is.na(out), "No Event", out))
我们以此为输入
# A tibble: 3 x 2
stmt out
<chr> <chr>
1 I have performed APC and RFA APC, RFA
2 An EMR was done EMR
3 I didn't do anything No Event
重新阅读问题后已进行了多次修订。还添加了更多替代方案。
答案 1 :(得分:0)
通过基数R的想法是提取所有大写字母的单词,然后粘贴大于1个字符的单词,即
sapply(regmatches(statement$statement, gregexpr('\\b[A-Z]+\\b', statement$statement)),
function(i) {
v1 <- i[nchar(i) > 1];
toString(v1)
})
#[1] "APC, RFA" "EMR" ""
答案 2 :(得分:0)
case_when
的逻辑是,一旦满足条件,它就不会执行其余条件,因此您实际上不能从case_when
语句中获得两个输出。因此,如果您想使用case_when
,建议先从一个最不常见的条件开始,然后再慢慢使其更通用。 (因此,TRUE
是最后一个条件)
如果您想坚持使用case_when
,则可以添加一个附加条件并分别检查这两种情况,并相应地提供输出。
library(dplyr)
statement %>%
mutate(
EVENT = case_when(
str_detect(statement, "APC") & str_detect(statement, "RFA") ~ "APC,RFA",
str_detect(statement,"EMR") ~ "EMR",
str_detect(statement, "HALO|RFA") ~ "RFA",
str_detect(statement, "APC") ~ "APC",
TRUE ~ "No Event"
)
)
# statement EVENT
#1 I have performed APC and RFA APC,RFA
#2 An EMR was done EMR
#3 I didn't do anything No Event
#4 FALSE No Event
答案 3 :(得分:0)
我不认为case_when
是最好的选择。我认为这取决于您有多少个像"HALO|RFA"
这样的映射。如果有很多,可能值得花时间编写适当的函数。但是,如果只是这样,则使用dplyr动词将管道组合在一起可能会更快。
我建议使用str_extract_all
和unnest
来获得带有相关动词的整洁数据帧,然后使用str_replace_all
来解决映射。最后,我将使用unique
确保替换中没有重复的行。
请注意,带有APC,RFA的第一列将分为两部分。我意识到这不是您要的,但是它将使tidyverse中的后续处理变得更加容易。有关整洁数据约定的更多信息,请参见以下链接:https://tidyr.tidyverse.org/articles/tidy-data.html
在当前的实现中,unnest
将删除没有模式匹配的最后一行。如果您希望使用NA
,则可以对原始数据执行full join
。另请参见https://github.com/tidyverse/tidyr/issues/358
statement<-data.frame(statement = c("I have performed APC and RFA","An EMR was done","I didn't do anything"),stringsAsFactors=FALSE)
library(tidyverse)
statement %>% mutate(
out = statement %>%
str_extract_all("((EMR)|(HALO)|(RFA)|(APC))")
) %>% unnest(.drop =FALSE) %>%
mutate(
out = out %>% str_replace_all("HALO", "RFA")
) %>%
unique() %>%
full_join(statement)
输出将为
statement out
I have performed APC and RFA APC
I have performed APC and RFA RFA
An EMR was done EMR
I didn't do anything <NA>