【问题标题】:R efficiency iterating through dataframes遍历数据框的 R 效率
【发布时间】:2018-04-15 23:06:22
【问题描述】:

我正在处理一个大型数据集,我们将其命名为 data,并且想要创建一个新列,我们根据某个列 data$input 将其命名为 data$results。结果基于一些条件 if/then 逻辑,所以我原来的方法是这样的:

for (rows in data) {
    data$results <- if(data$results == "1" | data$results== "2") {
        trueAnswer
    } else {
        falseAnswer
    }
}

对于大型数据帧,此过程可能需要几个小时才能运行。但是,如果我将数据子集到仅包含 data$results 为 1 或 2 的条目和另一个不正确的条目的数据帧中,我可以将 trueAnswer 应用于一个数据帧,将 falseAnswer 应用于另一个数据帧。然后我可以将数据帧重新绑定在一起。这种方法只需要几分钟。

为什么后一种方法使用子集的速度要快得多?这是一个将此过程应用于许多不同数据集的情况,因此前一种方法太慢而无法实用。我只是想了解导致第一种方法效率低下的原因。

【问题讨论】:

  • c(falseAnswer, trueAnswer)[(data$results %in% 1:2) + 1L]

标签: r dataframe tidyverse


【解决方案1】:

R 效率是围绕向量设计的,而不是循环。 for 或 while 循环是解决问题的最佳方法是非常罕见的(尽管确实会发生)。在您的情况下,您最好使用 if/else: ifelse 的矢量化版本。它需要一个测试向量(例如result %in% 1:2)和两个可能响应的向量,具体取决于测试结果。所有这些都必须是相同的长度。当您给出长度为 1 的答案时,它会将其扩展到适当的长度,否则会出错。在这里,它看起来像这样:

data$results <- ifelse(results %in% 1:2, trueAnswer, falseAnswer)

【讨论】:

  • 太好了,谢谢。你和毛里茨基本上说了同样的话。我不太明白的一点是为什么 ifelse 被认为是矢量化操作。假设 ifelse 将不得不逐行进行逻辑比较,那么它与我显式循环遍历我自己的数据有什么不同?
  • 查看alyssafrazee.com/2014/01/29/vectorization.html - 第一个似乎可以解决这个问题的谷歌链接。这是一个很好的问题,但是(到目前为止)我只知道这样做,而不是为什么
  • @niccalis 看看?ifelse;它解释说它返回一个与逻辑测试条件长度相同的 vector。所以换句话说,如果你测试 100 个条件,它将返回一个长度为 100 的向量。因此“向量化”。
  • 好的,答案(来自那个网站)原来是我应该能够自己回答的。 R 是一种解释型语言,不是编译型的。矢量化函数使用以编译语言实现的循环,因此它们要快得多。
  • @niccalis 我在下面的回答中添加了一些关于ifelse 的矢量化性质的进一步解释。
【解决方案2】:

始终建议提供fully reproducible & minimal example with sample data。这样我们就可以根据您的样本数据提供具体的帮助。

在很多情况下,可以在 R 中避免显式的for 循环,而我们可以使用优化的向量化操作。例如ifelse 就是这样一个矢量化函数。

一般dplyr 语法是这样的:

library(dplyr);
library(magrittr);
data %>%
    mutate(results = ifelse(input == 1 | input == 2, "1 or 2", "Neither 1 nor 2"))

更新

要了解ifelse 是如何矢量化的,请查看?ifelse

价值:

相同长度和属性的向量(包括维度 和“类”)作为“测试”和来自“是”值的数据值 或没有'。 [...]

换句话说,如果ifelse 评估了 100 个条件,则返回对象的长度为 100。

这可能会导致以下可能令人惊讶/意外的结果:

ifelse(c(TRUE), c(100, 200), c(300, 400))
#[1] 100

返回对象是 c(100, 200) 的元素 1,因为逻辑条件的长度为 1。

ifelse(c(TRUE, TRUE, TRUE), c(100, 200), c(300, 400))
#[1] 100 200 100

返回对象的长度为3,因为逻辑条件的长度为3;由于c(100, 200)只有两个元素,R需要回收条目。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 2018-09-28
    • 2018-05-26
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 2021-02-17
    相关资源
    最近更新 更多