首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我如何编写这个工作代码来提高性能?

我如何编写这个工作代码来提高性能?
EN

Stack Overflow用户
提问于 2019-07-09 15:46:36
回答 3查看 85关注 0票数 3

我有一个更大的数据集(25K记录)来设置这个样本。我注意到我的应用程序的代码在这件事情上变慢了,我想检查一下性能的提高。

背景:我的财政年度从七月开始,到六月结束。因此,我的记录有一个与一个月和一个历年不同的财政期间和财政年度。我想要添加额外的列,指示日历年和月。

金融周期:2018年7月7日(2017年7月)

金融周期: 07 2018年是2018年(2018年1月),等等。

可复制的例子:

代码语言:javascript
复制
dt<-data.table(FinancialPeriod =c(3,4,4,5,1,2,8,8,11,12,2,3,10,1,6), FinancialYear=c(2018), Amount=c(12,14,16,18,12))
dt$Month<-dt$FinancialPeriod + 6
dt$Year<-dt$FinancialYear
t1<-proc.time()
for(row in 1:nrow(dt)){
  if (dt[row,"Month"] > 12){
    dt[row,"Month"]<- dt[row,"Month"] -12
  } 
  else {
    dt[row,"Year"]<- dt[row,"Year"] -1
  }
}
proc.time()-t1
dt

上面的代码可以工作,但工作缓慢。我想就如何改进提出建议。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-07-10 00:40:47

另一种选择:

代码语言:javascript
复制
i <- DT1[Month > 12L, which=TRUE]
DT1[i, Month := Month - 12L][-i, Year := Year - 1L]

请注意,在可更新的github站点上正在开发一个fifelse

使用实际dim的计时:

代码语言:javascript
复制
# A tibble: 4 x 14
  expression      min     mean   median      max `itr/sec` mem_alloc  n_gc n_itr total_time result                  memory                 time    gc              
  <chr>      <bch:tm> <bch:tm> <bch:tm> <bch:tm>     <dbl> <bch:byt> <dbl> <int>   <bch:tm> <list>                  <list>                 <list>  <list>          
1 for_loop      1.92s    1.92s    1.92s    1.92s     0.521    4.66GB   110     1      1.92s <NULL>                  <Rprofmem [25,175 x 3~ <bch:t~ <tibble [1 x 3]>
2 mtd0         1.45ms   2.26ms    1.7ms   7.49ms   442.       6.55MB    31   221   500.02ms <data.table [25,000 x ~ <Rprofmem [67 x 3]>    <bch:t~ <tibble [221 x ~
3 mtd1       498.46us 650.79us  566.1us   2.98ms  1537.     699.56KB     6   768   499.81ms <data.table [25,000 x ~ <Rprofmem [24 x 3]>    <bch:t~ <tibble [768 x ~
4 basemtd    950.97us   1.41ms   1.02ms  50.65ms   709.       5.06MB    41   355   500.45ms <dbl [25,000]>          <Rprofmem [52 x 3]>    <bch:t~ <tibble [355 x ~

对于25k行数据,基数R已经非常快了。

数据:

代码语言:javascript
复制
set.seed(0L)
DT <- data.table(FinancialPeriod=sample(12L, 25e3L, TRUE), 
    FinancialYear=c(2018))
DT[, c("Month","Year") := .(FinancialPeriod + 6L, FinancialYear)]
DT0 <- copy(DT)
DT1 <- copy(DT)
DF <- setDF(copy(DT))

计时码:

代码语言:javascript
复制
bench::mark(
    for_loop = {
        for(row in 1:nrow(DF)){
            if (DF[row,"Month"] > 12){
                DF[row,"Month"]<- DF[row,"Month"] -12
            } 
            else {
                DF[row,"Year"]<- DF[row,"Year"] -1
            }
        }
    },
    mtd0=DT0[, c("Month", "Year") := list(ifelse(Month > 12, Month-12, Month), 
        ifelse(Month <= 12, Year-1, Year))],
    mtd1={
        i <- DT1[Month > 12L, which=TRUE]
        DT1[i, Month := Month - 12L][-i, Year := Year - 1L]
    },
    basemtd={
        DF0$Month <- ifelse(DF0$Month > 12L, DF0$Month - 12L, DF0$Month)  
        DF0$Year <- ifelse(DF0$Month <= 12L, DF0$Year - 1L, DF0$Year)  
    },
    check=FALSE
)
票数 2
EN

Stack Overflow用户

发布于 2019-07-10 07:12:50

我的建议是使用一个完整的日期,例如一个财政期间的开始。因此,我们可以使用FinancialDate而不是FinancialPeriod-FinancialYear组合,例如OP的示例

金融周期-金融界: 01 2018

变成了

FinancialDate: 2018-01-01

这种方法有几个好处:

  1. 只有一个日期对象描述周期,而不是两个更容易处理的对象,例如,用于聚合。如果需要,可以很容易地从date对象中提取月份和年份。
  2. 我们可以利用通常的日期算法,例如lubridate包,将FinancialDate转换为CalendarDate
  3. 此外,绘图工作更好的日期对象。

以下是代码:

代码语言:javascript
复制
library(lubridate)
dt[, FinDate := make_date(FinancialYear, FinancialPeriod)]
dt[, CalDate := FinDate %m+% months(6)]   # convert to calendar date by adding offset
dt[, c("CalMonth", "CalYear") := list(month(CalDate), year(CalDate))]
dt

FinancialPeriod FinancialYear Amount Month Year FinDate CalDate CalMonth CalYear 1: 3 2018 12 9 2018 2018-03-01 2018-09-01 9 2018 2: 4 2018 14 10 2018 2018-04-01 2018-10-01 10 2018 3: 4 2018 16 10 2018 2018-04-01 2018-10-01 10 2018 4: 5 2018 18 11 2018 2018-05-01 2018-11-01 11 2018 5: 1 2018 12 7 2018 2018-01-01 2018-07-01 7 2018 6: 2 2018 12 8 2018 2018-02-01 2018-08-01 8 2018 7: 8 2018 14 14 2018 2018-08-01 2019-02-01 2 2019 8: 8 2018 16 14 2018 2018-08-01 2019-02-01 2 2019 9: 11 2018 18 17 2018 2018-11-01 2019-05-01 5 2019 10: 12 2018 12 18 2018 2018-12-01 2019-06-01 6 2019 11: 2 2018 12 8 2018 2018-02-01 2018-08-01 8 2018 12: 3 2018 14 9 2018 2018-03-01 2018-09-01 9 2018 13: 10 2018 16 16 2018 2018-10-01 2019-04-01 4 2019 14: 1 2018 18 7 2018 2018-01-01 2018-07-01 7 2018 15: 6 2018 12 12 2018 2018-06-01 2018-12-01 12 2018

票数 3
EN

Stack Overflow用户

发布于 2019-07-09 16:01:01

看起来您使用的是data.table,所以我使用了data.table语法。有几种解决方案,但有一种选择是使用ifelse

代码语言:javascript
复制
dt[, c("Month", "Year") := list(ifelse(Month > 12, Month-12, Month), ifelse(Month <= 12, Year-1, Year))]

或者,如果您想跳过创建初始变量MonthYear

代码语言:javascript
复制
dt[, c("Month", "Year") := list(ifelse(FinancialPeriod + 6 > 12, FinancialPeriod -6, FinancialPeriod + 6), 
                                ifelse(FinancialPeriod + 6 <= 12, FinancialYear-1, FinancialYear))]

基准测试

原始数据:

代码语言:javascript
复制
Unit: microseconds
     expr     min       lq      mean   median       uq     max neval
 for_loop 21183.8 21765.90 23600.586 22169.80 22981.15 73243.2   100
   ifelse   298.7   332.05   350.509   356.35   369.10   495.8   100

较大的数据集:

代码语言:javascript
复制
data.table(sapply(dt, rep, 100))
Unit: microseconds
     expr       min      lq       mean     median        uq       max neval
 for_loop 1645857.5 1655792 1690718.78 1696271.35 1704510.1 1746731.2    10
       o1     395.4     398     425.29     425.05     446.6     462.3    10

代码:

代码语言:javascript
复制
microbenchmark::microbenchmark(
  for_loop = {
    for(row in 1:nrow(dt)){
      if (dt[row,"Month"] > 12){
        dt[row,"Month"]<- dt[row,"Month"] -12
      } 
      else {
        dt[row,"Year"]<- dt[row,"Year"] -1
      }
    }
  },
  ifelse = {
    dt[, c("Month", "Year") := list(ifelse(Month > 12, Month-12, Month), ifelse(Month <= 12, Year-1, Year))]
  },
  times = 100
)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56956299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档