如何解决用两个平行的列名列表改变多列的整洁方法
我想找到一种整洁的方法来执行我必须为多对列执行的数据清理步骤。
df <- data.frame(apple = c("Yes",NA,"Yes",NA),apple_NO = c(NA,"No_1","No_2"),berry = c("Yes","Yes"),berry_NO = c(NA,coconut = c(NA,coconut_NO = c("No_2",dinosaur = c("Yes",dinosaur_NO = c(NA,"No_2",NA))
> df
apple apple_NO berry berry_NO coconut coconut_NO dinosaur dinosaur_NO
1 Yes <NA> Yes <NA> <NA> No_2 Yes <NA>
2 <NA> No_1 Yes <NA> Yes <NA> <NA> No_2
3 <NA> No_1 <NA> No_1 Yes <NA> <NA> No_1
4 Yes <NA> <NA> No_1 Yes <NA> <NA> No_2
5 <NA> No_2 Yes <NA> <NA> No_2 Yes <NA>
cols <- c("apple","berry","coconut","dinosaur")
cols_NO <- c("apple_NO","berry_NO","coconut_NO","dinosaur_NO")
我想清除 cols_NO
中列中的值并为 cols
中的列分配新值
例如,如果我只需要清理一对列,我会执行以下操作:
df <- df %>%
mutate(apple = case_when(apple_NO == "No_1" ~ "None left",apple_NO == "No_2" ~ "Finished",TRUE ~ apple))
我也想用 berry
和 berry_NO
以及 coconut
和 coconut_NO
等来做到这一点。
我想要的输出看起来像这样:
apple apple_NO berry berry_NO coconut coconut_NO dinosaur dinosaur_NO
1 Yes <NA> Yes <NA> Finished No_2 Yes <NA>
2 None left No_1 Yes <NA> Yes <NA> Finished No_2
3 None left No_1 None left No_1 Yes <NA> None left No_1
4 Yes <NA> None left No_1 Yes <NA> None left No_2
5 Finished No_2 Yes <NA> Finished No_2 Yes <NA>
我认为在使用 map
或 map2
或 mapply
和并行列表的某个地方有一个解决方案,但我以前没有使用过,似乎找不到我可以使用的类似解决方案,在 =
中的 mutate
的左侧和右侧显示列列表。
谢谢!
编辑:
这让我很接近,但我仍然需要将其替换或 mutate_at
到我的主数据框。我的真实数据会从使用 grepl
中受益,所以我只是把它留在了。
fun.casewhen <- function(cols,cols_NO){
case_when(grepl("No_1",cols_NO) == TRUE ~ "None left",grepl("No_2",cols_NO) == TRUE ~ "Finished",TRUE ~ cols)
}
dftest <- map2(df %>% select(cols),df1 %>% select(cols_NO),~ fun.casewhen (.x,.y))
生成的 dftest 由 cols
中每一列的列表组成,但具有正确的值。
解决方法
这是一个 data.table
+ rlist
方法
library( data.table )
library( rlist )
data.table::setDT(df)
L <- split.default( df,gsub( "_NO","",names(df) ) )
rlist::list.cbind( lapply( L,function(x) x[,1 := data.table:: fcoalesce(x) ] ) )
,
这是一个依赖于多个支点的 tidyverse 解决方案。我确定这不是最简洁的方法,但作为另一种选择。
df %>%
mutate(row = row_number()) %>%
pivot_longer(-row) %>%
separate(name,c("group","keep"),sep = "_") %>%
pivot_wider(names_from = keep,values_from = value) %>%
mutate(`NA` = case_when(NO == "No_1" ~ "None left",NO == "No_2" ~ "Finished",TRUE ~ `NA`)) %>%
pivot_longer(-c(row,group)) %>%
unite("col",c(group,name)) %>%
pivot_wider(names_from = col,values_from = value)
row apple_NA apple_NO berry_NA berry_NO coconut_NA coconut_NO dinosaur_NA dinosaur_NO
<int> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 Yes NA Yes NA Finished No_2 Yes NA
2 2 None left No_1 Yes NA Yes NA Finished No_2
3 3 None left No_1 None left No_1 Yes NA None left No_1
4 4 Yes NA None left No_1 Yes NA Finished No_2
5 5 Finished No_2 Yes NA Finished No_2 Yes NA
,
我找到了一种将值分配给我的 df 的方法,尽管不是最好的 tidyr 风格:
fun.casewhen <- function(cols,cols_NO){
case_when(grepl("No_1",cols_NO) == TRUE ~ "None left",grepl("No_2",cols_NO) == TRUE ~ "Finished",TRUE ~ cols)
}
df[cols] <- map2(df %>% select(cols),df1 %>% select(cols_NO),~ fun.casewhen (.x,.y))
我之前错过了 [cols]
中的 df[cols]
。尽管如此,很高兴知道是否有更符合 tidyr 标准的解决方案,可以使用 mutate
和管道清理数据。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。