我习惯使用Python和JS,对R来说很新,但是喜欢它用于数据分析。我希望在我的数据框架中创建一个基于if / else逻辑的新字段,并尝试以标准/程序方式进行:
for (i in 1:nrow(df)) {
if (is.na(df$First_Payment_date[i]) == TRUE) {
df$User_status[i] = "User never paid"
} else if (df$Payment_Date[i] >= df$First_Payment_date[i]) {
df$User_status[i] = "Paying user"
} else if (df$Payment_Date[i] < df$First_Payment_date[i]) {
df$User_status[i] = "Attempt before first payment"
} else {
df$User_status[i] = "Error"
}
}
但这很疯狂。我尝试在大约300万行的数据框架上运行它,并且它花了太长时间。有关“R”方式的任何提示吗?
请注意,df$Payment_Date
和df$First_Payment_date
字段的格式为日期。
答案 0 :(得分:2)
如果您初始化为&#34;错误&#34;然后覆盖使用逻辑索引枚举的条件,这应该快得多。每行的if(){} else {}语句都会杀了你。
df$User_status <- "Error"
df$User_status[ is.na(df$First_Payment_date) ] <- "User never paid"
df$User_status[ df$Payment_Date >= df$First_Payment_date ] <- "Paying user"
df$User_status[ df$Payment_Date < df$First_Payment_date ] <- "Attempt before first payment"
答案 1 :(得分:1)
我正在针对相对较大的数据集对data.frame
和data.table
进行基准测试。
首先我们生成一些数据。
set.seed(1234)
library(data.table)
df = data.frame(First_Payment_date=c(sample(c(NA,1:100),1000000, replace=1)),
Payment_Date=c(sample(1:100,1000000, replace=1)))
dt = data.table(df)
然后设置基准。我在@ BondedDust的答案和它的data.table
等价之间进行测试。我稍微修改了(调试)他的代码。
library(microbenchmark)
test_df = function(){
df$User_status <- "Error"
df$User_status[ is.na(df$First_Payment_date) ] <- "User never paid"
df$User_status[ df$Payment_Date >= df$First_Payment_date ] <- "Paying user"
df$User_status[ df$Payment_Date < df$First_Payment_date ] <- "Attempt before first payment"
}
test_dt = function(){
dt[, User_status := "Error"]
dt[is.na(First_Payment_date), User_status := "User never paid"]
dt[Payment_Date >= First_Payment_date, User_status := "Paying user"]
dt[Payment_Date < First_Payment_date, User_status := "Attempt before first payment"]
}
microbenchmark(test_df(), test_dt(), times=10)
结果:data.table
生成的100万行数据比data.frame
快4倍。
> microbenchmark(test_df(), test_dt(), times=10)
Unit: milliseconds
expr min lq median uq max neval
test_df() 247.29182 256.69067 287.89768 319.34873 330.33915 10
test_dt() 66.74265 69.42574 70.27826 72.93969 80.89847 10
注意强>
对于小型数据集, data.frame
比data.table
快(例如10000行。)
答案 2 :(得分:0)
我不确定这会加速它,但你应该看到比以前的for
循环有所改善。在这些条件下,else
并不是必需的。
此外,R具有充当for
循环的函数和其他类型的循环。见?apply
。
给它一个镜头,看看它是如何工作的。我无法测试,因为我们没有您的数据。
> df$User_status[i] <- rep("Error", nrow(df))
## allocate a vector, fill it with "Error"
> sapply(seq(nrow(df)), function(i){
if(is.na(df$First_Payment_date[i])){
gsub("Error", "User never paid", df$User_status[i]) }
if(df$Payment_Date[i] >= df$First_Payment_date[i]){
gsub("Error", "Paying user", df$User_status[i]) }
if (df$Payment_Date[i] < df$First_Payment_date[i]) {
gsub("Error", "Attempt before first payment", df$User_status[i]) }
})
答案 3 :(得分:0)
处理此类事情的常用方法是通过ifelse
。
df$User_status <- with(df,
ifelse(is.na(First_Payment_date), "User never paid",
ifelse(Payment_Date >= First_Payment_date, "Paying user",
ifelse(Payment_Date < First_Payment_date, "Attempt before first payment",
"Error"))))