[英]Vectorizing with lapply instead of using For loop
我試圖擺脫R中的循環,並尋求矢量化和加速我的代碼部分。
可重現的示例:
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
我在這里(lapply) , 這里(lapply)和這里($運算符)找到了相關問題,但沒有一個問題真正對我有幫助。
這是我嘗試使用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循環相同的輸出,我將不勝感激。
謝謝!
所以lapply
在這里並沒有被完全使用,僅此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)
}
其余的我朋友,就和您擁有的一樣:)
我不知道lapply
是采取正確的方法。 我堅持使用mutate
您似乎已經在使用它:
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
由reprex軟件包 (v0.2.0)於2018-06-27創建。
這確實假定觀察結果(至少在“項目”組中)是按順序排列的。 如果不是,請在group_by
之后添加arrange(Date) %>%
您可以創建一個具有最新值的表,與原始表連接並獲得差異或使用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)]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.