【问题标题】:How can I sort DF and subtotal based on Profit and NumberDays如何根据 Profit 和 NumberDays 对 DF 和小计进行排序
【发布时间】:2017-03-09 14:49:35
【问题描述】:

我有一个 CSV 格式的数据,看起来像这样..

CUSIP   BuyDate SellDate    BuyAmount   SellAmount  Profit  DaysHolding Over365Days
037833100   12/1/2015   3/1/2017    45  27  -18 456 1
17275R102   1/28/2016   2/21/2017   28  25  -3  390 1
38259P508   10/29/2015  2/18/2017   39  36  -3  478 1
594918104   3/1/2016    3/2/2017    35  40  5   366 1
68389X105   4/14/2016   2/21/2017   47  37  -10 313 0
037833100   12/11/2015  2/19/2017   46  40  -6  436 1
17275R102   1/12/2016   2/24/2017   29  34  5   409 1
38259P508   12/22/2015  2/20/2017   46  39  -7  426 1
594918104   12/19/2015  2/22/2017   26  36  10  431 1
68389X105   2/13/2016   3/2/2017    33  34  1   383 1
037833100   12/9/2015   2/18/2017   32  37  5   437 1
17275R102   2/13/2016   2/27/2017   48  25  -23 380 1
38259P508   11/30/2015  2/23/2017   45  34  -11 451 1
594918104   11/14/2015  2/27/2017   47  28  -19 471 1
68389X105   2/10/2016   2/17/2017   39  38  -1  373 1
037833100   4/7/2016    3/5/2017    44  29  -15 332 0
17275R102   3/3/2016    2/19/2017   26  36  10  353 0
037833100   11/25/2015  2/17/2017   28  40  12  450 1
037833100   1/10/2016   3/6/2017    35  36  1   421 1
037833100   3/4/2016    2/22/2017   45  25  -20 355 0
38259P508   2/10/2016   3/7/2017    42  40  -2  391 1
38259P509   12/5/2015   2/25/2017   31  39  8   448 1
38259P510   4/7/2016    2/27/2017   27  34  7   326 0
38259P511   3/26/2016   2/17/2017   27  39  12  328 0
17275R102   2/11/2016   2/27/2017   29  39  10  382 1
17275R102   11/24/2015  2/18/2017   45  35  -10 452 1
38259P509   3/29/2016   3/7/2017    46  27  -19 343 0
38259P509   4/5/2016    2/23/2017   38  38  0   324 0
17275R102   2/13/2016   2/26/2017   35  31  -4  379 1
594918104   3/10/2016   3/4/2017    29  28  -1  359 0
17275R102   10/30/2015  2/23/2017   40  30  -10 482 1
17275R102   12/15/2015  3/2/2017    25  38  13  443 1
594918104   2/2/2016    2/22/2017   26  32  6   386 1
594918105   3/8/2016    2/20/2017   26  29  3   349 0
594918106   11/21/2015  3/6/2017    44  38  -6  471 1
594918107   3/21/2016   2/20/2017   48  39  -9  336 0
594918108   12/21/2015  3/5/2017    37  28  -9  440 1
594918109   1/16/2016   3/5/2017    35  33  -2  414 1
594918110   2/8/2016    3/2/2017    41  39  -2  388 1

此文件中有数百万行。我想根据 CUSIP 对所有交易进行排序,然后根据利润和 Over365Days 对结果进行小计。这是最终结果应该是什么样子的图像。我只是为效果添加了一些颜色。

我猜应该是这样的:

# read csv file
mydata = read.csv("AllTrades.csv")  

# sort by CUSIP, Over365Days
sortdata <- mtcars[order(CUSIP, Over365Days),] 

# aggregate by Profit & 365Days
finalresults <- aggregate(cbind(Profit, Over365Days) ~ CUSIP, data = sortdata, FUN = sum)

我可以在 Excel 中轻松管理小型数据集,但同样需要处理数百万行。有人可以给我一些可以做我描述的示例代码吗?谢谢大家。

【问题讨论】:

  • 我在理解您要执行的操作时遇到了一些问题。所以对于每个CUSIP,你想计算Profit的总和和Over365Days的总和?
  • 嗯,差不多。对于每个 CUSIP,计算两组利润的总和:>=365 天和
  • 我不确定您为什么需要对表格进行排序。像aggregate(mydata$Profit,by=list(CUSIP = mydata$CUSIP, Over365=myData$Over365),sum) 这样的东西不工作吗?
  • @xraynaud 的评论,但采用公式形式:aggregate(Profit ~ CUSIP + Over365, data = mydata, sum)
  • 我发布的函数中有错字,但我无法编辑我的命令。第二个 myData 应该是 mydata。

标签: r dataframe aggregate split-apply-combine


【解决方案1】:

我必须进行一些清理才能重现您的数据,但这是之后的结果 清洁部分,我将变量命名为clean_data

> str(clean_data)
'data.frame':   39 obs. of  8 variables:
$ CUSIP      : chr  "037833100" "17275R102" "38259P508" "594918104" ...
$ BuyDate    : chr  "12/1/2015 " "1/28/2016 " "10/29/2015" "3/1/2016  " ...
$ SellDate   : chr  "3/1/2017 " "2/21/2017" "2/18/2017" "3/2/2017 " ...
$ BuyAmount  : num  45 28 39 35 47 46 29 46 26 33 ...
$ SellAmount : num  27 25 36 40 37 40 34 39 36 34 ...
$ Profit     : num  -18 -3 -3 5 -10 -6 5 -7 10 1 ...
$ DaysHolding: num  456 390 478 366 313 436 409 426 431 383 ...
$ Over365Days: num  1 1 1 1 0 1 1 1 1 1 ...

然后我复制了 10 倍的数据集以提供稍大的数据大小,因此输出将 更有意义并将其命名为new_data

new_data <- plyr::ldply(1:10, function(i){
  clean_data
})

由于 Excel 格式不符合我们在之后轻松访问数据的方式 操作和聚合,我以稍微不同的方式存储结果 比你在 excel(...相信我...我是一名分析师多年...需要习惯 到但现在我永远不会回到数据透视表...)

因此,这些步骤适用于每个单独的 CUSIP,我们将“分块”数据集 仅进入属于该身份集的那些记录。 IE 为 N 唯一 CUSIP ids,我们将使用split 创建 N[m,j] 个碎片数据子集 方法。我们还将把它包装在一个循环中,这样我们只需要应用我们的 聚合公式一次,但将应用于每个子集。对于每个数据框 在 N 个唯一的 CUSIP id 领域中,我们将返回一个列表,其中包含 1) 原始分块数据 2) 利润 3) 总数

out_split <- lapply(split(new_data, new_data$CUSIP), function(i){
  list(
    data_subset = i, # This is the data unique to the CUSIP id
    profit_calc = sum(i[['Profit']]), # This is the sum of profits
    total = sum(i[['Over365Days']]) # This is the sum of 365 roll
  )
})

现在我们可以通过访问返回列表中的 CUSIP id 来调用我们的数据 并找到我们想要的任何东西。例如:

> out_split$`594918106`
$data_subset
        CUSIP    BuyDate  SellDate BuyAmount SellAmount Profit DaysHolding Over365Days
35  594918106 11/21/2015 3/6/2017         44         38     -6         471           1
74  594918106 11/21/2015 3/6/2017         44         38     -6         471           1
113 594918106 11/21/2015 3/6/2017         44         38     -6         471           1
152 594918106 11/21/2015 3/6/2017         44         38     -6         471           1
191 594918106 11/21/2015 3/6/2017         44         38     -6         471           1
230 594918106 11/21/2015 3/6/2017         44         38     -6         471           1
269 594918106 11/21/2015 3/6/2017         44         38     -6         471           1
308 594918106 11/21/2015 3/6/2017         44         38     -6         471           1
347 594918106 11/21/2015 3/6/2017         44         38     -6         471           1
386 594918106 11/21/2015 3/6/2017         44         38     -6         471           1

$profit_calc
[1] -60

$total
[1] 10

此外,我们可以通过以下方式找到所有计算得出的总数: (因为总数在每次迭代中存储为第 3 项)

 > sapply(out_split, `[[`, 3)
    037833100 17275R102 38259P508 38259P509 38259P510 38259P511 594918104 594918105 594918106 594918107 594918108 594918109 594918110 68389X105 
           50        80        40        10         0         0        40         0        10         0        10        10        10        20 

如果我们想看到利润:

> sapply(out_split, `[[`, 2)
037833100 17275R102 38259P508 38259P509 38259P510 38259P511 594918104 594918105 594918106 594918107 594918108 594918109 594918110 68389X105 
     -410      -120      -230      -110        70       120        10        30       -60       -90       -90       -20       -20      -100 

编辑

我意识到示例输出是在一个只有一条记录的集合上......所以要展示另一个以及如何轻松访问它:

> out_split$`037833100`$data_subset$Profit
 [1] -18  -6   5 -15  12   1 -20 -18  -6   5 -15  12   1 -20 -18  -6   5 -15  12   1 -20 -18  -6   5 -15  12   1 -20 -18  -6   5 -15  12   1 -20 -18  -6   5 -15  12
[41]   1 -20 -18  -6   5 -15  12   1 -20 -18  -6   5 -15  12   1 -20 -18  -6   5 -15  12   1 -20 -18  -6   5 -15  12   1 -20

任何想要复制的人的数据集重建步骤:

clean_data <- stringi::stri_split_lines('
CUSIP   BuyDate SellDate    BuyAmount   SellAmount  Profit  DaysHolding Over365Days
037833100   12/1/2015   3/1/2017    45  27  -18 456 1
17275R102   1/28/2016   2/21/2017   28  25  -3  390 1
38259P508   10/29/2015  2/18/2017   39  36  -3  478 1
594918104   3/1/2016    3/2/2017    35  40  5   366 1
68389X105   4/14/2016   2/21/2017   47  37  -10 313 0
037833100   12/11/2015  2/19/2017   46  40  -6  436 1
17275R102   1/12/2016   2/24/2017   29  34  5   409 1
38259P508   12/22/2015  2/20/2017   46  39  -7  426 1
594918104   12/19/2015  2/22/2017   26  36  10  431 1
68389X105   2/13/2016   3/2/2017    33  34  1   383 1
037833100   12/9/2015   2/18/2017   32  37  5   437 1
17275R102   2/13/2016   2/27/2017   48  25  -23 380 1
38259P508   11/30/2015  2/23/2017   45  34  -11 451 1
594918104   11/14/2015  2/27/2017   47  28  -19 471 1
68389X105   2/10/2016   2/17/2017   39  38  -1  373 1
037833100   4/7/2016    3/5/2017    44  29  -15 332 0
17275R102   3/3/2016    2/19/2017   26  36  10  353 0
037833100   11/25/2015  2/17/2017   28  40  12  450 1
037833100   1/10/2016   3/6/2017    35  36  1   421 1
037833100   3/4/2016    2/22/2017   45  25  -20 355 0
38259P508   2/10/2016   3/7/2017    42  40  -2  391 1
38259P509   12/5/2015   2/25/2017   31  39  8   448 1
38259P510   4/7/2016    2/27/2017   27  34  7   326 0
38259P511   3/26/2016   2/17/2017   27  39  12  328 0
17275R102   2/11/2016   2/27/2017   29  39  10  382 1
17275R102   11/24/2015  2/18/2017   45  35  -10 452 1
38259P509   3/29/2016   3/7/2017    46  27  -19 343 0
38259P509   4/5/2016    2/23/2017   38  38  0   324 0
17275R102   2/13/2016   2/26/2017   35  31  -4  379 1
594918104   3/10/2016   3/4/2017    29  28  -1  359 0
17275R102   10/30/2015  2/23/2017   40  30  -10 482 1
17275R102   12/15/2015  3/2/2017    25  38  13  443 1
594918104   2/2/2016    2/22/2017   26  32  6   386 1
594918105   3/8/2016    2/20/2017   26  29  3   349 0
594918106   11/21/2015  3/6/2017    44  38  -6  471 1
594918107   3/21/2016   2/20/2017   48  39  -9  336 0
594918108   12/21/2015  3/5/2017    37  28  -9  440 1
594918109   1/16/2016   3/5/2017    35  33  -2  414 1
594918110   2/8/2016    3/2/2017    41  39  -2  388 1
', omit_empty = TRUE)[[1]] %>% 
  stringi::stri_split_regex("\\s+", simplify = TRUE) %>% (function(x){
    col_names <- x[1,]
    a_data <- data.frame(x[2:nrow(x),], stringsAsFactors = FALSE)
    colnames(a_data) <- col_names
    as.data.frame(Map(function(i){
      .call_col <- sprintf("as.%s",readr::guess_parser(i))
      do.call(.call_col, list(i))
    }, a_data))
  })

【讨论】:

  • 非常感谢大家!这很有帮助!
  • 没问题...我花了几年的时间嫁给卓越,所以我知道你的痛苦,但是一旦你跳入 R,生活变得多么容易令人惊讶......尤其是在将这些音调放在一起时-书籍....祝你好运。
  • plyr 自 2014 年以来已死,请使用 dplyr! (或data.table
  • @smci 您可能对类似的问题以及我昨天不得不用类似的方法与 dplyr 管道重现的基准测试结果感兴趣。 stackoverflow.com/questions/42672455/… 。我应该注意到dplyrdata.table 是我日常生活的中心......就像parallel,但在这些类型的情况下,我总是回到base 的乐趣......
  • @CarlBoneri:有趣的帖子。但是,我们不要将新用户与几种不同的范式混淆。 plyr 并不总是有效,它经常在高基数拆分时因内存不足而失败。 dplyr 始终有效 (IME),并保证合理性能。
【解决方案2】:

这个聚合是一个简单的单行代码dplyr(或data.table)——(你完全不需要对你的数据框进行预排序):

require(dplyr)

summaryresults <- mydata %>%
    group_by(CUSIP) %>%
    summarize(Profit = sum(Profit), Over365Days = sum(Over365Days)) %>%
    ungroup()
    # %>% arrange(CUSIP, Over365Days) # ...if you want the summary result ordered by those vars

dplyrplyr 的继承者,非常易于使用和直观,带有mutatesummarizefilterselectarrange 等动词。见介绍或教程:https://cran.rstudio.com/web/packages/dplyr/vignettes/introduction.html

【讨论】:

  • 还有其他人得到吗? Error in summarise_impl(.data, dots) : cannot modify grouping variable
  • @CarlBoneri:呵呵!对不起。我们只需要group_by(CUSIP),而不是(CUSIP, Over365Days)。显然,我们不能在group_by(Over365Days) 中改变Over365Days 。请确认它已修复。
  • 向你的方向眨眨眼,伙计。
  • @CarlBoneri:如果 OP 提供了可重现的数据,我就可以在发布之前进行测试...... :-) 这一切都很好。
  • @CarlBoneri:当然。如果您可以在答案的底部添加显示 OP 如何生成可重现数据的代码,这将很有用..
猜你喜欢
  • 1970-01-01
  • 2013-10-06
  • 2010-10-30
  • 2017-03-14
  • 1970-01-01
  • 2012-06-07
  • 2013-03-27
  • 2022-08-19
  • 2017-06-13
相关资源
最近更新 更多