我使用以下命令:
table(factor("list",levels=1:"n")
与“列表”:(例如)a = c(1,3,4,4,3)和levels = 1:5,也要考虑到2和5。对于真正大的数据集,我的代码似乎非常无效。有人知道一个隐藏的库或代码片段,使它更快吗?
a = c(1,3,4,4,3)
levels = 1:5
bvjxkvbb1#
我们可以从collapse中使用fnobs,这将是高效的
collapse
fnobs
library(collapse) fnobs(df, g = df$X1)
在base R中,tabulate的效率高于table
base R
tabulate
table
tabulate(df$X1) [1] 9 6 15 13 11 9 7 9 11 10
jecbmhm32#
我们也可以使用janitor::tabyl:
janitor::tabyl
library(janitor) df %>% tabyl(X1) %>% adorn_totals() X1 n percent 1 9 0.09 2 6 0.06 3 15 0.15 4 13 0.13 5 11 0.11 6 9 0.09 7 7 0.07 8 9 0.09 9 11 0.11 10 10 0.10 Total 100 1.00
mi7gmzs63#
这并不是你要找的,但也许你可以用这个:
library(dplyr) set.seed(8192) df <- data.frame(X1 = sample(1:10, 100, replace = TRUE)) df %>% count(X1)
退货
X1 n 1 1 9 2 2 6 3 3 15 4 4 13 5 5 11 6 6 9 7 7 7 8 8 9 9 9 11 10 10 10
如果需要计算更多数字(包括缺失的数字),可以使用
library(tidyr) library(dplyr) df2 <- data.frame(X1 = 1:12) df %>% count(X1) %>% right_join(df2, by="X1") %>% mutate(n = replace_na(n, 0L))
得到
X1 n 1 1 9 2 2 6 3 3 15 4 4 13 5 5 11 6 6 9 7 7 7 8 8 9 9 9 11 10 10 10 11 11 0 12 12 0
dfuffjeb4#
TL;DR赢家是base::tabulate。总而言之,基本目标是性能,所以我准备了一个microbenchmark的所有提供的解决方案。我使用小和大向量,两种不同的场景。对于collapse包在我的机器上,我必须下载最新的Rcpp包1.0.7(以抑制崩溃)。甚至由我添加Rcpp solution是慢于base::tabulate。
base::tabulate
microbenchmark
Rcpp
suppressMessages(library(janitor)) suppressMessages(library(collapse)) suppressMessages(library(dplyr)) suppressMessages(library(cpp11)) # source https://stackoverflow.com/questions/31001392/rcpp-version-of-tabulate-is-slower-where-is-this-from-how-to-understand Rcpp::cppFunction('IntegerVector tabulate_rcpp(const IntegerVector& x, const unsigned max) { IntegerVector counts(max); for (auto& now : x) { if (now > 0 && now <= max) counts[now - 1]++; } return counts; }') set.seed(1234) a = c(1,3,4,4,3) levels = 1:5 df <- data.frame(X1 = a) microbenchmark::microbenchmark(tabulate_rcpp = {tabulate_rcpp(df$X1, max(df$X1))}, base_table = {base::table(factor(df$X1, 1:max(df$X1)))}, stats_aggregate = {stats::aggregate(. ~ X1, cbind(df, n = 1), sum)}, graphics_hist = {hist(df$X1, plot = FALSE, right = FALSE)[c("breaks", "counts")]}, janitor_tably = {adorn_totals(tabyl(df, X1))}, collapse_fnobs = {fnobs(df, df$X1)}, base_tabulate = {tabulate(df$X1)}, dplyr_count = {count(df, X1)}) #> Unit: microseconds #> expr min lq mean median uq max #> tabulate_rcpp 2.959 5.9800 17.42326 7.9465 9.5435 883.561 #> base_table 48.524 59.5490 72.42985 66.3135 78.9320 153.216 #> stats_aggregate 829.324 891.7340 1069.86510 937.4070 1140.0345 2883.025 #> graphics_hist 148.561 170.5305 221.05290 188.9570 228.3160 958.619 #> janitor_tably 6005.490 6439.6870 8137.82606 7497.1985 8283.3670 53352.680 #> collapse_fnobs 14.591 21.9790 32.63891 27.2530 32.6465 417.987 #> base_tabulate 1.879 4.3310 5.68916 5.5990 6.6210 16.789 #> dplyr_count 1832.648 1969.8005 2546.17131 2350.0450 2560.3585 7210.992 #> neval #> 100 #> 100 #> 100 #> 100 #> 100 #> 100 #> 100 #> 100 df <- data.frame(X1 = sample(1:5, 1000, replace = TRUE)) microbenchmark::microbenchmark(tabulate_rcpp = {tabulate_rcpp(df$X1, max(df$X1))}, base_table = {base::table(factor(df$X1, 1:max(df$X1)))}, stats_aggregate = {stats::aggregate(. ~ X1, cbind(df, n = 1), sum)}, graphics_hist = {hist(df$X1, plot = FALSE, right = FALSE)[c("breaks", "counts")]}, janitor_tably = {adorn_totals(tabyl(df, X1))}, collapse_fnobs = {fnobs(df, df$X1)}, base_tabulate = {tabulate(df$X1)}, dplyr_count = {count(df, X1)}) #> Unit: microseconds #> expr min lq mean median uq max #> tabulate_rcpp 4.847 8.8465 10.92661 10.3105 12.6785 28.407 #> base_table 83.736 107.2040 121.77962 118.8450 129.9560 184.427 #> stats_aggregate 1027.918 1155.9205 1338.27752 1246.6205 1434.8990 2085.821 #> graphics_hist 209.273 237.8265 274.60654 258.9260 300.3830 523.803 #> janitor_tably 5988.085 6497.9675 7833.34321 7593.3445 8422.6950 13759.142 #> collapse_fnobs 26.085 38.6440 51.89459 47.8250 57.3440 333.034 #> base_tabulate 4.501 6.7360 8.09408 8.2330 9.2170 11.463 #> dplyr_count 1852.290 2000.5225 2374.28205 2145.9835 2516.7940 4834.544 #> neval #> 100 #> 100 #> 100 #> 100 #> 100 #> 100 #> 100 #> 100
由reprex package(v2.0.0)于2021年8月1日创建
wa7juj8i5#
使用aggregate的基本R期权(从@Martin Gal借用df)
aggregate
df
> aggregate(. ~ X1, cbind(df, n = 1), sum) X1 n 1 1 9 2 2 6 3 3 15 4 4 13 5 5 11 6 6 9 7 7 7 8 8 9 9 9 11 10 10 10
另一个选项是使用hist
hist
> hist(df$X1, plot = FALSE, right = FALSE)[c("breaks", "counts")] $breaks [1] 1 2 3 4 5 6 7 8 9 10 $counts [1] 9 6 15 13 11 9 7 9 21
drnojrws6#
这里还有一个:summarytools数据来自Martin Gal!非常感谢:
summarytools
library(summarytools) set.seed(8192) df <- data.frame(X1 = sample(1:10, 100, replace = TRUE)) summarytools::freq(df$X1, cumul=FALSE)
输出:
Freq % Valid % Total ----------- ------ --------- --------- 1 9 9.00 9.00 2 6 6.00 6.00 3 15 15.00 15.00 4 13 13.00 13.00 5 11 11.00 11.00 6 9 9.00 9.00 7 7 7.00 7.00 8 9 9.00 9.00 9 11 11.00 11.00 10 10 10.00 10.00 <NA> 0 0.00 Total 100 100.00 100.00
0wi1tuuw7#
如果需要table()更快的替代方法,包括交叉制表,则collapse::qtab()(自v1.8.0(2022年5月)起可用)是可靠且明显更快的替代方法。fcount()也可用于单变量情况,并返回data.frame。
table()
collapse::qtab()
fcount()
library(collapse) # > v1.8.0, and > 1.9.0 for fcount() library(microbenchmark) v = sample(10000, 1e6, TRUE) microbenchmark(qtab(v, sort = FALSE), fcount(v), tabulate(v), times = 10) Unit: milliseconds expr min lq mean median uq max neval qtab(v, sort = FALSE) 1.911707 1.945245 2.002473 1.963654 2.027942 2.207891 10 fcount(v) 1.885549 1.906746 1.978894 1.932310 2.103997 2.138027 10 tabulate(v) 2.321543 2.323716 2.333839 2.328206 2.334499 2.372506 10 v2 = sample(10000, 1e6, TRUE) microbenchmark(qtab(v, v2), qtab(v, v2, sort = FALSE), table(v, v2), times = 10) Unit: milliseconds expr min lq mean median uq max neval qtab(v, v2) 45.61279 51.14840 74.16168 60.7761 72.86385 157.6501 10 qtab(v, v2, sort = FALSE) 41.30812 49.66355 57.02565 51.3568 54.69859 118.1289 10 table(v, v2) 281.60079 282.85273 292.48119 286.0535 288.19253 349.5513 10
话虽如此,就C代码而言,tabulate()的速度几乎和它的速度一样快,但它有一个明确的警告,那就是它根本不散列值,而是确定最大值并分配一个该长度的结果向量,将其用作计算值的表。
tabulate()
v[10] = 1e7L # Adding a random large value here length(tabulate(v)) [1] 10000000 length(table(v)) [1] 10001 length(qtab(v)) [1] 10001
因此,您得到的结果向量中包含699万个零,而您的性能会下降
microbenchmark(qtab(v, sort = FALSE), fcount(v), tabulate(v), times = 10) Unit: milliseconds expr min lq mean median uq max neval qtab(v, sort = FALSE) 1.873249 1.900473 1.966721 1.923064 2.064186 2.126588 10 fcount(v) 1.829338 1.850330 1.926676 1.880199 2.021013 2.057667 10 tabulate(v) 4.207789 4.357439 5.066296 4.417012 4.558216 10.347744 10
有鉴于此,qtab()实际上确实散列了每个值并实现了这样的性能,这一事实相当了不起。
qtab()
7条答案
按热度按时间bvjxkvbb1#
我们可以从
collapse
中使用fnobs
,这将是高效的在
base R
中,tabulate
的效率高于table
jecbmhm32#
我们也可以使用
janitor::tabyl
:mi7gmzs63#
这并不是你要找的,但也许你可以用这个:
退货
如果需要计算更多数字(包括缺失的数字),可以使用
得到
dfuffjeb4#
TL;DR赢家是
base::tabulate
。总而言之,基本目标是性能,所以我准备了一个
microbenchmark
的所有提供的解决方案。我使用小和大向量,两种不同的场景。对于collapse
包在我的机器上,我必须下载最新的Rcpp
包1.0.7(以抑制崩溃)。甚至由我添加Rcpp solution是慢于base::tabulate
。由reprex package(v2.0.0)于2021年8月1日创建
wa7juj8i5#
使用
aggregate
的基本R期权(从@Martin Gal借用df
)另一个选项是使用
hist
drnojrws6#
这里还有一个:
summarytools
数据来自Martin Gal!非常感谢:
输出:
0wi1tuuw7#
如果需要
table()
更快的替代方法,包括交叉制表,则collapse::qtab()
(自v1.8.0(2022年5月)起可用)是可靠且明显更快的替代方法。fcount()
也可用于单变量情况,并返回data.frame。话虽如此,就C代码而言,
tabulate()
的速度几乎和它的速度一样快,但它有一个明确的警告,那就是它根本不散列值,而是确定最大值并分配一个该长度的结果向量,将其用作计算值的表。因此,您得到的结果向量中包含699万个零,而您的性能会下降
有鉴于此,
qtab()
实际上确实散列了每个值并实现了这样的性能,这一事实相当了不起。