Расчет с несколькими условиями - PullRequest
0 голосов
/ 24 января 2019

Привет, ребята. У меня есть этот Dataframe в R:

m2 <- c(22,NA,0,NA,42,NA)
m3 <- c(89,38,0,67,0,NA)
df = data.frame(m2,m3)

Я хочу вычислить доходность между м3 и м2.Форма имеет вид: return = (m2 [i] - m3 [i]) / m3 [i].Условия для вычисления:

  1. , если m2 [i] = NA или m3 [i] = NA, тогда результат = NA
  2. , если m2 [i] = 0 и m3 [i] = 0, тогда результат = -9999
  3. , если m2 [i]! = 0 и m3 [i] = 0, то результат = 9999

До сих пор я пробовал этикод:

   for (i in nrow(df)){
      if (is.na(df[['m2']][i]) == TRUE | is.na(df[['m3']][i]) == TRUE){df[['result']][i] = NA}
      if (df[['m2']][i] == 0 & df[['m3']][i] == 0) {df[['result']][i] = 9999}
      if (df[['m3']][i] == 0 | df[['m2']][i] != 0) {df[['result']][i] = -9999}
      else {df[['result']][i] = (df[['m2']][i] - df[['m3']][i])/df[['m3']][i]}
    }

Но возвращается, как показано ниже:

 Error in if (df[["m2"]][i] == 0 & df[["m3"]][i] == 0) { : 
  missing value where TRUE/FALSE need

Я попробовал тот же метод для Python, и он работает.Есть ли способ сделать это в R, и я должен рассчитать возврат без использования цикла for?

Ответы [ 4 ]

0 голосов
/ 24 января 2019

На самом деле ваша логика утверждает, что вы хотите изменить:

NaN to -9999 (occurs for 0/0)
Inf to 9999 (occurs for x/0)

Таким образом, вы можете просто применить свою формулу, а затем заменить позже.Мне кажется, что на меня это не так уж и сложно.Я избегаю логики «если-тогда», когда это возможно.

base R решение:

df$return <- (df$m2 - df$m3) / df$m3
df[is.nan(df$return),"return"] <- -9999
df[is.infinite(df$return),"return"] <- 9999

dplyr решение:

library(dplyr)

df %>%
  mutate(return = (m2 - m3) / m3,
         return = if_else(is.nan(return), -9999, return),
         return = if_else(is.infinite(return), 9999, return))
0 голосов
/ 24 января 2019
m2 <- c(22,NA,0,NA,42,NA)
m3 <- c(89,38,0,67,0,NA)
df = data.frame(m2,m3)


library(tidyverse)

df %>%  mutate( return = ifelse(is.na(df$m2)|is.na(df$m3), NA, ifelse(df$m2 == 0 & df$m3 == 0, 9999, ifelse(df$m3 == 0 & df$m2 != 0, -9999, (df$m2 - df$m3)/df$m3))) )
0 голосов
/ 24 января 2019

Я бы нарушил эти два шага:

m2 <- c(22,NA,0,NA,42,NA)
m3 <- c(89,38,0,67,0,NA)
df = data.frame(m2,m3)


df$return <- with(df, (m2 - m3)/m3)
df$return <- with(df, ifelse(m2 == 0 & m3 == 0, -9999, ifelse(m2 != 0 & m3 == 0, 9999, return)))

Создан в 2019-01-24 пакетом Представить (v0.2.1)

Здесь следует отметить 1) использование ifelse(), поскольку оно векторизовано (то есть будет работать со всеми строками df естественным образом, избегая необходимости кодировать цикл for, и 2) R, естественно, выдаст NA if m2 или m3 равны NA, так что вы можете просто прописать условия, когда return должно равняться 9999 или -9999.

0 голосов
/ 24 января 2019

Если вы хотите удобочитаемость, case_when из dplyr может быть вариантом:

library(dplyr)

df %>%
  mutate(
    result = case_when(
      is.na(m2) | is.na(m3) ~ NA_real_,
      m2 == 0 & m3 == 0 ~ 9999,
      m2 != 0 & m3 == 0 ~ -9999,
      TRUE ~ (m2 - m3) / m3
    )
  )

Как добавил @markus, вы действительно можете пропустить первую строку, чтобы получить тот же вывод.

Я бы также предложил прочитать справочную страницу ?case_when, чтобы ознакомиться с некоторыми особенностями (такими как актуальность заказа, пропуск TRUE, почему используется NA_real_ в приведенном выше случае и т. Д.).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...