加速填充功能R.

时间:2017-05-31 21:39:21

标签: r performance function vectorization

我有一个缺少值的数据帧,我已经编写了一个使用R 3.3.2填充的函数

pkgs <- c("dplyr", "ggplot2", "tidyr", 'data.table', 'lazyeval')
lapply(pkgs, require, character.only = TRUE)

UID <- c('A', 'A', 'A', 'B', 'B', 'B', 'C', 'C')
Col1 <- c(1, 0, 0, 0, 1, 0, 0, 0)
df <- data.frame(UID, Col1)

填写Col1的功能:

AggregatedColumns <- function(DF, columnToUse, NewCol1) {
  # Setting up column names to use
  columnToUse <- deparse(substitute(columnToUse))
  NewCol1 <- deparse(substitute(NewCol1))

  # Creating new columns 
  DF[[NewCol1]] <- ifelse(DF[[columnToUse]] == 1, 1, NA)
  DF <- DF %>% group_by_("UID") %>% sort(DF[[columnToUse]], decreasing = TRUE) %>% fill_(NewCol1)
  DF <- DF %>% group_by_("UID") %>% sort(DF$columnToUse, decreasing = TRUE) %>% fill_(NewCol1, .direction = 'up')
  DF[[NewCol1]] <- ifelse(is.na(DF[[NewCol1]]), 0, DF[[NewCol1]])

  DF
}

我已经撤出了这部分功能,因为这是减慢功能的部分。我非常擅长编写函数,以及关于如何加速这些函数的任何建议。我已将速度问题分离到函数的fill_部分。

我要做的是将一个虚拟变量从Col1传递给New_Column,然后将前向填充传递给其他相同的ID。例如:

UID             Col1
John Smith        1
John Smith        0

应该成为

UID             Col1  New_Column
John Smith        1      1
John Smith        0      1

已编辑的功能 我编辑了函数以适应@HubertL的建议。该功能仍然相当慢,但希望通过这些编辑,该示例是可重现的。

AggregatedColumns <- function(DF, columnToUse, NewCol1) {
  # Setting up column names to use
  columnToUse <- deparse(substitute(columnToUse))
  NewCol1 <- deparse(substitute(NewCol1))

  # Creating new columns 
  DF[[NewCol1]] <- ifelse(DF[[columnToUse]] == 1, 1, NA)
    DF <- DF %>% group_by_("UID") %>% fill_(NewCol1) %>% fill_(NewCol1, .direction = 'up')
  DF[[NewCol1]] <- ifelse(is.na(DF[[NewCol1]]), 0, DF[[NewCol1]])

  DF
}

期望的输出:

UID Col1 New
A    1    1 
A    0    1
A    0    1 
B    0    1
B    1    1
B    0    1
C    0    0
C    0    0

2 个答案:

答案 0 :(得分:1)

如果速度是一个问题,您可以使用data.table包中的na.locf()zoo进行尝试。 LOCF 表示最后一次观察结转

library(data.table)
setDT(df)[Col1 != 0, New := Col1 ][, New := zoo::na.locf(New), UID][is.na(New), New := 0][]
#   UID Col1 New
#1:   A    1   1
#2:   A    0   1
#3:   A    0   1
#4:   B    0   1
#5:   B    1   1
#6:   B    0   1
#7:   C    0   0
#8:   C    0   0

这只是为了提出一个想法。它仍然需要包含在函数调用中。

它假定0中的值Col1被视为缺失。

答案 1 :(得分:1)

首先,这里有几点:

  1. 您不必要地致电<link rel="import" href="polymer/lib/utils/import-href.html"> (两次)while this function is very inefficient
  2. 当您只使用基础R简单地对流程进行矢量化时,您不必使用外部包中的低效函数(按组)(也是两次)。
  3. 这里是一个简单的单线程,不使用任何外部软件包,可以在5e7数据集上提高性能 x72 (对于更大的数据集可能更多)

    ifelse

    <强>基准

    AggregatedColumns2 <- function(DF, columnToUse, NewCol1) {
        # Setting up column names to use
        columnToUse <- deparse(substitute(columnToUse))
        NewCol1 <- deparse(substitute(NewCol1))
    
        # Creating the new column (one simple line)
        DF[[NewCol1]] <- as.integer(DF$UID %in% DF$UID[DF[[columnToUse]] == 1])
    
        # returning new data set back
        DF
    }
    

    现在为了比较那些我将重新排序并转换为矩阵,因为Hadleyverses包添加了大量不必要的属性(比较set.seed(123) library(stringi) N <- 5e7 UID <- stri_rand_strings(N, 2) Col1 <- sample(0:1, N, replace = TRUE) df <- data.frame(UID, Col1) system.time(res <- AggregatedColumns(df, Col1, NewCol1)) # user system elapsed # 198.67 3.94 203.07 system.time(res2 <- AggregatedColumns2(df, Col1, NewCol1)) # user system elapsed # 2.82 0.00 2.82 中创建的混乱与str(res)中的简单结构)< / p>

    str(res2)
相关问题