使用lapply进行矢量化,而不是使用For循环

时间:2018-06-27 05:09:25

标签: r for-loop vectorization lapply

我试图摆脱R中的循环,并希望矢量化和加速我的代码的一部分。

我希望使用lapply转换For循环,但出现错误: enter image description here

可复制的示例:

library(dplyr)

# This works using a For loop -----------------------------------

# create sample data frame
df <- data.frame(Date  = rep(c("Jan1", "Jan2", "Jan3"), 3),
                 Item  = c(rep("A", 3), rep("B", 3), rep("C", 3)),
                 Value = 10:18)


diff <- numeric() # initialize

# Loop through each item and take difference of latest value from earlier values
for (myitem in unique(df$Item)) {

    y = df[df$Date == last(df$Date) & df$Item == myitem, "Value"]  # Latest value for an item

    x = df[df$Item == myitem, "Value"]                             # Every value for an item

    diff <- c(diff, y-x)

}

df_final <- mutate(df, Difference = diff)
df_final

enter image description here

我发现了相关的问题here (lapply)here (lapply)here ($ operator),但是没有一个问题能真正帮助我。

这是我尝试使用lapply向量化的方法:

# Same thing using vectorized approach ----------------------------------

mylist <- list(unique(df$Item))

myfunction <- function(df = df, diff = numeric()) {

    y = df[df$Date == last(df$Date) & df$Item == mylist, "Value"]  # Latest value for an item

    x = df[df$Item == mylist, "Value"]                             # Every value for an item

    diff <- c(diff, y-x)

}

# throws error
diff_vector <- unlist(lapply(mylist, myfunction))

df_final2 <- mutate(df, Difference = diff_vector)
df_final2

我的真实数据集有数十万行。如果有人可以向我指出正确的方向,如何进行矢量化以获得与For循环相同的输出,我将不胜感激。

谢谢!

3 个答案:

答案 0 :(得分:5)

所以lapply并没有在这里被使用,仅此而已!

lapply将函数应用于列表的每个元素。明确地说,它接受列表的每个元素,并将函数应用于该元素。

因此,如果希望它将功能应用于数据框的多个子集,则需要为其获取一个列表,该列表是数据框的多个子集。因此,让我们首先创建该列表。

我们可以使用split函数执行此操作,它将基于一列的数据帧分为几个数据帧,并将它们存储为列表。数据帧的子集列表。完美!

因此,我们用此行替换创建mylist的行。

mylist <- split(df,df[,c("Item")])

现在,我们只需要对myfunction进行一些更改。记住,我们现在正在传递已经被子集化的数据,因此我们可以删除与Item匹配的条件。请记住,此功能将完全应用于所有这些数据帧。

myfunction <- function(df = df, diff = numeric()) { 
    y = df[df$Date == last(df$Date), "Value"]  # Latest value for an item

    x = df[, "Value"]                             # Every value for an item

    diff <- c(diff, y-x)
}

剩下的我的朋友,正是您所拥有的:)

答案 1 :(得分:1)

我不确定JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript("arguments[0].click();","Target Webelement"); 是采用的正确方法。我坚持使用lapply-您似乎已经在使用它:

mutate

reprex package(v0.2.0)于2018-06-27创建。

这确实假定观察结果(至少在“项目”组中)是按顺序排列的。如果不是,请在library(dplyr) #> #> Attaching package: 'dplyr' #> The following objects are masked from 'package:stats': #> #> filter, lag #> The following objects are masked from 'package:base': #> #> intersect, setdiff, setequal, union df <- data.frame(Date = rep(c("Jan1", "Jan2", "Jan3"), 3), Item = c(rep("A", 3), rep("B", 3), rep("C", 3)), Value = 10:18) df <- df %>% group_by(Item) %>% mutate(diff = last(Value) - Value) df #> # A tibble: 9 x 4 #> # Groups: Item [3] #> Date Item Value diff #> <fct> <fct> <int> <int> #> 1 Jan1 A 10 2 #> 2 Jan2 A 11 1 #> 3 Jan3 A 12 0 #> 4 Jan1 B 13 2 #> 5 Jan2 B 14 1 #> 6 Jan3 B 15 0 #> 7 Jan1 C 16 2 #> 8 Jan2 C 17 1 #> 9 Jan3 C 18 0

之后添加arrange(Date) %>%

答案 2 :(得分:1)

您可以创建一个具有最新值的表,与原始表连接并获得差异,或使用data.table创建一个具有最新值的附加列

library(data.table)
df <- data.frame(Date  = rep(c("Jan1", "Jan2", "Jan3"), 3),
                 Item  = c(rep("A", 3), rep("B", 3), rep("C", 3)),
                 Value = 10:18)

setDT(df)

df[,latestVal:=last(Value),by=.(Item)][,diff:=latestVal-Value][,.(Date,Item,Value,diff)]