爲了記錄(自從你提到過「Rcpp」),我在C級添加了一個方法。加速大約是7倍;可能會有更好/更快的解決方案,但是 - 與評論意見一致 - 可能更適合規劃不同的方法,而不是試圖以特定的部分儘快製作出特定的部分,特別是如果難以獲得顯着的加速。
library(inline)
ff <- cfunction(sig = c(R_df = "data.frame"), body = '
R_len_t nr = LENGTH(VECTOR_ELT(R_df, 0)), nc = LENGTH(R_df);
SEXP ans;
PROTECT(ans = allocVector(VECSXP, nr));
for(int i = 0; i < nr; i++) {
SET_VECTOR_ELT(ans, i, allocVector(VECSXP, nc));
setAttrib(VECTOR_ELT(ans, i), R_NamesSymbol,
getAttrib(R_df, R_NamesSymbol));
}
setAttrib(ans, R_NamesSymbol, getAttrib(R_df, R_RowNamesSymbol));
for(int i = 0; i < nc; i++) {
SEXP tmp;
PROTECT(tmp = coerceVector(VECTOR_ELT(R_df, i),
TYPEOF(VECTOR_ELT(R_df, i))));
switch(TYPEOF(tmp)) {
case LGLSXP:
case INTSXP: {
R_len_t *ptmp = INTEGER(tmp);
for(int j = 0; j < nr; j++)
SET_VECTOR_ELT(VECTOR_ELT(ans, j), i,
ScalarInteger(ptmp[j]));
break;
}
case REALSXP: {
double *ptmp = REAL(tmp);
for(int j = 0; j < nr; j++)
SET_VECTOR_ELT(VECTOR_ELT(ans, j), i,
ScalarReal(ptmp[j]));
break;
}
case STRSXP: {
for(int j = 0; j < nr; j++)
SET_VECTOR_ELT(VECTOR_ELT(ans, j), i,
ScalarString(STRING_ELT(tmp, j)));
break;
}
}
UNPROTECT(1);
}
UNPROTECT(1);
return(ans);
')
ff(a)
#$p1
#$p1$x
#[1] 1
#
#$p1$y
#[1] "k"
#
#
#$p2
#$p2$x
#[1] 2
#
#$p2$y
#[1] "o"
#
#
#$p3
#$p3$x
#[1] 3
#
#$p3$y
#[1] "l"
而且隨着你那被證明是快速的方法(在評論中提到的)比較:
identical(setNames(do.call(Map,
c(function(...)
"names<-"(list(...), colnames(a)), a)),
row.names(a)),
ff(a))
#[1] TRUE
而且在更大的 「data.frame」:
set.seed(101)
DF = do.call(cbind.data.frame,
replicate(4, cbind.data.frame(x = I(sample(letters, 1e5, T)),
y = runif(1e5),
z = sample(1e5)), simplify = F))
names(DF) = make.unique(names(DF), "")
identical(setNames(do.call(Map,
c(function(...)
"names<-"(list(...), colnames(DF)), DF)),
row.names(DF)),
ff(DF))
#[1] TRUE
library(microbenchmark)
microbenchmark(ans1 = setNames(do.call(Map,
c(function(...)
"names<-"(list(...), colnames(DF)),
DF)),
row.names(DF)),
ff(DF),
times = 10)
#Unit: milliseconds
# expr min lq median uq max neval
# ans1 3504.1825 3862.4333 3931.0853 4063.691 4162.9370 10
# ff(DF) 143.0398 340.6897 365.5144 404.475 498.3854 10
燦解決方案在列表中有不同的/沒有名字?你真的想把'x'值強制轉換成字符嗎? PS:你爲什麼想要這個列表結構? data.frame是這個數據的一個更自然的結構。 – Roland
對不起,我的錯,他們應該是數字! –
'split(a,rownames(a))'是另一種選擇。 – thelatemail