我可以用`across`或`{purrr}`语法来缩短和简化我的dmgr代码吗?

qxsslcnc  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(58)

从列表correspdf_modifies

# Note : corresp must be a list and not a data.frame 

corresp <- list(
  a_remplacer = c("abricot1"),
  remplacant = c("abricot2")
)

df_modifies <- data.frame(
  produit = c("abricot1", "abricot2"),
  m0123 = c(3, NA),
  m0223 = c(2.5, NA),
  m0323 = c(3, 2),
  m0423 = c(NA, 3)
)

我希望得到以下结果:

produit m0123 m0223 m0323 m0423
1 abricot2     3   2.5     2     3

我的代码很长,我想用across{purrr}来缩短它。

library(dplyr)

modifies <- data.frame(
  produit = corresp$remplacant) |> 
  mutate(
    m0123 = ifelse(is.na(df_modifies$m0123[df_modifies$produit %in% corresp$remplacant]),
                   df_modifies$m0123[which(!is.na(df_modifies$m0123))[1]],
                   df_modifies$m0123[df_modifies$produit %in% corresp$remplacant]),
    m0223 = ifelse(is.na(df_modifies$m0223[df_modifies$produit %in% corresp$remplacant]),
                   df_modifies$m0223[which(!is.na(df_modifies$m0223))[1]],
                   df_modifies$m0223[df_modifies$produit %in% corresp$remplacant]),
    m0323 = ifelse(is.na(df_modifies$m0323[df_modifies$produit %in% corresp$remplacant]),
                   df_modifies$m0323[which(!is.na(df_modifies$m0323))[1]],
                   df_modifies$m0323[df_modifies$produit %in% corresp$remplacant]),
    m0423 = ifelse(is.na(df_modifies$m0423[df_modifies$produit %in% corresp$remplacant]),
                   df_modifies$m0423[which(!is.na(df_modifies$m0423))[1]],
                   df_modifies$m0423[df_modifies$produit %in% corresp$remplacant])
  )

你能帮帮我吗?

qmelpv7a

qmelpv7a1#

填写NA,然后填写子集:

# fill NAs
df_modifies_fill <- data.frame(lapply(df_modifies, zoo::na.locf))
#    produit m0123 m0223 m0323 m0423
# 1 abricot1     3   2.5     3     3
# 2 abricot2     3   2.5     2     3

# then subset based on correst list value
df_modifies_fill[df_modifies_fill$produit == corresp$a_remplacer, ]
#    produit m0123 m0223 m0323 m0423
# 1 abricot1     3   2.5     3     3

# or loop through all list values
lapply(corresp, function(i) df_modifies_fill[df_modifies_fill$produit == i, ])
# $a_remplacer
#    produit m0123 m0223 m0323 m0423
# 1 abricot1     3   2.5     3     3
# 
# $remplacant
#    produit m0123 m0223 m0323 m0423
# 2 abricot2     3   2.5     2     3
jljoyd4f

jljoyd4f2#

我不确定这个答案的缩放版本如何工作,但你可以这样使用across

df_modifies |> 
  summarise(across(-produit, \(x) ifelse(is.na(x[produit == corresp$remplacant]), 
                                         x[produit == corresp$a_remplacer],
                                         x[produit == corresp$remplacant])),
            produit = corresp$remplacant)

#   m0123 m0223 m0323 m0423  produit
# 1     3   2.5     2     3 abricot2
pdsfdshx

pdsfdshx3#

前两种方法使用tidyverse,第三种使用data.table。

1)proc_transpose/coalesce我们使用proc_transpose转置df_modifiesm...列,并使用coalesce执行NA消除。最后再次使用proc_transpose转换回原始形式。

请注意,proc_transpose概念上

  • id=列移动到行名称
  • 转置(这也会互换行和列名)
  • 将矩阵转换为 Dataframe
  • 将结果行名称移回新的NAME

代码

library(dplyr)
library(procs)

df_modifies %>%
  proc_transpose(id = produit) %>%
  reframe(NAME, 
    value = coalesce(.[[corresp$remplacant]], .[[corresp$a_remplacer]])) %>%
  proc_transpose(id = "NAME") %>%
  mutate(produit = corresp$remplacant, .before = 1, NAME = NULL)

##    produit m0123 m0223 m0323 m0423
## 1 abricot2     3   2.5     2     3

**1a)pivot_**一种变体是使用pivot_longer,然后使用pivot_wider来实现转置,最后使用pivot_wider转置回来,如图所示:

library(dplyr)
library(tidyr)

df_modifies %>%
  pivot_longer(-produit) %>%
  pivot_wider(names_from = "produit") %>%
  reframe(name, value = coalesce(.[[corresp$remplacant]], .[[corresp$a_remplacer]])) %>%
  pivot_wider %>%
  mutate(produit = corresp$remplacant, .before = 1)

## # A tibble: 1 × 5
##   produit  m0123 m0223 m0323 m0423
##   <chr>    <dbl> <dbl> <dbl> <dbl>
## 1 abricot2     3   2.5     2     3

2)data.frame/fill另一种方法是将corresp转换为 Dataframe ,然后将其连接到df_modifies,以便在name上排序时将行按fill应用于m...列时的顺序排列。然后取最后一行并删除name列。

请注意,在示例中,df_modifies的行已经处于正确的顺序,因此如果我们知道我们可以避免使用corresp和相关的排序,则解决方案仅为df_modifies %>% fill(starts_with("m")) %>% slice_tail(n = 1)

library(dplyr)
library(purrr) # list_transpose
library(tidyr) # fill  
library(tibble) # enframe

df_modifies %>%
  left_join(enframe(list_transpose(corresp)[[1]]), by = c(produit = "value")) %>%
  arrange(name) %>%
  select(-name) %>%
  fill(starts_with("m")) %>%
  slice_tail(n = 1)

##    produit m0123 m0223 m0323 m0423
## 1 abricot2     3   2.5     2     3

3)转置/fcoalesce这与(1)类似,只是它使用了带有transpose而不是pivot_*的data.table

library(data.table)

dt <- as.data.table(df_modifies)

dt[, transpose(.SD, make.names = "produit", keep.names = "name")][,
  c("value") := fcoalesce(get(corresp$remplacant), get(corresp$a_remplacer))][,
  transpose(.SD[, c("name", "value")], make.names="name", keep.names="produit")][,
  produit := corresp$remplacant][]

##     produit m0123 m0223 m0323 m0423
## 1: abricot2     3   2.5     2     3

更新

已经更新了很多次,以简化和添加替代品。

相关问题