查找匹配行的最快方法
Fastest way of finding matching rows
我想知道在 xts
对象中查找与一个特定行相同的所有行的最快方法是什么
library(xts)
nRows <- 3
coreData <- data.frame(a=rnorm(nRows), b=rnorm(nRows), c=rnorm(nRows))
testXts1 <- xts(coreData, order.by=as.Date(1:nRows))
testXts2 <- xts(coreData, order.by=as.Date((nRows + 1):(2*nRows)))
testXts3 <- xts(coreData, order.by=as.Date((2*nRows + 1):(3*nRows)))
testXts <- rbind(testXts1, testXts2, testXts3)
> testXts
a b c
1970-01-02 -0.3288756 1.441799 1.321608
1970-01-03 -0.7105016 1.639239 -2.056861
1970-01-04 0.1138675 -1.782825 -1.081799
1970-01-05 -0.3288756 1.441799 1.321608
1970-01-06 -0.7105016 1.639239 -2.056861
1970-01-07 0.1138675 -1.782825 -1.081799
1970-01-08 -0.3288756 1.441799 1.321608
1970-01-09 -0.7105016 1.639239 -2.056861
1970-01-10 0.1138675 -1.782825 -1.081799
rowToSearch <- first(testXts)
> rowToSearch
a b c
1970-01-02 -0.3288756 1.441799 1.321608
indicesOfMatchingRows <- unlist(apply(testXts, 1, function(row) lapply(1:NCOL(row), function(i) row[i] == coredata(rowToSearch[, i]))))
testXts[indicesOfMatchingRows, ]
a b c
1970-01-02 -0.3288756 1.441799 1.321608
1970-01-05 -0.3288756 1.441799 1.321608
1970-01-08 -0.3288756 1.441799 1.321608
我相信这可以以更优雅、更快速的方式完成。
一个更普遍的问题是你在 R "I have this row matrix[5, ] how can I find (indexes of) other rows in matrix that are the same as matrix[5, ]" 中怎么说。
如何在 data.table
中执行此操作?
这是一个更快的基础 R 解决方案:
ind <- colSums(t(testXts) != as.vector(rowToSearch)) == 0L
testXts[ind,]
这是一个使用 data.table 连接的解决方案:
library(data.table)
testDT <- as.data.frame(testXts)
setDT(testDT, keep.rownames=TRUE)
setkey(testDT, a, b, c)
testDT[setDT(as.data.frame(rowToSearch))]
不过,comparing floating point numbers.
时我会小心
这不使用 data.table
但可能会非常快。您可以通过散列行来做到这一点,
library(digest)
hash <- apply(testXts, 1, digest)
testXts[which(hash[1] == hash)]
# a b c
# 1970-01-02 0.8466816 -0.7129076 -0.5742323
# 1970-01-05 0.8466816 -0.7129076 -0.5742323
# 1970-01-08 0.8466816 -0.7129076 -0.5742323
既然你说速度是你的主要关注点,你甚至可以通过使用 Rcpp 的 data.table 解决方案获得加速:
library(Rcpp)
cppFunction(
"LogicalVector compareToRow(NumericMatrix x, NumericVector y) {
const int nr = x.nrow();
const int nc = x.ncol();
LogicalVector ret(nr, true);
for (int j=0; j < nr; ++j) {
for (int k=0; k < nc; ++k) {
if (x(j, k) != y[k]) {
ret[j] = false;
break;
}
}
}
return ret;
}")
testXts[compareToRow(testXts, rowToSearch),]
# a b c
# 1970-01-02 1.324457 0.8485654 -1.464764
# 1970-01-05 1.324457 0.8485654 -1.464764
# 1970-01-08 1.324457 0.8485654 -1.464764
这是一个相当大的实例(有 100 万行)的比较:
set.seed(144)
bigXts <- testXts[sample(nrow(testXts), 1000000, replace=TRUE),]
testDT <- as.data.frame(bigXts)
josilber <- function(x, y) x[compareToRow(x, y),]
roland.base <- function(x, y) x[colSums(t(x) != as.vector(y)) == 0L,]
library(data.table)
roland.dt <- function(testDT, y) {
setDT(testDT, keep.rownames=TRUE)
setkey(testDT, a, b, c)
testDT[setDT(as.data.frame(y))]
}
library(microbenchmark)
microbenchmark(josilber(bigXts, rowToSearch), roland.base(bigXts, rowToSearch), roland.dt(testDT, rowToSearch), times=10)
# Unit: milliseconds
# expr min lq mean median uq max
# josilber(bigXts, rowToSearch) 7.830986 10.24748 45.64805 14.41775 17.37049 258.4404
# roland.base(bigXts, rowToSearch) 3530.042324 3964.72314 4288.05758 4179.64233 4534.21407 5400.5619
# roland.dt(testDT, rowToSearch) 32.826285 34.95014 102.52362 57.30213 130.51053 267.2249
此基准假设对象在调用 roland.dt
之前已转换为数据帧(开销约 4 秒),并且在调用 compareToRows
之前已编译(开销约 3 秒) =14=]。 Rcpp 解决方案比基本 R 解决方案快约 300 倍,比 data.table 解决方案快约 4 倍(中位运行时间)。基于digest
的方法没有竞争力,每次执行时间超过60秒。
最简单的data.table
解决方案大概是:
merge(as.data.table(testXts), as.data.table(rowToSearch, keep.rownames=FALSE))
Returns:
a b c index
1: 1.685138 -0.3039018 -1.550871 1970-01-02
2: 1.685138 -0.3039018 -1.550871 1970-01-05
3: 1.685138 -0.3039018 -1.550871 1970-01-08
为什么这有效:
merge = 公共列上的内部联接(如果没有另外指定)。此内部联接 returns 仅具有与 rowToSearch 相同的 (a, b, c) 值的列。
右侧的 keep.rownames=FALSE
确保删除 rowToSearch 的日期索引(不想要的)并且不进入用于连接的公共列。
我想知道在 xts
对象中查找与一个特定行相同的所有行的最快方法是什么
library(xts)
nRows <- 3
coreData <- data.frame(a=rnorm(nRows), b=rnorm(nRows), c=rnorm(nRows))
testXts1 <- xts(coreData, order.by=as.Date(1:nRows))
testXts2 <- xts(coreData, order.by=as.Date((nRows + 1):(2*nRows)))
testXts3 <- xts(coreData, order.by=as.Date((2*nRows + 1):(3*nRows)))
testXts <- rbind(testXts1, testXts2, testXts3)
> testXts
a b c
1970-01-02 -0.3288756 1.441799 1.321608
1970-01-03 -0.7105016 1.639239 -2.056861
1970-01-04 0.1138675 -1.782825 -1.081799
1970-01-05 -0.3288756 1.441799 1.321608
1970-01-06 -0.7105016 1.639239 -2.056861
1970-01-07 0.1138675 -1.782825 -1.081799
1970-01-08 -0.3288756 1.441799 1.321608
1970-01-09 -0.7105016 1.639239 -2.056861
1970-01-10 0.1138675 -1.782825 -1.081799
rowToSearch <- first(testXts)
> rowToSearch
a b c
1970-01-02 -0.3288756 1.441799 1.321608
indicesOfMatchingRows <- unlist(apply(testXts, 1, function(row) lapply(1:NCOL(row), function(i) row[i] == coredata(rowToSearch[, i]))))
testXts[indicesOfMatchingRows, ]
a b c
1970-01-02 -0.3288756 1.441799 1.321608
1970-01-05 -0.3288756 1.441799 1.321608
1970-01-08 -0.3288756 1.441799 1.321608
我相信这可以以更优雅、更快速的方式完成。
一个更普遍的问题是你在 R "I have this row matrix[5, ] how can I find (indexes of) other rows in matrix that are the same as matrix[5, ]" 中怎么说。
如何在 data.table
中执行此操作?
这是一个更快的基础 R 解决方案:
ind <- colSums(t(testXts) != as.vector(rowToSearch)) == 0L
testXts[ind,]
这是一个使用 data.table 连接的解决方案:
library(data.table)
testDT <- as.data.frame(testXts)
setDT(testDT, keep.rownames=TRUE)
setkey(testDT, a, b, c)
testDT[setDT(as.data.frame(rowToSearch))]
不过,comparing floating point numbers.
时我会小心这不使用 data.table
但可能会非常快。您可以通过散列行来做到这一点,
library(digest)
hash <- apply(testXts, 1, digest)
testXts[which(hash[1] == hash)]
# a b c
# 1970-01-02 0.8466816 -0.7129076 -0.5742323
# 1970-01-05 0.8466816 -0.7129076 -0.5742323
# 1970-01-08 0.8466816 -0.7129076 -0.5742323
既然你说速度是你的主要关注点,你甚至可以通过使用 Rcpp 的 data.table 解决方案获得加速:
library(Rcpp)
cppFunction(
"LogicalVector compareToRow(NumericMatrix x, NumericVector y) {
const int nr = x.nrow();
const int nc = x.ncol();
LogicalVector ret(nr, true);
for (int j=0; j < nr; ++j) {
for (int k=0; k < nc; ++k) {
if (x(j, k) != y[k]) {
ret[j] = false;
break;
}
}
}
return ret;
}")
testXts[compareToRow(testXts, rowToSearch),]
# a b c
# 1970-01-02 1.324457 0.8485654 -1.464764
# 1970-01-05 1.324457 0.8485654 -1.464764
# 1970-01-08 1.324457 0.8485654 -1.464764
这是一个相当大的实例(有 100 万行)的比较:
set.seed(144)
bigXts <- testXts[sample(nrow(testXts), 1000000, replace=TRUE),]
testDT <- as.data.frame(bigXts)
josilber <- function(x, y) x[compareToRow(x, y),]
roland.base <- function(x, y) x[colSums(t(x) != as.vector(y)) == 0L,]
library(data.table)
roland.dt <- function(testDT, y) {
setDT(testDT, keep.rownames=TRUE)
setkey(testDT, a, b, c)
testDT[setDT(as.data.frame(y))]
}
library(microbenchmark)
microbenchmark(josilber(bigXts, rowToSearch), roland.base(bigXts, rowToSearch), roland.dt(testDT, rowToSearch), times=10)
# Unit: milliseconds
# expr min lq mean median uq max
# josilber(bigXts, rowToSearch) 7.830986 10.24748 45.64805 14.41775 17.37049 258.4404
# roland.base(bigXts, rowToSearch) 3530.042324 3964.72314 4288.05758 4179.64233 4534.21407 5400.5619
# roland.dt(testDT, rowToSearch) 32.826285 34.95014 102.52362 57.30213 130.51053 267.2249
此基准假设对象在调用 roland.dt
之前已转换为数据帧(开销约 4 秒),并且在调用 compareToRows
之前已编译(开销约 3 秒) =14=]。 Rcpp 解决方案比基本 R 解决方案快约 300 倍,比 data.table 解决方案快约 4 倍(中位运行时间)。基于digest
的方法没有竞争力,每次执行时间超过60秒。
最简单的data.table
解决方案大概是:
merge(as.data.table(testXts), as.data.table(rowToSearch, keep.rownames=FALSE))
Returns:
a b c index
1: 1.685138 -0.3039018 -1.550871 1970-01-02
2: 1.685138 -0.3039018 -1.550871 1970-01-05
3: 1.685138 -0.3039018 -1.550871 1970-01-08
为什么这有效:
merge = 公共列上的内部联接(如果没有另外指定)。此内部联接 returns 仅具有与 rowToSearch 相同的 (a, b, c) 值的列。
右侧的keep.rownames=FALSE
确保删除 rowToSearch 的日期索引(不想要的)并且不进入用于连接的公共列。