When using 'reduce' combine a list to 'final_0' (refer below image), how to mutate new variable 'amount_from'? my code show error . Thanks!
library(tidyverse)
table_base <- data.frame(cat=c("a","b","c","d"))
table_a <- data.frame(cat=c("a","b"),
value=c(1,2))
table_b <- data.frame(cat=c("a","c","d"),
value=c(7,9,10))
final_0<- reduce(list(table_base,table_a,table_b),left_join,by='cat') %>%
mutate(amount=coalesce(!!!select(.,starts_with('value'))))
#below code show error [no applicable method for 'fill' applied to an object of class "character"]
final_0 %>% pivot_longer(-c('cat','amount')) %>%
mutate(value_from=if_else(amount==value,name,NULL)) %>%
group_by(cat) %>%
mutate(value_from=tidyr::fill(value_from,.direction = "downup"))
CodePudding user response:
Running ?fill will show the issue:
Usage
fill(data, ..., .direction = c("down", "up", "downup", "updown"))
The function takes a data frame and a set of columns to fill (from ...). In your implementation, you used it inside a mutate() call.
Here's how to fix the issue:
final_0 %>%
pivot_longer(-c('cat','amount')) %>%
mutate(value_from=if_else(amount==value,name,NULL)) %>%
group_by(cat) %>%
fill(value_from, .direction = "downup")
# A tibble: 8 x 5
# Groups: cat [4]
cat amount name value value_from
<chr> <dbl> <chr> <dbl> <chr>
1 a 1 value.x 1 value.x
2 a 1 value.y 7 value.x
3 b 2 value.x 2 value.x
4 b 2 value.y NA value.x
5 c 9 value.x NA value.y
6 c 9 value.y 9 value.y
7 d 10 value.x NA value.y
8 d 10 value.y 10 value.y
Although this works, there is a solution that that avoids unnecessarily creating NULL values using if_else() and then needing to fill them:
final_0 %>%
pivot_longer(-c("cat", "amount")) %>%
group_by(cat) %>%
mutate(value_from = na.omit(name[amount == value]))
# A tibble: 8 x 5
# Groups: cat [4]
cat amount name value value_from
<chr> <dbl> <chr> <dbl> <chr>
1 a 1 value.x 1 value.x
2 a 1 value.y 7 value.x
3 b 2 value.x 2 value.x
4 b 2 value.y NA value.x
5 c 9 value.x NA value.y
6 c 9 value.y 9 value.y
7 d 10 value.x NA value.y
8 d 10 value.y 10 value.y
Some important notes about this:
- We simply filter on
nameusing yourif_else()condition. We then applyna.omit()sincevaluecould beNA. - This code can result in different values of
value_fromfor the samecatin the case thatvalue.xandvalue.yare both equal toamount. This would also happen in your implementation because of the way you usedif_else(). If you wantvalue_fromto only have one value for eachcat, you should use something likena.omit(name[amount == value])[[1]]in the code above.

