Быстрая фильтрация данных. - PullRequest
0 голосов
/ 12 мая 2018

У меня есть случай, когда я хочу быстро фильтровать таблицы данных повторно.У меня такое ощущение, что если я использую простой фильтр, такой как df[val>0,], сканирование будет O(N), но если я просто установлю поле val в качестве ключа, то я смогу фильтровать быстрее, но не уверен, как это сделать.В качестве примера я сделал следующее:

отсортированный data.table

df_sort = data.table(id = seq(1, 100000), val = runif(100000, 0, 1))
setkeyv(df_sort, c('val')

обычный data.table

df = data.table(id = seq(1, 100000), val = runif(100000, 0, 1))

Случай, который я хочу сделать:найти уникальные id для val > tol.Используя rbenchmark я сделал следующее

benchmark('raw' = { l = length(unique(df$id[df$val >=0.1]))}, 'sort' = {l = length(unique(df_sort$id[df_sort$val >=0.1]))}, replications=20)

результат, который я получил, не показал разницы между ними.

  test replications elapsed relative user.self sys.self user.child sys.child
1  raw           20   0.440    1.005     0.494        0          0         0
2 sort           20   0.438    1.000     0.540        0          0         0

Может ли кто-нибудь дать несколько советов о том, как этого добиться?Это вообще возможно?

РЕДАКТИРОВАТЬ

Попробовал предложение в комментарии, вернулся хуже.Не уверен почему.

benchmark('raw' = { l = df[val >=0.1, uniqueN(id)]}, 'sort' = {l = df_sort[val >=0.1, uniqueN(id)]}, replications=200)

test replications elapsed relative user.self sys.self user.child sys.child
1  raw          200   0.770    1.000     0.928        0          0         0
2 sort          200   1.361    1.768     1.691        0          0         0

1 Ответ

0 голосов
/ 13 мая 2018

ОК, вот некоторые правильные тесты. Единицы времени в ваших двух тестах, вероятно, не совпадают.

library(rbenchmark)
library(data.table)

set.seed(42)
#using sample to rule out ALTREP influence
df <- data.table(id = sample(1e7, replace = TRUE), val = runif(1e7, 0, 1))
df_sort <- copy(df)
setkey(df_sort, val)

benchmark('raw' = { l = length(unique(df$id[df$val >=0.1]))}, 
          'sort' = {l = length(unique(df_sort$id[df_sort$val >=0.1]))},
          'raw_DT' = {df[val >=0.1, uniqueN(id)]},
          'sort_DT' = {df_sort[val >=0.1, uniqueN(id)]},
          'raw_DT_length' = {df[val >=0.1, length(unique(id))]},
          replications=20, order = "relative")
#           test replications elapsed relative user.self sys.self user.child sys.child
#3        raw_DT           20   9.422    1.000     8.742    0.680          0         0
#4       sort_DT           20   9.617    1.021     8.901    0.697          0         0
#2          sort           20  15.237    1.617    14.016    1.222          0         0
#1           raw           20  15.313    1.625    14.128    1.190          0         0
#5 raw_DT_length           20  16.719    1.774    15.473    1.233          0         0


benchmark(unique_length = length(unique(df$id)), 
          uniqueN = uniqueN(df$id),
          replications=20, order = "relative")
#           test replications elapsed relative user.self sys.self user.child sys.child
#2       uniqueN           20   7.708    1.000     7.340    0.368          0         0
#1 unique_length           20  15.683    2.035    14.765    0.920          0         0

benchmark(subset_base = df$id[df$val >=0.1], 
          subset_data.table = df[val >=0.1, id],
          subset_data.table_keyed = df_sort[val >=0.1, id],
          replications=20, order = "relative")
#                     test replications elapsed relative user.self sys.self user.child sys.child
#1             subset_base           20   1.546    1.000     1.206    0.340          0         0
#3 subset_data.table_keyed           20   2.360    1.527     2.046    0.314          0         0
#2       subset_data.table           20   2.493    1.613     2.184    0.309          0         0

Некоторые замечания: ваш базовый подход R вообще не использует возможности data.table. Логические операторы Base R не используют сортировку; это простое векторное сканирование. uniqueN бьет length(unique()) как следует. Подмножество data.table не оптимизировано для >= (пока). Если вы действительно хотите улучшить время, вы должны написать uniqueNSubset функцию с Rcpp, которая использует сортируемые данные (я бы также отсортировал идентификаторы).

> sessionInfo()
R version 3.5.0 (2018-04-23)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS High Sierra 10.13.4

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib

locale:
[1] de_DE.UTF-8/de_DE.UTF-8/de_DE.UTF-8/C/de_DE.UTF-8/de_DE.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] data.table_1.11.2 rbenchmark_1.0.0 

loaded via a namespace (and not attached):
[1] compiler_3.5.0 tools_3.5.0 
...