Tôi muốn thực hiện tìm kiếm rất nhanh và có vẻ như sử dụng hàm băm (thông qua môi trường) là cách tốt nhất để thực hiện điều đó. Bây giờ tôi có một ví dụ đang chạy trong môi trường, nhưng nó không trả về những gì tôi cần.
Đây là một ví dụ:
a <- data.table::data.table(a=c(1, 3, 5), b=c(2, 4, 6), time=c(10, 20, 30))
my_env <- list2env(a)
x <- a[2, .(a, b)] # x=c(3,4)
đã tìm thấy <- get("x", envir = my_env)
tôi hy vọng tìm thấy = c(3, 4, 20)
nhưng đã nhận được tìm thấy = c(3, 4)
(Tôi muốn trả về toàn bộ hàng thay vì một tập hợp con các hàng không xác định)
lý lịch:Tôi có một danh sách khổng lồ với các nguồn và đích cho các tuyến đường được tính toán bằng osrm, ví dụ:
vĩ độ1, kinh độ1, vĩ độ2, kinh độ2, thời gian di chuyển
46,12, 8,32, 47,87, 9,92, 1036
...
Danh sách chứa khoảng 100000 hàng trong ví dụ đầu tiên. Việc sử dụng tìm kiếm nhị phân trong data.table giúp mã của tôi nhanh hơn 100 lần nhưng quá trình tìm kiếm vẫn mất 1 mili giây. Vì tôi phải tìm kiếm rất nhiều tuyến đường trong quá trình mô phỏng (khoảng 2e5 lần tìm kiếm), tôi muốn nhanh hơn.
@Gregor: Tôi là người mới bắt đầu học R, nhưng tôi không nghĩ câu hỏi của mình bị trùng lặp:
- Tôi biết liên kết thứ hai, đó là liên kết tổng quan trừu tượng về các khả năng được các chuyên gia liệt kê. Hơn nữa, nó đã 4 tuổi.
- Tôi không biết về liên kết đầu tiên, nhưng từ những câu trả lời này, tôi không biết liệu mình có nên chuyển sang môi trường hay không và cách triển khai hoạt động. Cũng không có cuộc thảo luận nào về việc tìm kiếm một phần của danh sách khổng lồ.
Tóm tắt (Cảm ơn DigEmAll về ví dụ đang chạy bên dưới):
- Sử dụng Rcpp trên số nguyên, việc tìm kiếm chiếm ít bộ nhớ hơn mà không làm giảm chất lượng. Ngoài ra, nó nhanh hơn khoảng 3 lần.
- Không sử dụng môi trường băm khi bạn muốn tìm giá trị kép (phải được chuyển đổi thành chuỗi).
- Việc triển khai trong mã hiện có phải dễ dàng.
Đây là một ví dụ sử dụng môi trường và data.table, mã này rất dễ hiểu:
thư viện (data.table)
# tạo một ví dụ ngẫu nhiên lớn (160k hàng)
set.seed(123)
fromTo <- Expand.grid(1:400,1:400)
colnames(fromTo) <- c('a','b')
DF <- as.data.frame(cbind(fromTo,time=as.integer(runif(nrow(fromTo), min = 1, max=500))))
# thiết lập môi trường để sử dụng nó làm hashtable:
# chúng ta chỉ cần đặt thời gian vào trong một môi trường bằng cách sử dụng
# a|b (nối a với b) làm khóa
timeList <- as.list(DF$time)
tên(timeList) <- dán(DF$a,DF$b,sep='|')
timeEnv <- list2env(timeList)
# thiết lập data.table để sử dụng nó làm hashtable
DT <- setDT(DF,key=c('a','b'))
#tạo chức năng tìm kiếm
searchUsingEnv <- function(a,b){
thời gian <- get(paste(a,b,sep='|'),envir=timeEnv,inherits=FALSE)
trở lại (thời gian)
}
searchUsingDataTable <- function(from,to){
thời gian <- DT[.(từ,đến),thời gian]
trở lại (thời gian)
}
Điểm chuẩn:
# chức năng điểm chuẩn
# tức là chúng tôi cố gắng tìm kiếm ~16K hàng trong hai loại bảng băm của mình
benchEnv <- function(){
n <- nrow(fromTo)
s <- as.integer(n * 0.9)
cho(i trong s:n){
searchUsingEnv(fromTo[i,'a'],fromTo[i,'b'])
}
}
băng ghế dự bị<- function(){
n <- nrow(fromTo)
s <- as.integer(n * 0.9)
cho(i trong s:n){
searchUsingDataTable(fromTo[i,'a'],fromTo[i,'b'])
}
}
# hãy đo lường hiệu suất
> system.time(benchEnv(), gcFirst = TRUE)
hệ thống người dùng đã trôi qua
2,26 0,00 2,30
> system.time(benchDT(), gcFirst = TRUE)
hệ thống người dùng đã trôi qua
42,34 0,00 42,56
Tóm lại:
môi trường dường như nhanh hơn nhiều so với việc truy cập một khóa lặp lại vào data.table, vì vậy bạn có thể thử sử dụng môi trường đó.
biên tập:
Môi trường có thể được truy cập nhanh chóng, nhưng chúng chỉ có thể có các khóa chuỗi chiếm nhiều bộ nhớ hơn gấp đôi. Vì vậy, tôi đã thêm cách sử dụng Rcpp
Ví dụ về và std::map<>
Sử dụng ánh xạ đa giá trị:
(LƯU Ý: Nếu bạn đang sử dụng Windows, bạn sẽ cần cài đặt RCông cụ Để Rcpp hoạt động bình thường)
thư viện (data.table)
thư viện (Rcpp)
thư viện (nội tuyến)
nHàng <- 1e7
############# tạo data.table "DT" chứa tọa độ và thời gian
generate_routes_dt <- function(nmax) {
set.seed(123)
tuyến đường <- data.table(lat1 = số(nmax),
lng1 = số(nmax),
lat2 = số(nmax),
lng2 = số(nmax),
thời gian = số(nmax))
tmp <- sample(seq(46, 49, length.out = nmax), nmax)
tuyến$lat1 <- tmp
tmp <- sample(seq(8, 10, length.out = nmax), nmax)
tuyến$lng1 <- tmp
tmp <- sample(seq(46, 49, length.out = nmax), nmax)
tuyến$lat2 <- tmp
tmp <- sample(seq(8, 10, length.out = nmax), nmax)
tuyến$lng2 <- tmp
tmp <- sample(seq(0, 1e7, length.out = nmax), nmax)
tuyến$time <- as.integer(tmp)
data.table::setkey(tuyến, lat1, lng1, lat2, lng2)
trở lại (tuyến đường)
}
DT <- generate_routes_dt(nRows)
############## tạo chức năng tìm kiếm data.table
searchUsingDataTable <- function(lat_1,lng_1,lat_2,lng_2){
thời gian <- DT[.(lat_1,lng_1,lat_2,lng_2),thời gian]
trở lại (thời gian)
}
##############
############## tạo chức năng tìm kiếm Rcpp
# đoạn code sau tạo 2 hàm: createMap và getTime
#cách sử dụng:
# bản đồ <- createMap(lat1Vec,lng1Vec,lat2Vec,lng2Vec,timesVec)
# t <- getTime(map,lat1,lng1,lat2,lng2)
nguồnCpp(code=
'
#include
lớp MultiKey {
public:
vĩ độ gấp đôi1;
đôi lng1;
vĩ độ kép2;
đôi lng2;
MultiKey(đôi la1, đôi ln1, đôi la2, đôi ln2)
: lat1(la1), lng1(ln1), lat2(la2), lng2(ln2) {}
toán tử bool<(const MultiKey &right) const
{
if (lat1 == right.lat1) {
if ( lng1 == right.lng1 ) {
if (lat2 == right.lat2) {
return lng2 < right.lng2;
}
khác {
return lat2 < right.lat2;
}
}
khác {
return lng1 < right.lng1;
}
}
khác {
trả về lat1 < right.lat1;
}
}
};
// [[Rcpp::export]]
SEXP createMap(Rcpp::NumericVector lat1,
Rcpp::Vector số lng1,
Rcpp::NumericVector lat2,
Rcpp::Vector số lng2,
Rcpp::NumericVector lần){
std::map* map = new std::map;
int n1 = lat1.size();
int n2 = lng1.size();
int n3 = lat2.size();
int n4 = lng2.size();
int n5 = time.size();
if(!(n1 == n2 && n2 == n3 && n3 == n4 && n4 == n5)){
ném std::range_error("độ dài vectơ đầu vào khác nhau");
}
for(int i = 0; i < n1; i++){
Phím MultiKey(lat1[i],lng1[i],lat2[i],lng2[i]);
map->insert(std::pair(key, lần[i]));
}
Rcpp::XPtr< std::map > p(map, true);
trở lại (p);
}
// [[Rcpp::export]]
Rcpp::NumericVector getTime(SEXP mapPtr,
nhân đôi1,
đôi lng1,
vĩ độ đôi2,
gấp đôi lng2){
Rcpp::XPtr< std::map > ptr(mapPtr);
Phím MultiKey(lat1,lng1,lat2,lng2);
std::map::iterator it = ptr->find(key);
if(it == ptr->end())
trả về R_NilValue;
return Rcpp::wrap(it->second);
}
')
bản đồ <- createMap(DT$lat1,DT$lng1,DT$lat2,DT$lng2,DT$time)
searchUsingRcpp <- function(lat_1,lng_1,lat_2,lng_2){
thời gian <- getTime(map,lat_1,lng_1,lat_2,lng_2)
trở lại (thời gian)
}
##############
############## điểm chuẩn
set.seed(1234)
rowToSearchOneByOne <- DT[sample.int(nrow(DT),size=nrow(DT),replace=FALSE),]
băng ghế dự bị <- function(searchFun2Use){
for(i in nrow(rowsToSearchOneByOne)){
khóa <- rowToSearchOneByOne[i,]
searchFun2Use(key$lat1,key$lng1,key$lat2,key$lng2)
}
}
điểm chuẩn vi mô::điểm chuẩn vi mô(
băng ghế dự bị (searchUsingRcpp),
băng ghế dự bị (searchUsingDataTable),
lần=100)
##############
Kết quả điểm chuẩn:
Đơn vị: micro giây
expr min lq trung bình uq max neval
băng ghế dự bị(searchUsingRcpp) 360.959 381.7585 400.4466 391.999 403.9985 665.597 100
băng ghế dự bị(searchUsingDataTable) 1103.034 1138.0740 1214.3008 1163.514 1224.9530 2035.828 100
Để ý:
Tôi thực sự không nghĩ việc sử dụng double làm khóa là một ý tưởng hay... nên sử dụng các giá trị float để tìm kiếm với dung sai cụ thể hoặc trong một phạm vi, chứ không phải để tìm kết quả khớp hoàn hảo trên bản đồ.
Tôi là một lập trình viên xuất sắc, rất giỏi!