Улучшение производительности подмножества data.table

Я запускаю большую симуляцию Монте-Карло и обнаружил, что поднастройка/поиск моих данных — самая медленная часть моего кода. Чтобы протестировать некоторые альтернативы, я сравнил производительность с фреймами данных, data.table и матрицей. Вот эталонный код:

library(data.table)
#install.packages('profvis')
library(profvis)
x.df = data.frame(a=sample(1:10,10000,replace=T), b=sample(1:10,10000,replace=T)) # set up a dataframe
x.dt = as.data.table(x.df) # a data.table
setkey(x.dt,a) # set key for faster searches
x.mat = as.matrix(x.df) # a matrix

profvis({
for (i in 1:10000) {
  # test simple subsetting
  xsubset.mat = x.mat[100:200,2]
  xsubset.df = x.df[100:200,2]
  xsubset.dt = x.dt[100:200,2]
  # test search preformance
  xsearch.mat = x.mat[which(x.df$a==10),2]
  xsearch.df = x.df[which(x.df$a==10),2]
  xsearch.dt = x.dt[.(10),2]
}
})

Вот мои результаты: Улучшение производительности подмножества data.table Если серьезно, мне нравится компактный синтаксис data.table, и мне интересно, можно ли что-то сделать, чтобы улучшить его производительность. По словам создателей, он должен быть сверхбыстрым. Я использую его неправильно?

подумайте об использовании пакета parallel для моделирования методом Монте-Карло, чтобы запустить код на нескольких ядрах.

DSGym 28.05.2019 21:08

Я мог бы понять более медленные подмножества, учитывая, что [i, j] может делать так много вещей в зависимости от выражения, что должны быть накладные расходы на начальные проверки. Более медленный поиск кажется мне странным.

Alexis 28.05.2019 22:33

Если ваш x.dt одинаков на протяжении этих многих итераций, а поиск/поиск выполняется для целых чисел, таких как a, просто предварительно вычислите подмножества и сохраните их в списке. bs = split(x.dt$b, x.dt$a) и доступ как bs[[1]] по мере необходимости.

Frank 29.05.2019 12:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
111
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После еще нескольких тестов я теперь понимаю проблему. Самый быстрый пакет зависит от того, выполняю ли я много маленьких поисков или один большой поиск. Кажется, что data.table имеет много накладных расходов на поиск, что делает его более подходящим для работы с одной огромной таблицей, а не для множества поисков по маленьким.

Рассмотрим следующий код и сравним с оригиналом:

# make a giant table, but search it only once:
x.df = data.frame(a=sample(1:10,100000000,replace=T), b=sample(1:10,100000000,replace=T))
x.dt = as.data.table(x.df)
setkey(x.dt,a)
x.mat = as.matrix(x.df)

profvis({
for (i in 1:1) {
  xsubset.mat = x.mat[100:200,2]
  xsubset.df = x.df[100:200,2]
  xsubset.dt = x.dt[100:200,2]

  xsearch.mat = x.mat[which(x.df$a==10),2]
  xsearch.df = x.df[which(x.df$a==10),2]
  xsearch.dt = x.dt[.(10),2]
}
})

Результаты: searching one big table

При поиске по небольшим наборам данных «время» не имеет большого значения. Даже если это займет «намного» больше времени, это все еще в наносекундах, так что никого это не волнует. data.table действительно имеет накладные расходы, когда речь идет о наносекундах. Тем не менее, время имеет значение только тогда, когда мы масштабируемся до миллисекунд/секунд/и т. д. — тогда оно становится болезненным, и именно тогда data.table сияет, и в первую очередь это идея, стоящая за ним. Никто не стал бы создавать пакет для повышения производительности за наносекунды в R

David Arenburg 29.05.2019 10:13

Следовательно, ваше утверждение «data.table имеет много накладных расходов на поиск» довольно бессмысленно. Вы должны протестировать большие наборы данных много раз (а не один раз), а затем посмотреть, сколько у них накладных расходов.

David Arenburg 29.05.2019 10:15

Другие вопросы по теме