R 因子函数 运行 长数据帧慢
R factor function running slow with long dataframe
我有一个很长的数据框(数百万行,几列)。对于 运行 固定效应回归,我想使用 factor
函数将分类变量声明为因子,但这很慢。我正在寻找加速它的潜在解决方案。
我的代码如下:
library(lfe)
my_data=read.csv("path_to//data.csv")
attach(data.frame(my_data))
下面是非常的慢行:
my_data$col <- factor(my_data$col)
如果你知道你正在创造的因素的水平,这可以大大加快速度。观察:
library(microbenchmark)
set.seed(237)
test <- sample(letters, 10^7, replace = TRUE)
microbenchmark(noLevels = factor(test), withLevels = factor(test, levels = letters), times = 20)
Unit: milliseconds
expr min lq mean median uq max neval cld
noLevels 523.6078 545.3156 653.4833 696.4768 715.9026 862.2155 20 b
withLevels 248.6904 270.3233 325.0762 291.6915 345.7774 534.2473 20 a
为了获得 OP 情况的级别,我们只需调用 unique
。
myLevels <- unique(my_data$col)
my_data$col <- factor(my_data$col, levels = myLevels)
还有一个由 Kevin Ushley (Fast factor generation with Rcpp) 编写的 Rcpp
产品。我对代码进行了一些修改,假设人们会知道级别 先验 的情况。来自参考网站的函数是 RcppNoLevs
,修改后的 Rcpp 函数在下面的基准测试中是 RcppWithLevs
。
microbenchmark(noLevels = factor(test),
withLevels = factor(test, levels = letters),
RcppNoLevs = fast_factor(test),
RcppWithLevs = fast_factor_Levs(test, letters), times = 20)
Unit: milliseconds
expr min lq mean median uq max neval cld
noLevels 571.5482 609.6640 672.1249 645.4434 704.4402 1032.7595 20 d
withLevels 275.0570 294.5768 318.7556 309.2982 342.8374 383.8741 20 c
RcppNoLevs 189.5656 203.3362 213.2624 206.9281 215.6863 292.8997 20 b
RcppWithLevs 105.7902 111.8863 120.0000 117.9411 122.8043 173.8130 20 a
这里是修改后的 Rcpp 函数,假设一个人将级别作为参数传递:
#include <Rcpp.h>
using namespace Rcpp;
template <int RTYPE>
IntegerVector fast_factor_template_Levs( const Vector<RTYPE>& x, const Vector<RTYPE>& levs) {
IntegerVector out = match(x, levs);
out.attr("levels") = as<CharacterVector>(levs);
out.attr("class") = "factor";
return out;
}
// [[Rcpp::export]]
SEXP fast_factor_Levs( SEXP x, SEXP levs) {
switch( TYPEOF(x) ) {
case INTSXP: return fast_factor_template_Levs<INTSXP>(x, levs);
case REALSXP: return fast_factor_template_Levs<REALSXP>(x, levs);
case STRSXP: return fast_factor_template_Levs<STRSXP>(x, levs);
}
return R_NilValue;
}
我有一个很长的数据框(数百万行,几列)。对于 运行 固定效应回归,我想使用 factor
函数将分类变量声明为因子,但这很慢。我正在寻找加速它的潜在解决方案。
我的代码如下:
library(lfe)
my_data=read.csv("path_to//data.csv")
attach(data.frame(my_data))
下面是非常的慢行:
my_data$col <- factor(my_data$col)
如果你知道你正在创造的因素的水平,这可以大大加快速度。观察:
library(microbenchmark)
set.seed(237)
test <- sample(letters, 10^7, replace = TRUE)
microbenchmark(noLevels = factor(test), withLevels = factor(test, levels = letters), times = 20)
Unit: milliseconds
expr min lq mean median uq max neval cld
noLevels 523.6078 545.3156 653.4833 696.4768 715.9026 862.2155 20 b
withLevels 248.6904 270.3233 325.0762 291.6915 345.7774 534.2473 20 a
为了获得 OP 情况的级别,我们只需调用 unique
。
myLevels <- unique(my_data$col)
my_data$col <- factor(my_data$col, levels = myLevels)
还有一个由 Kevin Ushley (Fast factor generation with Rcpp) 编写的 Rcpp
产品。我对代码进行了一些修改,假设人们会知道级别 先验 的情况。来自参考网站的函数是 RcppNoLevs
,修改后的 Rcpp 函数在下面的基准测试中是 RcppWithLevs
。
microbenchmark(noLevels = factor(test),
withLevels = factor(test, levels = letters),
RcppNoLevs = fast_factor(test),
RcppWithLevs = fast_factor_Levs(test, letters), times = 20)
Unit: milliseconds
expr min lq mean median uq max neval cld
noLevels 571.5482 609.6640 672.1249 645.4434 704.4402 1032.7595 20 d
withLevels 275.0570 294.5768 318.7556 309.2982 342.8374 383.8741 20 c
RcppNoLevs 189.5656 203.3362 213.2624 206.9281 215.6863 292.8997 20 b
RcppWithLevs 105.7902 111.8863 120.0000 117.9411 122.8043 173.8130 20 a
这里是修改后的 Rcpp 函数,假设一个人将级别作为参数传递:
#include <Rcpp.h>
using namespace Rcpp;
template <int RTYPE>
IntegerVector fast_factor_template_Levs( const Vector<RTYPE>& x, const Vector<RTYPE>& levs) {
IntegerVector out = match(x, levs);
out.attr("levels") = as<CharacterVector>(levs);
out.attr("class") = "factor";
return out;
}
// [[Rcpp::export]]
SEXP fast_factor_Levs( SEXP x, SEXP levs) {
switch( TYPEOF(x) ) {
case INTSXP: return fast_factor_template_Levs<INTSXP>(x, levs);
case REALSXP: return fast_factor_template_Levs<REALSXP>(x, levs);
case STRSXP: return fast_factor_template_Levs<STRSXP>(x, levs);
}
return R_NilValue;
}