Existuje efektívny spôsob, ako zmeniť len na riadky, ktoré spĺňajú podmienku? Myslím, mutovať(ak(stav))

0

Otázka

Teším sa uplatňujú mutovať, len ak sú splnené určité podmienky.

Viem, že som si to...

data2 <- data1 %>%
   group_by(a, b) %>%
   mutate(
      var1 = case_when(
         condition ~ TRUE,
         TRUE ~ FALSE,
         NA
         ),
      var2 = case_when(
         condition ~ TRUE,
         max(var28),
         var2
         ),
      var3 = case_when(
         condition ~ TRUE,
         "happy",
         var3
         ),
...more vars here....
)

Čo by som chcel je niečo, čo vyzerá takto...

data2 <- data1 %>%
   group_by(a, b) %>%
   mutate(
      when(condition),
      var1 = FALSE,
      var2 = max(var28),
      var3 = "happy",
...more vars here....
)

Bohužiaľ mutate(across(when(condition))) nefunguje.

Všetky suggesions?

conditional-statements dplyr r tidyverse
2021-11-23 22:06:02
2

Najlepšiu odpoveď

4

Nie je funkčnosť urobiť v mutovať, ale Romain Francois má spoločnú funkciu by ste mohli sami určiť, ktorý to:

library(dplyr, warn.conflicts = F)

mutate_when <- function(.data, when, ...) {
  dots <- enquos(...)
  names <- names(dots)
  
  mutate(.data, {
    test <- {{ when }}
    
    changed <- data.frame(!!!dots, stringsAsFactors = FALSE)
    out <- across(all_of(names))
    # assuming `changed` and `out` have the same data frame type

    out[test, ] <- changed[test, ]
    out
  })
  
}

tibble(x = 1:4, y = 1:4) %>% 
  mutate_when(x < 4, x = -x, y = -y)
#> # A tibble: 4 × 2
#>       x     y
#>   <int> <int>
#> 1    -1    -1
#> 2    -2    -2
#> 3    -3    -3
#> 4     4     4

Vytvorené na 2021-11-23 podľa reprex balík (v2.0.1)

2021-11-23 22:24:23

Je to presne zjednodušené funkcie som hľadal. Vďaka!
k6adams
1

Iné možné riešenie je použiť cez() a ifelse(), napr. ak je hodnota v stĺpci x je menej ako štyri, vykonajte mutácie:

library(tidyverse)
tibble(x = c(1:2, 4:5), y = 1:4) %>% 
  mutate(across(everything(), ~ ifelse(x < 4, -.x, .x)))
#> # A tibble: 4 × 2
#>       x     y
#>   <int> <int>
#> 1    -1    -1
#> 2    -2    -2
#> 3     4     3
#> 4     5     4

Vytvorené na 2021-11-24 podľa reprex balík (v2.0.1)

Môžete tiež hniezdo ifelse to spolu, napr. ak je hodnota v stĺpci x je menší ako 4, alebo ak hodnota v každom stĺpci je rovná 3, mutovať:

library(tidyverse)
tibble(x = c(1:2, 4:5), y = 1:4) %>% 
  mutate(across(everything(), ~ ifelse(x < 4, -.x,
                                       ifelse(.x == 3, .x + 10, .x))))
#> # A tibble: 4 × 2
#>       x     y
#>   <int> <dbl>
#> 1    -1    -1
#> 2    -2    -2
#> 3     4    13
#> 4     5     4

Vytvorené na 2021-11-24 podľa reprex balík (v2.0.1)

A tak sa na:

library(tidyverse)
tibble(x = c(1:2, 4:5), y = 1:4) %>% 
  mutate(across(everything(), ~ ifelse(x < 4, -.x,
                                       ifelse(.x == 3, .x + 10,
                                              ifelse(.x >= 5, "outlier", .x)))))
#> # A tibble: 4 × 2
#>   x           y
#>   <chr>   <dbl>
#> 1 -1         -1
#> 2 -2         -2
#> 3 4          13
#> 4 outlier     4

Vytvorené na 2021-11-24 podľa reprex balík (v2.0.1)

--

Robiť mutácie efektívnejšie, nepoužívajte dplyr::mutovať. Na ifelse() funkcia je vektorizované (ďalšie podrobnosti: https://swcarpentry.github.io/r-novice-gapminder/09-vectorization/) a ak máte veľký dataframe, ifelse sám sa veľmi pravdepodobné, že sa rýchlejšie ako tidyverse funkcie, napr.

library(tidyverse)
df <- tibble(x = c(1:2, 4:5), y = 1:4)
df$y <- ifelse(df$x < 4, -df$y, df$y)
df
#> # A tibble: 4 × 2
#>       x     y
#>   <int> <int>
#> 1     1    -1
#> 2     2    -2
#> 3     4     3
#> 4     5     4

Upraviť

Ďalší potenciálny možnosť je nahradiť hodnoty prostredníctvom priradenia: df$y[df$x < 4] <- -(df$y); df$x[df$x < 4] <- -(df$x) (rýchlo, ale existujú obmedzenia).

Tu je rýchly benchmark z navrhovaných metód s 1 milión riadkov:

library(tidyverse)
df <- tibble(x = sample(1:10, 1000000, replace = TRUE),
             y = sample(1:10, 1000000, replace = TRUE))

mutate_func <- function(df){
  df %>%
    mutate(across(everything(), ~ ifelse(x < 4, -.x, .x)))
}

ifelse_func <- function(df){
  df$y <- ifelse(df$x < 4, -df$y, df$y)
}

replacement_func <- function(df) {
  df$y[df$x < 4] <- -(df$y)
  df$x[df$x < 4] <- -(df$x)
}

mutate_when_func <- function(df) {
  mutate_when <- function(.data, when, ...) {
    dots <- enquos(...)
    names <- names(dots)
  
    mutate(.data, {
      test <- {{ when }}
    
      changed <- data.frame(!!!dots, stringsAsFactors = FALSE)
      out <- across(all_of(names))
      # assuming `changed` and `out` have the same data frame type
    
      out[test, ] <- changed[test, ]
      out
    })
  }

df %>% 
  mutate_when(x < 4, x = -x, y = -y)
}

library(microbenchmark)
result <- microbenchmark(mutate_func(df), ifelse_func(df),
                         mutate_when_func(df), replacement_func(df),
                         times = 10)
autoplot(result)

example_1.png

2021-11-23 22:16:02

to je naozaj skvelé analýzy. V mojej konkrétnej situácii, mám malé údajov, kde výstup je odvodený od premenných pomocou diagramu, a kód môže byť díval sa na menej technické publikum. Takže mutate_when funkcia sa hodí bill tento čas, ale je to dobré vedieť, zapouzdřit ja alebo niekto iný je na tom niečo viac computationally intenzívne.
k6adams

V iných jazykoch

Táto stránka je v iných jazykoch

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................