迭代查找子集的最小值-(数百万次)

时间:2019-01-28 15:49:28

标签: r performance subset min

我正在寻找一种更快,更高效的方式来执行我当前正在执行的“操作”(尽管速度很慢)。 我有一个包含500万个观测值和10个特征(变量)的数据表。此操作感兴趣的变量为三个:Price,date_initial,date_final。

这是我需要做的: 对于每个观察,我需要查看表并确定该观察是否具有与其他所有具有相同观察值的最低价格 date_initial和相同的date_final。 因此,基本上,对于每一行,我需要查看日期中的适当子集并确定最低价格,并检查当前观察值是否等于该最低价格。

这里是一个示例:(结果标志是我尝试生成的结果) 在此处输入图片说明

Price   date_initial    date_final   Result_Flag
45      2018-01-01      2018-01-10   No
40      2018-01-01      2018-01-07   Yes
48      2018-01-01      2018-01-10   No
49      2018-01-01      2018-01-10   No
42      2018-01-01      2018-01-10   Yes
69      2018-01-01      2018-01-07   No

如您所见,第二个观测值是“是”,因为它具有date_initial == 2018-01-01和date_final == 2018-01-07的所有观测值中最低的价格。 再次,我正在寻找一种高效且快速的方法。我当前的方法有效,但是非常慢。我正在使用apply和ifelse语句。我也在使用数据表。任何帮助,将不胜感激。 谢谢!

3 个答案:

答案 0 :(得分:3)

这是一个快速的解决方案:

dt[, res := ifelse(Price == min(Price), 'yes', 'no'),  by = .(date_initial, date_final)]
dt
#    Price date_initial date_final Result_Flag res
# 1:    45   2018-01-01 2018-01-10          No  no
# 2:    40   2018-01-01 2018-01-07         Yes yes
# 3:    48   2018-01-01 2018-01-10          No  no
# 4:    49   2018-01-01 2018-01-10          No  no
# 5:    42   2018-01-01 2018-01-10         Yes yes
# 6:    69   2018-01-01 2018-01-07          No  no

使用此数据:

dt = fread("Price   date_initial    date_final   Result_Flag
45      2018-01-01      2018-01-10   No
40      2018-01-01      2018-01-07   Yes
48      2018-01-01      2018-01-10   No
49      2018-01-01      2018-01-10   No
42      2018-01-01      2018-01-10   Yes
69      2018-01-01      2018-01-07   No"
)

答案 1 :(得分:1)

使用base r,您可以这样做:

transform(df,Result_Flag = factor(Price==ave(Price,date_initial,date_final,FUN=min),,c('No','Yes')))
  Price date_initial date_final Result_Flag
1    45   2018-01-01 2018-01-10          No
2    40   2018-01-01 2018-01-07         Yes
3    48   2018-01-01 2018-01-10          No
4    49   2018-01-01 2018-01-10          No
5    42   2018-01-01 2018-01-10         Yes
6    69   2018-01-01 2018-01-07          No

您可以使用ifelse代替该因素。您也可以这样做:

 library(tidyverse)
 df%>%
    group_by(date_initial,date_final)%>%
    mutate(Result_Flag=factor(Price==min(Price),label=c('No','Yes')))
# A tibble: 6 x 4
# Groups:   date_initial, date_final [2]
  Price date_initial date_final Result_Flag
  <int> <fct>        <fct>      <fct>      
1    45 2018-01-01   2018-01-10 No         
2    40 2018-01-01   2018-01-07 Yes        
3    48 2018-01-01   2018-01-10 No         
4    49 2018-01-01   2018-01-10 No         
5    42 2018-01-01   2018-01-10 Yes        
6    69 2018-01-01   2018-01-07 No         

答案 2 :(得分:0)

不确定这是否比您的功能快,但请尝试:)

testdata = matrix(c(
45,      "2018-01-01",      "2018-01-10",   
40,      "2018-01-01",      "2018-01-07",   
48,      "2018-01-01",      "2018-01-10",   
49,      "2018-01-01",      "2018-01-10",   
42,      "2018-01-01",      "2018-01-10",   
69,      "2018-01-01",      "2018-01-07"), ncol = 3, byrow = T)   

testdata[,1] = as.numeric(testdata[,1])

testdata = data.table(testdata)
names(testdata) = c("price", "date_i", "date_f")

# create a table with min values for all date_i date_f combinations
lowest = testdata[,list(min = min(price)), list(date_i, date_f)]

# attach the min-values to your dataframe by date_i and date_f
# there might be a faster data.table merge function
testdata = merge(testdata, lowest, by = c("date_i", "date_f"), all.x = T)

# if price is bigger than min write No to result, else yes
testdata$result = ifelse(testdata$price > testdata$min, "No", "Yes")