具有多种条件的计算

时间:2019-01-24 11:38:43

标签: r dataframe dplyr

嗨,我在R中有这个数据框:

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

我想计算m3和m2之间的收益。公式为: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 :(得分:3)

如果您想提高可读性,可以选择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_,等)。

答案 1 :(得分:2)

我将打破这两个步骤:

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)))

reprex package(v0.2.1)于2019-01-24创建

这里要注意的事情包括:1)使用ifelse(),因为它是矢量化的(即将自然地对df的所有行进行操作,而不必编写for循环代码; 2)R自然会产生{{1 }}如果NAm2m3,那么您只需说明NA等于return9999的条件。

答案 2 :(得分:1)

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))) )

答案 3 :(得分:1)

您的逻辑真正要说明的是您要更改:

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

因此您可以简单地应用公式,然后替换。对我来说,看起来似乎有些困惑。我会尽可能避免使用“ if-then”逻辑。

基本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))