Как изменить новый col в фрейме данных, используя определенную функцию и условия? Tidyverse/R

#r #dplyr #tidyverse

Вопрос:

Прежде всего, я не смог найти вопрос, связанный с моей проблемой, приношу извинения, если на этот вопрос уже был дан ответ.

У меня есть фрейм данных с некоторыми столбцами, и я хочу вычислить новое значение, используя определенную формулу. Я предполагаю, что мне придется использовать mutate() из tidyverse, но я хочу избежать строк/выборок, в которых есть одно или несколько значений 0. Я не знаю, как я могу проверить, есть ли какой-либо 0, когда я использую mutate() . Кроме того, я не знаю, как я могу применить свою конкретную формулу для создания нового столбца.

Я оставляю здесь код для создания фрейма данных в качестве примера моей проблемы.

 set.seed(123)
df <- data.frame(
  time = seq(now(), now() hours(11),by='hours'),
  a = sample(0:100,12),
  b = sample(0:100,12),
  c = sample((0:20)/1000,12))

df[1:3,]$a <- 0
df[3:5,]$b <- 0
df[3:4,]$c <- 0

# function: M = a*b (1-e^(-c/2))
# if any 0 in the row -> M = NA
# else: apply function
 

Функция может быть записана как

 a*b*(1-exp(-c/2))
 

В окончательном df должно быть 4 столбца за каждый час (строка) (a,b,c и новое вычисленное M), но когда a | b | c == 0, M = NA .

Я буду очень благодарен за каждую небольшую помощь. Ура!

РЕДАКТИРОВАТЬ: Реальная функция сложнее, чем в этом примере,поэтому не всегда будет верно,что если один член (a, b, c,…) равен 0, то результирующее M равно 0. Извините, я не понял, что этот постулат верен для упрощенного уравнения. Но я хочу избежать любого значения 0, потому что они получены из мониторинга физиологических переменных, и я знаю, что если одно значение равно 0 в выборке, то выборка неверна, так что НЕТ.

Ответ №1:

Если какое-либо из a , b или c равно 0, оно возвращается M как 0, которое можно изменить на NA .

 library(dplyr)

df %>%
  mutate(M = a*b*(1-exp(-c/2)), 
         M = na_if(M, 0))

#                  time  a  b     c         M
#1  2021-10-18 19:41:56  0 90 0.013        NA
#2  2021-10-18 20:41:56  0 56 0.016        NA
#3  2021-10-18 21:41:56  0  0 0.000        NA
#4  2021-10-18 22:41:56 13  0 0.000        NA
#5  2021-10-18 23:41:56 66  0 0.011        NA
#6  2021-10-19 00:41:56 41 71 0.014 20.305847
#7  2021-10-19 01:41:56 49 25 0.009  5.500115
#8  2021-10-19 02:41:56 42  6 0.012  1.507473
#9  2021-10-19 03:41:56 97 41 0.017 33.661237
#10 2021-10-19 04:41:56 24 97 0.008  9.293401
#11 2021-10-19 05:41:56 89 82 0.019 69.002718
#12 2021-10-19 06:41:56 68 35 0.015 17.783230
 

Комментарии:

1. О, извините, возможно, это был не лучший пример, я попытался упростить набор данных и уравнение. Уравнение упрощено. Например,в оригинале есть добавленный термин, поэтому неверно, что если один термин равен 0, M будет равен 0. Я опубликую исходное уравнение здесь: a b*(c d(1-exp(-e/(f g)))) Я использую буквы, чтобы было легче понять. Извините за недоразумение. Знаете ли вы, можно ли использовать условие, как я просил изначально, без использования этого «математического» трюка, который вы опубликовали?

2. Если есть способ использовать что-то вроде части » M = na_if(M, 0)», но вместо M искать 0 в a, b, c,…, этого будет достаточно, но я не знаю ни одной подобной функции. Ty

3. В конце концов, я использовал ваш подход, но наоборот. Во-первых, я заменил все 0 значениями NA, поэтому уравнение вернет NA. Я отмечу ваш ответ как решение. Однако я все равно был бы признателен, если бы знал, есть ли способ сделать это с учетом условий.

4. @RobertoT Как насчет df %>% mutate(M = ifelse(if_any(a:c, ~. == 0), NA, a*b*(1-exp(-c/2)))) ?

5. Большое спасибо! Я не знал, все ли. Это отличное решение.