【问题标题】:apply function to all rows and columns in data frame except first column based on value in first column根据第一列中的值将函数应用于数据框中的所有行和列,但第一列除外
【发布时间】:2012-09-06 03:10:27
【问题描述】:

您好,希望我能简单地解释一下。我知道这可以通过循环来完成,但这将花费很长时间,我需要将此分析作为网页的一部分来完成,因此某种应用功能应该会更好地工作。

我有 2 个数据框。数据框 A 有一个不同的“锚点”列表和每个类别值(这些是来自已经执行的 ddply 的加权平均值)。

anchor     ecomax    ecomin     volume     price    runtime
1   9482 0.12981362 0.5714286 0.12981362 0.1324330 1.00000000
2   9488 0.01458662 0.5544864 0.01458662 0.2967270 0.04166667
3   9549 0.09734398 0.5721429 0.09734398 0.1219376 1.00000000
4   9574 0.00902656 0.5505136 0.00902656 0.1455307 0.14652568
5   9575 0.00902656 0.5505136 0.00902656 0.1460919 0.14652568
6   9576 0.07608863 0.5613563 0.07608863 0.1114813 1.00000000

数据框 B 是具有相同类别值的较大数据框(暂时忽略名称),但每个锚点有多个条目。

  anchor ecomax_max_med ecomin_min_med volume_med price_med run_time_minimum_med
1   9482     0.12981362      0.5714286 0.12981362 0.1120882           1.00000000
2   9482     0.12981362      0.5714286 0.12981362 0.1686777           1.00000000
3   9488     0.01552049      0.5550000 0.01552049 0.2925363           0.04166667
4   9488     0.01292292      0.5535714 0.01292292 0.3041928           0.04166667
5   9549     0.09734398      0.5721429 0.09734398 0.1238916           1.00000000
6   9549     0.09734398      0.5721429 0.09734398 0.1184564           1.00000000

我想根据匹配的锚点从平均值(数据框 A)中减去 B 的类别值;即 B 的前 2 行(锚 9482)将与 A 的第一行(锚 9482 均值)不同,接下来的 2 行 B(锚 9488)将与 A 的下一行(锚 9488 均值)不同, 等等。

最终结果是使新数据框 C 的每一行/列(锚点除外)成为数据框 B 中的值与其对应的锚点均值(数据框 A)之间的差异。我希望这是相当直截了当的;它可以很容易地通过一个冗长的循环来完成。我猜这需要“匹配”或“按”的某种组合,但我不确定,这非常令人沮丧。帮助!

【问题讨论】:

  • 必须用矩阵思维来思考。

标签: r dataframe match apply


【解决方案1】:

这是data.table 解决方案。

它通过将ABanchor (设置为键)合并来工作。然后它计算我们创建的表达式e

list(ecomax_diff = ecomax_max_med - ecomax, ecomin_diff = ecomin_min_med - ecomin, volume_diff = volume_med - volume, price_diff = price_med - price, runtime_diff = run_time_minimum_med - runtime)

使用mapplysprintfparse

解决方案取决于将每个 data.table 对应的列名传递给 mapply。

library(data.table)
DA <- data.table(A)
DB <- data.table(B)
setkey(DA, 'anchor')
setkey(DB, 'anchor')

.calls <- mapply(sprintf, as.list(names(DA)[-1]), 
  as.list(names(DB)[-1]), as.list(names(DA)[-1]), 
  MoreArgs = list(fmt = '%s_diff = %s - %s'))

.e <- parse(text = sprintf('list(%s)', paste(.calls, collapse =', ')))


DA[DB, eval(.e)]
##  anchor ecomax_diff ecomin_diff volume_diff price_diff runtime_diff
## 1:   9482  0.00000000   0.0000000  0.00000000 -0.0203448            0
## 2:   9482  0.00000000   0.0000000  0.00000000  0.0362447            0
## 3:   9488  0.00093387   0.0005136  0.00093387 -0.0041907            0
## 4:   9488 -0.00166370  -0.0009150 -0.00166370  0.0074658            0
## 5:   9549  0.00000000   0.0000000  0.00000000  0.0019540            0
## 6:   9549  0.00000000   0.0000000  0.00000000 -0.0034812            0

第二个,效率较低但可能更容易遵循的解决方案

 # calculate the difference between the respective columns (merged appropriately
 DIFF <- DB[, names(DB)[-1],with = F] - DA[DB][, names(DA)[-1], with = F]
 # combine with the anchor column from DB 
 DC <-  cbind(DB[,list(anchor)],DIFF)
 # rename with the names from A (otherwise they will have the same as DB
 setnames(DC, names(DA))
 # It creates the correct output !
 DC
 ##    anchor      ecomax      ecomin      volume      price      runtime
 ## 1:   9482  0.00000000   0.0000000  0.00000000 -0.0203448            0
 ## 2:   9482  0.00000000   0.0000000  0.00000000  0.0362447            0
 ## 3:   9488  0.00093387   0.0005136  0.00093387 -0.0041907            0
 ## 4:   9488 -0.00166370  -0.0009150 -0.00166370  0.0074658            0
 ## 5:   9549  0.00000000   0.0000000  0.00000000  0.0019540            0
 ## 6:   9549  0.00000000   0.0000000  0.00000000 -0.0034812            0
  • 注意:如果 -.data.table 在未来版本中忽略字符列,这可能会变得更加简单

【讨论】:

  • +5 虽然难以阅读(即使对我来说!)它应该是有效的。您是否意识到 DA[DB, eval(.e)] 不是在进行完全合并,而是使用 join-inerited-scope 进行 by-without-by 吗?这是相当先进的所以只是想知道它是否是偶然的:)
  • 由于DA的密钥是唯一的,它可能需要,mult="first"来避免已知的减速错误(#2216)。
  • 嗯。必须有更简单的方法,比如B - A[B]。从表面上看,- 适用于data.table,但B - A[B] 需要一些潜在的功能请求(例如-.data.table 可以跳过character 列)。
  • join继承范围在小数据集上相当浪费。我记得在其中一个小插曲中读到过它,还有你之前的评论说在 j 中使用 eval() 会更有效。
  • DA[DB, eval(.e), mult = 'first'] 似乎打破了范围。 - 它给出了一个错误Error in eval(expr, envir, enclos) : object 'ecomax_max_med' not found
【解决方案2】:
datmer <- merge(datA, datB)
str(datmer)
#------------------    
'data.frame':   6 obs. of  11 variables:
 $ anchor              : int  9482 9482 9488 9488 9549 9549
 $ ecomax              : num  0.1298 0.1298 0.0146 0.0146 0.0973 ...
 $ ecomin              : num  0.571 0.571 0.554 0.554 0.572 ...
 $ volume              : num  0.1298 0.1298 0.0146 0.0146 0.0973 ...
 $ price               : num  0.132 0.132 0.297 0.297 0.122 ...
 $ runtime             : num  1 1 0.0417 0.0417 1 ...
 $ ecomax_max_med      : num  0.1298 0.1298 0.0155 0.0129 0.0973 ...
 $ ecomin_min_med      : num  0.571 0.571 0.555 0.554 0.572 ...
 $ volume_med          : num  0.1298 0.1298 0.0155 0.0129 0.0973 ...
 $ price_med           : num  0.112 0.169 0.293 0.304 0.124 ...
 $ run_time_minimum_med: num  1 1 0.0417 0.0417 1 ...

 datmer2 <- cbind(datmer[,1, drop=FALSE], 
                  as.matrix(datmer[, 2:6])  - as.matrix(datmer[7:11]) )
 datmer2
#--------
  anchor      ecomax     ecomin      volume      price runtime
1   9482  0.00000000  0.0000000  0.00000000  0.0203448       0
2   9482  0.00000000  0.0000000  0.00000000 -0.0362447       0
3   9488 -0.00093387 -0.0005136 -0.00093387  0.0041907       0
4   9488  0.00166370  0.0009150  0.00166370 -0.0074658       0
5   9549  0.00000000  0.0000000  0.00000000 -0.0019540       0
6   9549  0.00000000  0.0000000  0.00000000  0.0034812       0

如果您想按照 @mnel 执行的顺序 (B-A) 使用差异,您还可以让列名与第二个数据框的列名相同:

 str( cbind(datmer[,1, drop=FALSE], as.matrix(datmer[7:11])  - as.matrix(datmer[2:6]) ) )
'data.frame':   6 obs. of  6 variables:
 $ anchor              : int  9482 9482 9488 9488 9549 9549
 $ ecomax_max_med      : num  0 0 0.000934 -0.001664 0 ...
 $ ecomin_min_med      : num  0 0 0.000514 -0.000915 0 ...
 $ volume_med          : num  0 0 0.000934 -0.001664 0 ...
 $ price_med           : num  -0.02034 0.03624 -0.00419 0.00747 0.00195 ...
 $ run_time_minimum_med: num  0 0 0 0 0 0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多