Подход purrr для создания новых столбцов через функцию с двумя аргументами

Я почти уверен, что есть способ добраться туда, но я не могу его найти.

У меня есть фрейм данных с несколькими столбцами. Теперь я хочу добавить новые столбцы в свой фрейм данных, содержащий информацию при выборке из этих столбцов (0/1). У меня есть аккуратное решение с across, которое работает, если я хочу выбрать одинаковое количество элементов из каждого столбца. У меня также есть (еще более уродливое) решение с across при выборке разного количества элементов из каждого столбца, но я надеялся на более простое решение с purrr, где я просто предоставляю имена столбцов в качестве одного аргумента и количество элементов для выборки как еще один аргумент, а затем получит мои новые столбцы.

Любые идеи?

Данные

df <- data.frame(x = runif(10),
                 y = runif(10),
                 z = runif(10))

df[1, 1] <- NA
df[2, 2] <- NA
df[3, 3] <- NA

sampling <- c(2, 3, 4)
names(sampling) <- c("random_x", "random_y", "random_z")

Решение для выборки одинакового количества элементов

df %>%
  mutate(across(everything(),
                ~if_else(is.na(.),
                         NA_integer_,
                         as.integer(row_number() %in% sample(which(!is.na(.)), size = 3))),
                .names = "{.col}_random"))

Решение для выборки другого количества элементов

df %>%
  mutate(across(everything(),
                ~if_else(is.na(.),
                         NA_integer_,
                         as.integer(row_number() %in% sample(which(!is.na(.)), size = sampling[str_detect(names(sampling), paste0(cur_column(), "$"))]))),
                .names = "{.col}_random"))

Желаемый способ мурлыкать

св. может по этим линиям?

df %>%
  map2(.x = c("x", "y", "z"),
       .y = sampling,
       .f = ~if_else(is.na(.x),
                     NA_integer_,
                     as.integer(row_number() %in% sample(which(!is.na(.x)), size = .y))))

Проблема с purrrм, очевидно, заключается в том, что я не использую правильный синтаксис, потому что я передаю вектор символов как .x, а не столбцы из df.

Желаемый результат

(оставляя в стороне случайность результатов)

           x          y         z x_random y_random z_random
1         NA 0.06686268 0.7663706       NA        0        0
2  0.7551366         NA 0.5550793        0       NA        1
3  0.7437531 0.61971712        NA        0        0       NA
4  0.5238451 0.57510689 0.7637622        1        0        0
5  0.9593917 0.17481769 0.4443493        0        0        0
6  0.2821633 0.86972254 0.2284449        0        0        0
7  0.3941531 0.61981285 0.8202302        0        0        1
8  0.1473573 0.58482156 0.9078447        0        1        1
9  0.7063327 0.77550907 0.9271699        1        1        1
10 0.6320678 0.06011700 0.2139956        0        1        0
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
1
0
59
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий
  • Вы не должны использовать df %>% map2(...), если вы передаете .x, .y отдельно в map2.
  • is.na(.x) неверно, так как .x — это значения символов (например, "x", "y" и "z"). Я использовал df[[.x]] для подмножества значений.
  • Поскольку мы не используем df %>% ..., поэтому row_number() не будет работать, поэтому мы изменили его на seq_along.

Вот подход с map2_dfc для создания новых столбцов, и мы используем bind_cols для привязки его к исходному фрейму данных.

library(dplyr)
library(purrr)

bind_cols(df, map2_dfc(.x = c("x", "y", "z"),
                       .y = sampling,
                       .f = ~tibble(!!paste0(.x, "_random") := 
           if_else(is.na(df[[.x]]), NA_integer_,
as.integer(seq_along(df[[.x]]) %in% sample(which(!is.na(df[[.x]])), size = .y))))))

#            x          y           z x_random y_random z_random
#1          NA 0.02358698 0.222022714       NA        0        1
#2  0.15099912         NA 0.878007560        0       NA        0
#3  0.20228598 0.92222805          NA        0        0       NA
#4  0.10955137 0.68713928 0.485866574        1        1        1
#5  0.57361508 0.56205208 0.367087414        1        1        0
#6  0.30534642 0.75997029 0.006055428        0        0        1
#7  0.76949447 0.78142772 0.279323093        0        0        0
#8  0.07178739 0.73181961 0.187739444        0        0        1
#9  0.52645525 0.48321814 0.213029355        0        1        0
#10 0.30858707 0.20973381 0.450931534        0        0        0

Спасибо. Интересный. Не обязательно выглядит проще, чем мой старый подход с дополнительным созданием tibble и bind_cols. Но, может быть, я просто был наивен, полагая, что есть простой способ мурлыкать.

deschen 23.04.2022 14:25

Другое возможное решение с использованием purrr::imap_dfc:

library(tidyverse)

mutate(df, imap_dfc(sampling, ~ +(1:nrow(df) %in% sample(setdiff(1:nrow(df), 
    which(is.na(df[, str_sub(.y, nchar(.y))]))), .x))) * ifelse(is.na(df), NA, 1))

#>              x         y          z random_x random_y random_z
#> 1           NA 0.5784770 0.87429843       NA        0        0
#> 2  0.483728093        NA 0.87502533        0       NA        0
#> 3  0.294748405 0.3057474         NA        0        0       NA
#> 4  0.993350082 0.4282864 0.02936437        0        0        1
#> 5  0.344054454 0.4872465 0.65317911        0        0        1
#> 6  0.465265657 0.6721587 0.77952998        0        1        1
#> 7  0.659649583 0.9923243 0.01262495        1        1        0
#> 8  0.314616988 0.7686583 0.99389609        1        0        0
#> 9  0.009670492 0.1558185 0.73083388        0        0        0
#> 10 0.102769163 0.1543078 0.84348806        0        1        1

Просто к вашему сведению, как я это решил. Очень похоже на решение @Ronak Shah, но немного отличается здесь и там:

df %>%
  add_column(map2_dfc(.x = c("x", "y", "z"),
                      .y = sampling,
                      .f = ~if_else(is.na(df[.x]),
                                    NA_integer_,
                                    as.integer(row_number(df[.x]) %in% sample(which(!is.na(df[.x])), size = .y)))) %>%
               rename_with(.cols = everything(),
                           .fn   = ~names(sampling)))

Другие вопросы по теме