r - 使用 dplyr 对随机交易列表进行排序

标签 r sorting dplyr

假设有以下一组原始交易:

library(tidyverse)

original_transactions <- data.frame(
  row = 1:6,
  start = 0,
  change = runif(6, min = -10, max = 10) %>% round(2),
  end = 0
) %>% mutate(
  temp = cumsum(change),
  end = 100 + temp, # End balance
  start = end - change # Start balance
) %>% select(
  -temp
)

enter image description here

它显示了一个(按时间顺序)交易序列,起始余额为 100.00 美元,期末余额为 95.65 美元,有六次交易/更改。

现在假设你收到了一个困惑的版本
transactions <- original_transactions %>% sample_n(
  6
) %>% mutate(
  row = row_number() # Original sequence is unknown
)

enter image description here

如何对 R 中的序列进行逆向工程?即获取transactions的排序顺序匹配 original_transactions ?理想情况下,我想使用 dplyr 来执行此操作和一系列管道 %>%并避免循环。

假设开始/结束余额将是唯一的,并且一般而言,交易数量可能会有所不同。

最佳答案

首先,让

original_transactions
#   row  start change    end
# 1   1 100.00   2.33 102.33
# 2   2 102.33  -6.52  95.81
# 3   3  95.81  -4.20  91.61
# 4   4  91.61  -3.56  88.05
# 5   5  88.05   7.92  95.97
# 6   6  95.97   3.61  99.58

transactions
#   row  start change    end
# 1   1 100.00   2.33 102.33
# 2   2  91.61  -3.56  88.05
# 3   3  95.81  -4.20  91.61
# 4   4 102.33  -6.52  95.81
# 5   5  88.05   7.92  95.97
# 6   6  95.97   3.61  99.58


diffs <- outer(transactions$start, transactions$start, `-`)
matches <- abs(sweep(diffs, 2, transactions$change, `-`)) < 1e-3

我猜是计算 diffs是整个解决方案中计算成本最高的部分。 diffsstart 之间所有可能的差异您的 transactions .然后将它们与 change 进行比较栏目matches我们知道 transactions 的哪几对行应该一起去如果数字精度没有问题,我们可以使用 match功能并快速完成。然而,在这种情况下,我们有以下 两个选项 .

首先,我们可以使用 igraph .
library(igraph)
(g <- graph_from_adjacency_matrix(t(matches) * 1))
# IGRAPH 45d33f0 D--- 6 5 -- 
# + edges from 45d33f0:
# [1] 1->4 2->5 3->2 4->3 5->6

也就是说,我们有一个隐藏路径图:1->4->3->2->5->6,我们想要恢复它。它由没有传入边的顶点的最长路径给出(即 1 ):
transactions[as.vector(tail(all_simple_paths(g, from = which(rowSums(matches) == 0)), 1)[[1]]), ]
#   row  start change    end
# 1   1 100.00   2.33 102.33
# 4   4 102.33  -6.52  95.81
# 3   3  95.81  -4.20  91.61
# 2   2  91.61  -3.56  88.05
# 5   5  88.05   7.92  95.97
# 6   6  95.97   3.61  99.58

另一种选择是递归。
fun <- function(x, path = x) {
  if(length(xNew <- which(matches[, x])) > 0)
    fun(xNew, c(path, xNew))
  else path
}
transactions[fun(which(rowSums(matches) == 0)), ]
#   row  start change    end
# 1   1 100.00   2.33 102.33
# 4   4 102.33  -6.52  95.81
# 3   3  95.81  -4.20  91.61
# 2   2  91.61  -3.56  88.05
# 5   5  88.05   7.92  95.97
# 6   6  95.97   3.61  99.58

它使用与前一种方法相同的唯一最长路径图思想。

没有显式循环......当然你可以用 %>% 重写所有内容。 ,但它不会像你想要的那么漂亮;这不是真正的传统数据转换任务,其中 dplyr是最好的。

关于r - 使用 dplyr 对随机交易列表进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53862943/

相关文章:

xml - 使用 R 的 XML 包从头开始构建具有完整命名空间信息的 KML

r - 如何在两列之间交换值

javascript - 在 Javascript 中对数组、变量或对象进行排序

c++ - 对负值使用计数排序?

r - 基于字符串模糊匹配的连接数据框

r - 如何在 for 中使用 arrangement?

r - 在 R 中处理 gzip 编码的 GET/OAUTH 响应

r - 在传单中绘制 shp 文件,适用于 ggplot

c++无法使选择排序正常工作

r - 使用 ddply R 对大数据框中的大量列进行求和和 ifelse 的更好更快的方法