首页 > 解决方案 > 使用 data.table 包,哪个将提供最快的用户时间?(R 编程)

问题描述

我在一次在线培训的测试中遇到了这个问题。我只是通过反复试验得到了它。很可能,我做错了什么,因为我是 R 编程的初学者。

这是问题:

问题图片

在阅读我的 R 代码之前,请注意,在最后一部分中,我必须将所有列转换为数字,因为没有它,我会收到以下消息:

“rowMeans(DT) 中的错误:‘x’必须是数字。”

在测试中,我教授的解决方案是:“ DT[,mean(pwgtp15), by=SEX]

使用我的 R 代码,正确答案是mean(DT$pwgtp15, by=DT$SEX)

我得到这个输出:

输出图像

我的疑问是,也许我的工作方式DT[,mean(pwgtp15), by=SEX]会产生缓慢的计算。

为此,我用

DT <- data.frame(data.matrix(DT))

哪一个是正确答案?教授解决方案?我的答案?另一个?

这是我的代码:

#THE SOLUTION IS DT[,mean(pwgtp15), by=SEX]
#HOWEVER, my solution is mean(DT$pwgtp15, by=DT$SEX)

install.packages("data.table")

library("data.table")

# the example below runs 100 times
download.file("https://d396qusza40orc.cloudfront.net/getdata%2Fdata%2Fss06pid.csv", destfile = "ACS.csv")

DT <- fread("ACS.csv", sep = ",")



counter<- 0
myName<-"DT[,mean(pwgtp15), by=SEX]"
for (i in 1:100)
{
  a<- Sys.time()  
  DT[,mean(pwgtp15), by=SEX]
  b<-Sys.time()
  myTime<-b-a
  counter<- counter + myTime
}
cat("counter is: ", counter, "myName is: ", myName, "\n")



counter<- 0
myName<-"mean(DT[DT$SEX==1,]$pwgtp15);mean(DT[DT$SEX==2,]$pwgtp15)"
for (i in 1:100)
{
  a<- Sys.time()  
  mean(DT[DT$SEX==1,]$pwgtp15); mean(DT[DT$SEX==2,]$pwgtp15)
  b<-Sys.time()
  myTime<-b-a
  counter<- counter + myTime
}
cat("counter is: ", counter, "myName is: ", myName, "\n")



counter<- 0
myName<-"sapply(split(DT$pwgtp15,DT$SEX),mean)"
for (i in 1:100)
{
  a<- Sys.time()  
  sapply(split(DT$pwgtp15,DT$SEX),mean)
  b<-Sys.time()
  myTime<-b-a
  counter<- counter + myTime
}
cat("counter is: ", counter, "myName is: ", myName, "\n")



counter<- 0
myName<-"tapply(DT$pwgtp15, DT$SEX, mean)"
for (i in 1:100)
{
  a<- Sys.time()  
  tapply(DT$pwgtp15, DT$SEX, mean)
  b<-Sys.time()
  myTime<-b-a
  counter<- counter + myTime
}
cat("counter is: ", counter, "myName is: ", myName, "\n")



counter<- 0
myName<-"mean(DT$pwgtp15, by=DT$SEX)"
for (i in 1:100)
{
  a<- Sys.time()  
  mean(DT$pwgtp15, by=DT$SEX)
  b<-Sys.time()
  myTime<- b-a
  counter<- counter + myTime
}
cat("counter is: ", counter, "myName is: ", myName, "\n")



#We convert the entire DATAFRAME to numeric
#Otherwise rowmeans will not work
DT <- data.frame(data.matrix(DT))


counter<- 0
myName<-"rowMeans(DT)[DT$SEX==1];rowMeans(DT)[DT$SEX==2]"

for (i in 1:100)
{
  a<- Sys.time()  
  rowMeans(DT)[DT$SEX==1];rowMeans(DT)[DT$SEX==2]
  b<-Sys.time()
  myTime<- b-a
  counter<- counter + myTime
}
cat("counter is: ", counter, "myName is: ", myName, "\n")

标签: r

解决方案


如前所述,问题的答案选择不会产生相同的结果。by to没有命名参数base::mean()。由于该函数允许向其他方法传递或从其他方法传递更多参数,因此它不会通过参数出错。因此,由于它不会按 等因素进行拆分/子集DT$SEX,因此这将是最快的时间。

此外,其他方法返回较慢的时间是有原因的:

  • tapply(...), sapply(split(...)),rowMeans(...)

    所有都是直接或间接应用的家庭成员,它们是隐藏循环而不是完全矢量化的计算。此外,rowMeans它是一个包装器,apply并且被调用了两次。另外,apply众所周知,将整个数据框/表转换为矩阵,我们应该注意@DavidArenburg 的警告

    如果您正在使用data.frames,请忘记有一个名为的函数apply——无论你做什么——都不要使用它。尤其是边距为 1(此函数唯一好的用例是在列上操作matrix- 边距为 2)。

  • mean(...); mean(...)

    这对子集数据帧进行了两次调用。逻辑索引[返回数据框的所有列,然后$选择最终的数字列mean()

    事实上,如果你运行向量子集而不是返回所有列的数据框子集,它会更快,也许是最快的:

    mean(DT$pwgtp15[DT$SEX==1]);mean(DT$pwgtp15[DT$SEX==2])
    
    a <- Sys.time() 
    DT[,mean(pwgtp15), by=SEX]
    b <- Sys.time() 
    myTime <- b-a
    myTime
    # Time difference of 0.01888704 secs
    # Time difference of 0.03294992 secs
    # Time difference of 0.03321409 secs
    
    a <- Sys.time() 
    mean(DT$pwgtp15[DT$SEX==1]);mean(DT$pwgtp15[DT$SEX==2])
    b <- Sys.time() 
    myTime <- b-a
    myTime
    # Time difference of 0.006003857 secs
    # Time difference of 0 secs
    # Time difference of 0 secs
    

推荐阅读