يبدو أن التنفيذ الجديد لـ nest()
و unnest()
قد أدى إلى تباطؤ كبير ، مقارنة بالإصدار السابق tidyR
ربما المشكلة تتعلق بحجم التخصيص المسبق؟
في هذه الحالة ، يجب أن يكون num_rows
كبيرًا لملاحظة التباطؤ. انظر مقتطف الرمز أدناه.
num_rows <- 100000
x <- dplyr::tibble(first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1))
before <- Sys.time()
y <- dplyr::tibble(first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1)) %>%
tidyr::nest(second_and_third = c(second, third)) %>%
tidyr::unnest(second_and_third)
after <- Sys.time()
if(length(which(x != y)) != 0){
stop("nest() and unnest() procedure results in corrupted data!")
}
cat(paste("Execution Time:",difftime(after,before,units="secs"),"seconds"))
على نظامي:
Execution Time: 61.2449209690094 seconds
لقد اختبرت هذا مع tidyR 0.8.3
:
num_rows <- 100000
x <- dplyr::tibble(first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1))
before <- Sys.time()
y <- dplyr::tibble(first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1)) %>%
tidyr::nest(second_and_third = c(second, third)) %>%
tidyr::unnest()
after <- Sys.time()
if(length(which(x != y)) != 0){
stop("nest() and unnest() procedure results in corrupted data!")
}
cat(paste("Execution Time:",difftime(after,before,units="secs"),"seconds"))
وهناك رأيت
Execution Time: 5.78480935096741 seconds
إبطاء بمقدار 10.587x
من الجدير بالذكر أن nest_legacy()
و unnest_legacy()
مازالا سريعين:
num_rows <- 100000
x <- dplyr::tibble(first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1))
before <- Sys.time()
y <- dplyr::tibble(first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1)) %>%
tidyr::nest_legacy(second_and_third = c(second, third)) %>%
tidyr::unnest_legacy()
after <- Sys.time()
if(length(which(x != y)) != 0){
stop("nest() and unnest() procedure results in corrupted data!")
}
cat(paste("Execution Time:",difftime(after,before,units="secs"),"seconds"))
على جهازي
Execution Time: 3.19051384925842 seconds
لذلك ، بالنسبة لكود الأداء ، يمكن للمرء دائمًا استخدام وظائف legacy()
. أود أن أقترح إصلاح هذا للإصدار الرئيسي التالي ، وتوجيه الأشخاص لاستخدام وظائف legacy()
لتجنب التباطؤ غير المتوقع.
أنا أيضا التعليقات ليست مفيدة جدا. يرجى فقط النقر فوق زر الإعجاب بدلاً من ذلك.
تم حل معظم المشاكل هنا في إصدار التطوير من vctrs. كانت المشكلة بشكل أساسي مع unnest()
(حقًا ، unchop()
). راجع r-lib / vctrs # 530 لمزيد من المعلومات.
مع مثالك الدقيق:
# devtools::install_github("r-lib/vctrs")
library(tidyr)
num_rows <- 100000
x <- dplyr::tibble(
first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1)
)
before <- Sys.time()
y <- dplyr::tibble(
first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1)
) %>%
tidyr::nest(second_and_third = c(second, third)) %>%
tidyr::unnest(second_and_third)
after <- Sys.time()
if(length(which(x != y)) != 0){
stop("nest() and unnest() procedure results in corrupted data!")
}
cat(paste("Execution Time:",difftime(after,before,units="secs"),"seconds"))
#> Execution Time: 9.04665207862854 seconds
تم إنشاؤه في 2019-09-24 بواسطة حزمة reprex (v0.2.1)
أعتقد أننا يمكن أن نحصل على 1-2 ثانية أسرع مع r-lib / vctrs # 592.
وربما أكثر قليلاً من تطبيق C أصلي vec_recycle_common()
.
Reprex يقارن الوظائف الجديدة والقديمة مباشرةً:
library(tidyr)
num_rows <- 10000
df <- tibble(
first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1)
)
bench::mark(
new = df %>%
nest(second_and_third = c(second, third)) %>%
unnest(second_and_third),
old = df %>%
nest_legacy(second, third) %>%
unnest_legacy(data)
)
#> Warning: Some expressions had a GC in every iteration; so filtering is disabled.
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 new 906ms 906ms 1.10 3.6MB 27.6
#> 2 old 384ms 404ms 2.48 2.98MB 24.8
تم إنشاؤه في 2019-11-13 بواسطة حزمة reprex (v0.3.0)
لذلك تم الآن حل أسوأ فجوة في الأداء ، على الرغم من أنه من الواضح أنه سيكون من الأفضل القيام بعمل أفضل من الإصدار السابق (على الرغم من أن الإصدار الجديد أكثر عمومية ، لذا فليس من المستغرب أن يكون أبطأ قليلاً حاليًا). يُظهر التوصيف 15٪ من وقت التشغيل بدءًا من drop_null()
، و 70٪ من vec_rbind()
لذا كما يقترح DavisVaughan ، فإن vctrs هي المكان الواضح لمتابعة تحسين الأداء .
من الناحية النظرية ، هناك فوائد من r-lib / vctrs # 592
library(tidyr)
num_rows <- 10000
tbl <- tibble(
first = 1:num_rows,
second = 5:(num_rows+5-1),
third = 7:(num_rows+7-1)
)
tbl_nest <- tbl %>%
nest(second_and_third = c(second, third))
df_nest <- as.data.frame(tbl_nest)
df_nest$second_and_third <- lapply(df_nest$second_and_third, as.data.frame)
bench::mark(
tibble_new = unnest(tbl_nest, second_and_third),
tibble_old = unnest_legacy(tbl_nest, second_and_third),
dataframe_new = unnest(df_nest, second_and_third),
dataframe_old = unnest_legacy(df_nest, second_and_third),
iterations = 30
)
#> Warning: Some expressions had a GC in every iteration; so filtering is
#> disabled.
#> # A tibble: 4 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 tibble_new 622.2ms 698ms 1.37 1.43MB 22.7
#> 2 tibble_old 92.4ms 98.9ms 10.1 808.02KB 23.2
#> 3 dataframe_new 345.6ms 431.9ms 2.25 680.05KB 19.4
#> 4 dataframe_old 62.3ms 67.2ms 14.7 575.67KB 28.3
تم إنشاؤه في 2019-11-13 بواسطة حزمة reprex (الإصدار 0.3.0.9000)
Reprex أبسط قليلاً:
library(tidyr)
n <- 10000
df <- tibble(
g = 1:n,
y = rep(list(tibble(x = 1:5)), n)
)
bench::mark(
unnest(df, y),
unnest_legacy(df, y)
)
#> Warning: Some expressions had a GC in every iteration; so filtering is disabled.
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 unnest(df, y) 488.4ms 512.8ms 1.95 2.82MB 22.4
#> 2 unnest_legacy(df, y) 88.6ms 91.9ms 10.7 1.44MB 24.9
تم إنشاؤه في 2019-11-28 بواسطة حزمة reprex (v0.3.0)
تحديث تزايدي. مع فرع VCTRS الرئيسي بعد تضمين الفوائد الكبيرة من r-lib / vctrs # 825 والمزايا الصغيرة من r-lib / vctrs # 824
library(tidyr)
n <- 10000
df <- tibble(
g = 1:n,
y = rep(list(tibble(x = 1:5)), n)
)
bench::mark(
unnest(df, y),
unnest_legacy(df, y),
iterations = 50
)
#> Warning: Some expressions had a GC in every iteration; so filtering is disabled.
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 unnest(df, y) 204ms 297.5ms 3.39 3.38MB 14.0
#> 2 unnest_legacy(df, y) 48ms 73.6ms 13.4 1.25MB 11.6
تم إنشاؤه بتاريخ 2020-02-17 بواسطة حزمة reprex (v0.3.0)
لدي فكرة أخرى لتقليل هذا الأمر عن طريق نقل بعض تفاصيل التنفيذ باهظة الثمن tidyr::unchop()
إلى C
مع dev dplyr ، أرى الآن:
library(tidyr)
n <- 10000
df <- tibble(
g = 1:n,
y = rep(list(tibble(x = 1:5)), n)
)
bench::mark(
unnest(df, y),
unnest_legacy(df, y)
)
#> Warning: Some expressions had a GC in every iteration; so filtering is disabled.
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 unnest(df, y) 87.2ms 90.8ms 11.0 3.62MB 20.1
#> 2 unnest_legacy(df, y) 123.7ms 129.6ms 7.73 4.11MB 23.2
تم إنشاؤه بتاريخ 2020-04-22 بواسطة حزمة reprex (v0.3.0)
لذا فقد تباطأ unnest_legacy()
قليلاً ، لكن unnest()
أصبح الآن أسرع ، وأبطأ قليلاً من ذي قبل.
أعتقد أن هذا مكان جيد لمغادرته. يمكننا بالتأكيد العودة لتحسين الأداء في المستقبل ، لكنني أعتقد أن الدافع الأساسي الملحة قد تم حله الآن.
التعليق الأكثر فائدة
من الجدير بالذكر أن
nest_legacy()
وunnest_legacy()
مازالا سريعين:على جهازي
لذلك ، بالنسبة لكود الأداء ، يمكن للمرء دائمًا استخدام وظائف
legacy()
. أود أن أقترح إصلاح هذا للإصدار الرئيسي التالي ، وتوجيه الأشخاص لاستخدام وظائفlegacy()
لتجنب التباطؤ غير المتوقع.