r语言 - 在 dplyr::mutate 中使用 strsplit(不带 tibble::d ata_frame)会引发"Evaluation error: non-character argum



编辑:我的df创作中有一个错别字,MediaName的最后一个值缺少_;现在已经更正了。

我想在数据框中创建一个新的变量TrialId作为另一个变量MediaName值的一部分,具体取决于第三个变量Phase的值,并认为我可以在dplyr::mutate中使用strsplitifelse来做到这一点,如下所示:

library(dplyr)
# Creating a simple data frame for the example
df <- data.frame(Phase = c(rep("Familiarisation",8),rep("Test",3)),
MediaName = c("Flip_A1_G1","Reg_B2_S1","Reg_A2_G1","Flip_B1_S1",
"Reg_A1_G2","Flip_B2_S2","Reg_A2_G2","Flip_B1_S2",
"HC_A1L","TC_B1R","RC_BL_2R"))
# Creating a new column
df <- df %>%
mutate(TrialId = ifelse(Phase == "Familiarisation",
sapply(strsplit(MediaName, "_"), "[", 2),
sapply(strsplit(MediaName, "_"), "[", 1)))

预期结果是

> df$TrialId
[1] "A1" "B2" "A2" "B1" "A1" "B2" "A2" "B1" "HC" "TC" "RC"

但是,这给了我以下错误,因为我相信strsplit

Error in mutate_impl(.data, dots) : 
Evaluation error: non-character argument.

我从这个 SO 问题中知道,我可以在这个小示例中将数据框定义为tibble::data_frame,而无需知道为什么这可以解决问题,从而轻松解决我的问题。我不能完全做到这一点,尽管在我的实际代码中,df来自读取csv文件(带有read.csv())。我一直认为使用df <- df %>% as_tibble() %>% mutate(...)会以类似的方式解决问题,但它没有(为什么?

有没有办法在读取文件时实际使用tibble?或者有没有另一种方法可以实现我需要做的事情,而不使用strsplit也许?

我也在阅读另一个您可以使用tidyr::separate的 SO 问题,但它并没有完全按照我的意愿做,因为我需要根据Phase的值保留第一个或第二个值。

你可以试试:

library(tidyverse)
# your first data 
df_old <- data.frame(Phase = c(rep("Familiarisation",8),rep("Test",3)),
MediaName = c("Flip_A1_G1","Reg_B2_S1","Reg_A2_G1","Flip_B1_S1",
"Reg_A1_G2","Flip_B2_S2","Reg_A2_G2","Flip_B1_S2",
"HC_A1L","TC_B1R","RC_BL2R"))
df_old %>% 
separate(MediaName, into=letters[1:3], sep="_", fill = "left", remove = FALSE) %>% 
select(Phase, MediaName, TrialId=b)
Phase  MediaName TrialId
1  Familiarisation Flip_A1_G1      A1
2  Familiarisation  Reg_B2_S1      B2
3  Familiarisation  Reg_A2_G1      A2
4  Familiarisation Flip_B1_S1      B1
5  Familiarisation  Reg_A1_G2      A1
6  Familiarisation Flip_B2_S2      B2
7  Familiarisation  Reg_A2_G2      A2
8  Familiarisation Flip_B1_S2      B1
9             Test     HC_A1L      HC
10            Test     TC_B1R      TC
11            Test    RC_BL2R      RC

它是根据提供的示例数据的硬编码解决方案。用"_"分隔,如果只有两个而不是三个"_"从左侧填充NA。最后,选择所需的列。

编辑

使用新数据,情况会稍微复杂一些。 但您可以尝试:

df %>% 
add_column(MediaName_keep=df$MediaName) %>% 
group_by(MediaName_keep) %>% 
separate_rows(MediaName, sep="_") %>% 
mutate(n=1:n()) %>% 
filter((Phase == "Familiarisation" & n == 2) | (Phase == "Test" & n == 1)) %>% 
select(Phase, MediaName=MediaName_keep, TrialId=MediaName)
# A tibble: 11 x 3
# Groups:   MediaName [11]
Phase  MediaName TrialId
<fctr>     <fctr>   <chr>
1 Familiarisation Flip_A1_G1      A1
2 Familiarisation  Reg_B2_S1      B2
3 Familiarisation  Reg_A2_G1      A2
4 Familiarisation Flip_B1_S1      B1
5 Familiarisation  Reg_A1_G2      A1
6 Familiarisation Flip_B2_S2      B2
7 Familiarisation  Reg_A2_G2      A2
8 Familiarisation Flip_B1_S2      B1
9            Test     HC_A1L      HC
10            Test     TC_B1R      TC
11            Test   RC_BL_2R      RC

想法是一样的。分开,但此时按MediaName_keep添加和计算新行,然后根据您的需要进行过滤。

您遇到的问题是因为字符串在factor中自动转换,因此您无法将strsplit()应用于非字符串对象。我的解决方案只是将MediaName转换为string类型。

require(dplyr)    
df <- df %>%
dplyr::mutate(MediaName = as.character(levels(df$MediaName))[df$MediaName]) %>%
dplyr::mutate(TrialId = ifelse(Phase == "Familiarisation",
sapply(strsplit(MediaName, "_"), "[", 2),
sapply(strsplit(MediaName, "_"), "[", 1))) 


solution<- c("A1", "B2", "A2", "B1", "A1", "B2", "A2", "B1", "HC", "TC", "RC")
identical(solution, df$TrialId)
[1] TRUE

最新更新