【问题标题】:Compare value in vector with all other vectors将向量中的值与所有其他向量进行比较
【发布时间】:2016-02-16 14:03:59
【问题描述】:

假设以下数据集:

+---------------+------------+---------- + |航空公司 |销售总额 |出发前几天 | +---------------+------------+---------- + |吉隆坡 | 477.99 | 0 | |自动对焦 | 457.99 | 0 | |平方 | 556.31 | 0 | +---------------+------------+---------- +

我想做的是:

  1. 将列中的值与同一列中的所有其他值进行比较。
  2. saleTotal(1) 是否小于 saleTotal(2) 和 saleTotal(3) 的值
  3. 如果是,多少? saleTotal(3)/saleTotal(1)

工单

  • 477,99
  • 477,99 (556.31/477.99)-1=1.16(增加 16%)
  • 457.99 .....
  • 457.99 .....
  • 556.31
  • 556.31

到目前为止我所做的尝试:

cal <- apply(df_matrix[1:2,2], 1, function(x) {
  A <- x
  x <- x[-1]
  ifelse(x>A, 1, ifelse(x<A, 0, NA))
})
cal

这没有成功并打印出“logical(0)”,所以我猜没有结果。 我尝试了很多方法,使用 lapply、mapply,但似乎都是比较静态数字而不是前几行。

我从 apply 中了解到的是,每个 X 都有其“迭代”的行。这就是为什么我尝试比较 X>A 而 A 是具有所有 saleTotal 值的整个向量的原因。因此,遍历每一个。


预期输出 业务产出:“价格比 XY 其他价格便宜”

我想这将是避免大矩阵和尽可能低内存的最佳方法) 有没有办法直接“nrow()”结果而不是先创建矩阵/列表?

+------------+-------------+ |销售总额 |比 | 便宜 +------------+-------------+ | 477.99 | 1 | | 457.99 | 2 | | 556.31 | 0 | +------------+-------------+

知道怎么做吗?性能怎么样,我有 100000+ 行?

编辑:预期输出(一种方式)

【问题讨论】:

  • 看看outer(df$saleTotal, df$saleTotal, "/") 值大于 1 表示增加,小于 1 表示减少,矩阵的对角线全为 1,因为它将每个值与自身进行比较。
  • 想要的输出到底是什么?给出FALSE&lt; 比较会发生什么?您的“工作订单”表示一个简单的循环,例如 lapply(seq_along(x), function(i) x[-i][x[[i]] &lt; x[-i]] / x[[i]])
  • @s1x 显示示例输入的预期输出...
  • 看来你需要findInterval; length(x) - findInterval(x, sort(x)) 应该足够高效。
  • @alexis_laz 您应该将此作为答案发布,(如果有人好奇地对我认为很棒的解决方案进行基准测试(我认为findInterval 会更快);p)跨度>

标签: r


【解决方案1】:

请参阅末尾关于效率的说明

根据您的预期输出,您可以迭代每个值并计算(将TRUE 值相加)该值比所有其他值便宜多少次,并返回一个列表以将该值与计数“配对”:

sapply(data[,2],function(x) {
  list(x, sum(x < data[,2]))
})

以长格式给出:

     [,1]   [,2]   [,3]  
[1,] 477.99 457.99 556.31
[2,] 1      2      0     

如果您只想向现有数据集添加一列,应该这样做:

data$cheaperThan <- sapply(data[,2],function(x) sum(x < data[,2])) 

使用的数据:

> system.time(sapply(large,function(x) sum(x < large)))
utilisateur     système      écoulé 
       1.08        0.22        1.30 
> system.time(length(large) - findInterval(large,sort(large)))
utilisateur     système      écoulé 
       0.01        0.00        0.01 

@alexis_laz 解决方案,如果真的真的真的更有效:

> set.seed(123)
> test <- runif(50000)*100
> identical(sapply(test,function(x) sum(x < test)), (length(test) - findInterval(test,sort(test))))
[1] TRUE
> system.time(sapply(test,function(x) sum(x < test)))
utilisateur     système      écoulé 
      13.64        1.24       14.96 
> system.time(length(test) - findInterval(test,sort(test)))
utilisateur     système      écoulé 
       0.01        0.00        0.02

【讨论】:

  • 谢谢!使用大型数据集完善这项工作(@alexis_laz 以获得有效的解决方案)。 @docendo discimus 解决方案也有效 - 但由于输出格式而使用大量内存。因此,根据输出,您可以同时使用两者。
  • 我猜sum(x &lt; x)findinterval(x, sort(x)) 在概念上是相同的,但是sorting 一次的成本应该总是超过length(x) * length(x) 循环,至少对于大型向量而言。我认为findInterval 是 R 中为数不多的“灵丹妙药”之一...... :-)
【解决方案2】:

你可以像这样使用?outer

outer(df$saleTotal, df$saleTotal, "/")
#          [,1]     [,2]      [,3]
#[1,] 1.0000000 1.043669 0.8592152
#[2,] 0.9581581 1.000000 0.8232640
#[3,] 1.1638528 1.214677 1.0000000

大于 1 的值表示增加,小于 1 的值表示减少,矩阵的对角线全为 1,因为它将每个值与自身进行比较。

当然,您可以将其修改为仅显示大于 1 的值,例如使用:

res <- outer(df$saleTotal, df$saleTotal, "/")
res * as.integer(res > 1)
#         [,1]     [,2] [,3]
#[1,] 0.000000 1.043669    0
#[2,] 0.000000 0.000000    0
#[3,] 1.163853 1.214677    0

或者,如果您只想要一个逻辑矩阵:

res > 1
#      [,1]  [,2]  [,3]
#[1,] FALSE  TRUE FALSE
#[2,] FALSE FALSE FALSE
#[3,]  TRUE  TRUE FALSE

【讨论】:

  • 对我的小样本很有魅力。有 50,000 行:“错误:无法分配大小为 24.2 Gb 的向量”;所以外部似乎不适用于这里的大型数据集,因为它建立了一个巨大的矩阵。
  • @s1x,我明白你的意思了。如 alexis_laz 所要求的,您应该更具体地了解所需的输出。如果你想要每次比较的结果,我认为其他方法也会很困难(你有多少内存?)
  • @s1x 如果每个值都必须与其他值进行比较,那么结果向量显然至少是factorial(length(data[,'saleTotal']))...
猜你喜欢
  • 1970-01-01
  • 2017-12-29
  • 1970-01-01
  • 2016-03-13
  • 2021-12-29
  • 1970-01-01
  • 2022-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多