【问题标题】:Filtering using a list of value in R with lapply() is too slow使用带有 lapply() 的 R 中的值列表进行过滤太慢了
【发布时间】:2020-01-30 04:52:58
【问题描述】:

我有一个独特的股票名称列表(大约 12,000 只股票)以及它们的“以前的最大收入”和一个相当大的数据框。数据框包含股票名称、收入、收入年份。例如:

AAPL | 2000 | 1,000
AAPL | 2001 | 1,200
AAPL | 2002 | 900
AMZN | 2000 | 300
AMZN | 2001 | 500
MSFT | 2000 | 600

我需要从大型数据框中查看某只股票在哪一年超过了其“之前的最大收入”。由于每家公司报告的收入年份不同,有的有 2000-2002 年的数据,有的有更多(2000-2005 年),有的有更少(2000-2001 年)。

我的方法是筛选股票名称。所以,我必须对每只股票都这样做。这就是为什么我使用 lapply() 但它太慢了。

下面是我要说的部分。

rec_year <- function(sym) {
  recovery_year <- (post_table %>% filter(tic==sym & ni > pre_max_table[pre_max_table$tic==sym]$ni))$fyear[1]
  return(recovery_year - pre_max_table[pre_max_table$tic==sym]$fyear)
}
YearsRecover <- unlist(lapply(tic_list,rec_year))

ni:净收入 tic:股票名称 fyear: 财政年度

pre_max_table 包含股票列表及其之前的最高收入。例如: 苹果 | 2001 | 1,200 亚马逊 | 2002 | 900 微软 | 2001 | 1000

post_table 包含新数据以检查 pre_max_table 中的先前最大值

函数rec_year()首先检查pre_max_table中之前的最大净收入。然后它检查股票名称sym 在哪一年超过了之前的最大值。如果它找到了一年,它会返回上一个最大收入的年份与sym 打破自己记录的年份之间的差值。 然后我使用lapply() 将此rec_year() 应用于tic_list 中的股票列表

我认为代码运行缓慢,因为它必须遍历许多 tic 名称 (12k)。每次它必须重新运行 rec_year() 函数。

如果有人能提出更好/更快的方法来解决这个问题,我们将不胜感激。

【问题讨论】:

  • 您能否编辑您的问题以用文字表达代码的用途?
  • 另外,pre_max_table 中有什么内容?请分享一个样本。我怀疑有一种方法可以通过加入更快地做到这一点,但不确定你在做什么。
  • 嗨,我添加了解释。很抱歉有歧义。
  • 您是否已经拥有pre_max_table 或者您计算过?我想你可以在没有那张桌子的情况下做到这一点。当前共享数据的预期输出是什么?
  • 哦,我已经有了那个 pre_max_table。基本上我需要使用 post_table 计算每家公司需要多少年才能超过以前的最大值。

标签: r optimization apply lapply


【解决方案1】:

因为pre_max_table 似乎是data.table,所以第一步我会setkey(pre_max_table, tic),这样

  recovery_year <- (post_table %>% filter(tic==sym & ni > pre_max_table[pre_max_table$tic==sym]$ni))$fyear[1]

可以修改为

  recovery_year <- (post_table %>% filter(tic==sym & ni > pre_max_table[sym]$ni))$fyear[1]

然后我观察到使用filter() 会减慢代码,所以我进一步修改为

  recovery_year <- post_table[post_table$tic==sym & post_table$ni > pre_max_table[sym]$ni, "fyear"][1]

【讨论】:

  • 您好,感谢您的回答。但是有没有办法在不使用 lapply() 的情况下做到这一点(为每个组找到一个特定的值)?我发现多次调用一个函数会大大降低代码的速度。
  • 我不知道是否有一种方法可以在不多次调用函数的情况下做到这一点。只要没有人发现,我们所能做的就是优化功能。
【解决方案2】:

有没有办法在不使用 lapply() 的情况下做到这一点(为每个组找到某个值)?

与原始方法相比,这是一种方法,首先选择所有收入较高的行,然后从这些行中删除除每只股票的第一行之外的所有行:

# pick all rows from post_table with income higher than that from pre_max_table
ps = subset(post_table, ni > pre_max_table[post_table['tic']]$ni)
# pick only the first row for each stock
pnd = ps[!duplicated(ps$tic), c('tic', 'fyear')]
# compute the "recover" time for each stock (including NAs)
YearsRecover = pnd[levels(pnd$tic), 'fyear'] - pre_max_table$fyear

【讨论】:

    猜你喜欢
    • 2017-04-25
    • 2018-08-23
    • 2018-02-04
    • 1970-01-01
    • 2011-07-17
    • 2015-05-07
    • 2017-04-04
    • 2019-05-08
    • 1970-01-01
    相关资源
    最近更新 更多