R效率迭代数据帧

时间:2018-04-15 23:06:23

标签: r dataframe tidyverse

我正在使用大型数据集,我们可以将其称为data,并希望创建新列,然后根据某些列data$results调用它data$input。结果基于一些条件if / then逻辑,所以我的原始方法类似于:

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

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

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

2 个答案:

答案 0 :(得分:0)

始终建议提供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

  

值:

     

具有相同长度和属性(包括尺寸)的矢量        和'“class”')作为'test'和来自'yes'值的数据值        或没有'。 [...]

换句话说,如果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需要回收条目。

答案 1 :(得分:0)

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

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