【问题标题】:Why is R script running slower on Windows Server 2008 than OSX 10.6?为什么 R 脚本在 Windows Server 2008 上的运行速度比 OSX 10.6 慢?
【发布时间】:2014-02-24 02:53:29
【问题描述】:

我已将一些脚本从运行 OS X 10.6.8、4GB Ram 和 2.53GHz Core 2 Duo 处理器(大约 2008 年)的旧 iMac 迁移到运行 Windows Server 2008、64 位的新虚拟 AWS 机器配备 15GB 内存。尽管如此,以下代码在新的 Windows 机器上运行的时间是原来的 4 倍。

我已经更改了一些周围的代码,但这部分是瓶颈,是相同的。输入变量(unique_datessummary_datain_data)在两台机器之间也具有相似的大小。

在 Windows 机器上,每个 date 循环大约需要 30 秒,而之前在 Mac 上需要 5 秒。

任何关于如何加快速度的建议将不胜感激。

* 更新 *

从正在制作的 cmets 中,我得到的印象是,有一种更快的方法可以做到这一点,而无需我将原始问题呈现为有争议的循环。

我正在努力实现以下目标: 我有许多公司的时间序列数据。对于每个日期,每家公司都有第 1 个月、第 3 个月、第 6 个月、第 12 个月、第 18 个月和第 24 个月的回报。每个公司也被分配到一个组(分位数)。对于每个日期,我想计算每个分位数的平均和中位数 1mth、3mth、6mth 等回报。

然后将结果存储在预先分配的summary_data 数据帧中。

实际数据有 343 个日期,每个日期有 500 家公司,分位数有 25 家公司。最慢的部分是ss_in_data <- subset(in_data, ...),而其余部分总共大约需要 0.02 秒。

我对 R 还很陌生,但在 MYSQL 中,我可以很简单地使用 MEANGROUP BY DATE, FRACTILE 来计算。在 R 中有类似的方法吗?

再次感谢大家的帮助。

我当前的代码在示例数据下方:

# In this sample data there are 12 companies, 3 dates. Each company is 
# assigned to 1 of 3 fractiles
# Consequently there are 4 companies in each fractile.

# Create input data
date1 <- as.Date(as.character('2010-01-31'),"%Y-%m-%d")
date2 <- as.Date(as.character('2010-02-28'),"%Y-%m-%d")
date3 <- as.Date(as.character('2010-03-31'),"%Y-%m-%d")

dates <- c(rep(date1,12),rep(date2,12),rep(date3,12))

coys <- rep(c('A','B','C','D','E','F','G','H','I','J','K','L'),3)
ret_3mth <- rep(seq(0.1, by=0.2, length.out = 12),3)
ret_6mth <- rep(seq(0.2, by=0.2, length.out = 12),3)
ret_12mth <- rep(seq(0.3, by=0.2, length.out = 12),3)
fractiles <- rep(rep(c(1,2,3),4),3)

in_data <- data.frame(dates, coys, ret_3mth, ret_6mth, ret_12mth, fractiles)

# Initialise summary data frame
dates <- c(rep(date1,3),rep(date2,3),rep(date3,3))
fractiles <- rep(c(1,2,3),3)
mean_3mth <- rep(NA,9)
mean_6mth <- rep(NA,9)
mean_12mth <- rep(NA,9)
summary <- data.frame(dates, fractiles, mean_3mth, mean_6mth, mean_12mth)

# Other variables
unique_dates <- unique(dates)
num_fract_curr <- 3

当前方法:

for (date in unique_dates) {
      # Only write to screen ever x loops (as set by write_line_freq)
      if (counter%%write_line_freq == 0) {
        writeLines(paste(run_name,' : Summary calcs ROCE ',roce, '  Date: ',as.Date(date, origin='1970-01-01'),
                         ' ',counter,':',num_dates,'  Time: ',format.timediff(start_time),sep=''))
      }
      counter <- counter + 1


  for(i in 1:num_fract_curr) {
    # Create subsets to speed up processing

    ss_summary_data <- subset(summary_data, date_base == as.Date(date, origin='1970-01-01') & summary_data[summary_data_fractile] == i)
    ss_in_data <- subset(in_data, date_base == as.Date(date, origin='1970-01-01') & in_data[in_data_fractile] == i)


    # Causes error if ss_in_data is empty
    if (nrow(ss_in_data) > 0) {
      ss_summary_data$mean1mth <- mean(ss_in_data$ret_1mth, na.rm = TRUE)
      ss_summary_data$median1mth <- median(ss_in_data$ret_1mth, na.rm = TRUE)

      ss_summary_data$mean3mth <- mean(ss_in_data$ret_3mth, na.rm = TRUE)
      ss_summary_data$median3mth <- median(ss_in_data$ret_3mth, na.rm = TRUE)

      ss_summary_data$mean6mth <- mean(ss_in_data$ret_6mth, na.rm = TRUE)
      ss_summary_data$median6mth <- median(ss_in_data$ret_6mth, na.rm = TRUE)

      ss_summary_data$mean12mth <- mean(ss_in_data$ret_12mth, na.rm = TRUE)
      ss_summary_data$median12mth <- median(ss_in_data$ret_12mth, na.rm = TRUE)

      ss_summary_data$mean18mth <- mean(ss_in_data$ret_18mth, na.rm = TRUE)
      ss_summary_data$median18mth <- median(ss_in_data$ret_18mth, na.rm = TRUE)

      ss_summary_data$mean24mth <- mean(ss_in_data$ret_24mth, na.rm = TRUE)
      ss_summary_data$median24mth <- median(ss_in_data$ret_24mth, na.rm = TRUE)

      # Save the updated summary data back into the 'summary_data' data frame
      summary_data[(summary_data$date == date) & (summary_data[summary_data_fractile] == i),] <- ss_summary_data
    }
  }
}

【问题讨论】:

  • 我假设您将ss_summary_data 预分配到正确的大小?如果没有,这是一个明显的改进,将速度提高几个数量级。
  • @PaulHiemstra 不,我根本没有预先分配ss_summary_data。作为data.frame,我没有意识到你应该甚至可以这样做。第一次引用或定义它是在您看到的代码中。与ss_in_data 相同,在此代码中定义。他们都应该预先分配吗?不过它们并不大,最多 50 行。
  • 好的,最多 50 行听起来不会造成瓶颈。在 R 中,按顺序增长一个对象是出了名的慢,但当然只用于构建一个有 50 行的更大的对象。
  • 没有按顺序构建。 ss_summary_data 在每个循环中被重新创建/覆盖为summary_data 的子集,然后写回到已经创建的summary_data,因此它的大小不会改变。
  • 从代码中很难准确地理解你要在那里做什么,但如果我没有错过什么,你不应该需要for 循环。看起来您正在尝试重新发明“拆分-应用-组合”方法。查看包 plyr、dplyr 或 data.table。

标签: windows r performance macos


【解决方案1】:

我没有深入了解速度差异,但这是在 R 中执行此计算的荒谬方法。

按照@Roland 的建议改用ddply

计算时间从 12 小时减少到几秒钟。

感谢大家的帮助。

新方法:

 summary_data <- ddply(in_data, c('date_base',fractile_name),summarise, mean_1mth = mean(ret_1mth, na.rm=TRUE), 
                                          mean_3mth = mean(ret_3mth, na.rm=TRUE),mean_6mth = mean(ret_6mth, na.rm=TRUE),
                                          mean_12mth = mean(ret_12mth, na.rm=TRUE), mean_18mth = mean(ret_18mth, na.rm=TRUE),
                                          mean_24mth = mean(ret_24mth, na.rm=TRUE),
                                          median_1mth = median(ret_1mth, na.rm=TRUE), median_3mth = median(ret_3mth, na.rm=TRUE),
                                          median_6mth = median(ret_6mth, na.rm=TRUE), median_12mth = median(ret_12mth, na.rm=TRUE), 
                                          median_18mth = median(ret_18mth, na.rm=TRUE),median_24mth = median(ret_24mth, na.rm=TRUE))

【讨论】:

    猜你喜欢
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-23
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    • 2016-08-02
    相关资源
    最近更新 更多