【问题标题】:Ifelse in R with multiple categorical conditions具有多个分类条件的 R 中的 Ifelse
【发布时间】:2017-11-17 20:57:46
【问题描述】:

我有一个数据集,dt.train2,有 1500 个不同的观察值和 130 个变量。其中之一是languages,它可以是englishfrencharabic...

我想创建一个ifelse 字符串,它为english 提供属性1,为french 提供2,为spanish 提供属性3,为其他任何东西提供0。我不知道该怎么做。

dt.train2[, language_string := ifelse(language == "english", 
                                      1, 
                                      ifelse(language == "french", 
                                             2, 
                                             ifelse(language == "spanish",3)]

我正在使用它来运行关于销售的线性模型。

【问题讨论】:

  • 您只是缺少最后的 else 条件,language == "spanish",3, 0),您需要 , 0
  • 也就是说,这似乎是为线性模型做准备的糟糕方法,除非你真的认为无论有什么语言效应,法语效应是英语效应的两倍,西班牙语效应是三倍乘以英语效果。
  • 我会说做一张桌子并做一个更新加入stackoverflow.com/questions/42587214/…
  • 你完全正确!谢谢!

标签: r if-statement data.table conditional


【解决方案1】:

ifelse() 就快到了,您只需要最终的else 结果(以及一对缺少的右括号)。

dt.train2[, language_string := ifelse(
  language == "english", 1,
    ifelse(language == "french", 2,
      ifelse(language == "spanish", 3, 0)
    )
  )
]

您可以通过其他几种方式来做到这一点:

制作查找表并加入:

# sample data
dt = data.table(language = c("english", "french", "spanish", "arabic", "chinese", "pig latin"))


lookup = data.table(language = c("english", "french", "spanish"),
                    language_string = c(1, 2, 3))

dt2 = merge(dt, lookup, by = "language", all.x = TRUE)
dt2[is.na(language_string), language_string := 0]

上述查找表方法可能是可扩展性最好的方法。但是,对于如此少量的编码,您也可以只设置它们中的每一个:

# start with the default, 0
dt[, language_string := 0 ]
# then do each of the exceptions
dt[lanuage == "english", language_string := 1]
dt[language == "french", language_string := 2]
dt[language == "spanish", language_string := 3]

【讨论】:

  • 仅供参考,用于查找的一个习惯用法类似于dt[, v := 0][lookup, on=.(language), v := language_string],因此通过引用添加列而不是构建新表。
  • 完美,这就是我想要的!非常感谢
【解决方案2】:

我同意 cmets 的观点,如果这是针对线性模型,那么这是一个糟糕的方法。如果您坚持将语言作为预测变量,最好制作一系列虚拟变量。在这种情况下,您将添加 3 个预测变量(“english”、“french”、“arabic”),它们的值都为 0 或 1。

不管怎样,这是我的 dplyr 对这个问题的看法,它使用了CASE WHEN SQL 风格的语法并且更容易阅读。

require(tidyverse)
dt.train2 <- dt.train2 %>%
          mutate(language_string = case_when(language == "english" ~ 1,
                                             language == "french" ~ 2,
                                             language == "spanish" ~ 3,
                                             TRUE ~ 0))

【讨论】:

  • 你是对的。我对此真的很陌生。我会试试你的解决方案。非常感谢!
  • @Gregor 感谢您的关注。对于其他情况,我使用 TRUE ~ 0 的全部内容对其进行了编辑。
【解决方案3】:

检查一下:

 t <- 'es'
 tt <- (if (t == 'en') 1 else if (t == 'fr') {2} else if (t == 'es') 3 else 0)
 tt
 [1] 0

然后您可以将其应用于数据框:

df <- data.frame(l=c('en', 'fr', 'es', 'sthelse'))
df$lnum <- sapply(df$l, function(t){(if (t == 'en') 1 else if (t == 'fr') {2} else if (t == 'es') 3 else 0)})
df
        l lnum
1      en    1
2      fr    2
3      es    3
4 sthelse    0

【讨论】:

  • 可以交替写成(t=="en") + 2*(t=="fr") + 3*(t=="es"),这样它就被向量化了。
  • 有争议的downvoting(没有),但未矢量化的方式真的很糟糕,即使在几百行上它也会明显变慢。而unlist(lapply()) 过于复杂 - 如果您要这样做,只需使用sapply。但是矢量化ifelse()(或 Frank 的聪明矢量化解决方案)要好得多。
  • 你说的很对——把它改成 sapply。谢谢!
  • 或者只是c(en=1, fr=2, es=3)[t]
【解决方案4】:
language_options <- c("english", "french", "spanish", ...)
dt.train2[, language_string := match(language, language_options)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 2021-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多