Случайные числа в столбце на основе значения другого столбца - PullRequest
0 голосов
/ 11 января 2019

Добрый день всем,

Я борюсь с созданием столбца, который бы заполнял значения, используя функцию создания значения случайного значения, которая принимает значение другого столбца в качестве аргумента.

Немного контекста - у меня есть таблица данных с временем выполнения в столбце:

library(data.table)

dt <- data.table(Item = rep(123456,each = 1000), LT = rnorm(1000,mean = 10, sd = 3))

и функция:

rand_ddlt_norm <- function(Lt,mean,sd){
  sign(Lt) * ( sum( rnorm( floor(abs(Lt)), mean, sd) ) +
                 rnorm(1, mean, sd) * ( abs(Lt)%%1) )
}

Вышеуказанная функция предназначена для расчета спроса в течение времени выполнения заказа для каждой строки.

К сожалению, я не могу этого сделать:

dt[,ddlt := rand_ddlt_norm(LT, mean = 100, sd = 30)]

потому что все строки будут заполнены одинаковым номером.

Я, очевидно, мог бы поставить это в цикл, но для 10 000 итераций, более 20 000 продуктов и многочисленных типов распределения время вычислений становится нелепым.

Буду любезно приветствовать любые предложения о том, как можно оптимизировать этот код без выполнения цикла.

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Я бы предложил вам векторизовать вашу функцию напрямую:

rand_ddlt_norm_vec <- function(Lt,mean,sd){
  sign(Lt) * ( rowSums( t(sapply(1:length(Lt),function(x){rnorm(floor(abs(Lt)),mean,sd)})))  +
                 rnorm(length(Lt), mean, sd) * ( abs(Lt)%%1) )
}

Где Lt теперь вектор. Здесь

t(sapply(1:length(Lt),function(x){rnorm(floor(abs(Lt)),mean,sd)}))

создать матрицу с тем же номером строки, что и Lt, и таким же номером столбца, что и floor(abs(Lt)). Затем вы используете Rowsum, чтобы получить вектор.

Для сравнения с решением JdeMello:

rand_ddlt_norm_vec2 <- Vectorize(rand_ddlt_norm)

library(microbenchmark)
library(data.table)

dt <- data.table(Item = rep(123456,each = 10000), LT = rnorm(10000,mean = 10, sd = 3))

    microbenchmark(
      denis = function(){dt[,ddlt := rand_ddlt_norm_vec(LT, mean = 100, sd = 30)]},
      jdeMello = function(){dt[,ddlt := rand_ddlt_norm_vec2(LT, mean = 100, sd = 30)]}
    )

Unit: nanoseconds
     expr min lq  mean median uq  max neval cld
    denis   0  0  0.24      0  0    1   100   a
 jdeMello   0  0 25.88      0  0 2566   100   a

Это решение в 100 раз быстрее, чем решение JdeMello.

0 голосов
/ 11 января 2019

Используйте Vectorize() для векторизации вашей функции.

# data
library(data.table)

set.seed(1)

dt <- data.table::data.table(Item = rep(123456,each = 1000), LT = rnorm(1000,mean = 10, sd = 3))

# def function
rand_ddlt_norm <- function(Lt,est11,est12){
  sign(Lt) * ( sum( rnorm( floor(abs(Lt)), est11, est12) ) +
                 rnorm(1, est11, est12) * ( abs(Lt)%%1) )
}

rand_ddlt_norm <- Vectorize(rand_ddlt_norm) # vectorize it

dt[,ddlt := rand_ddlt_norm(LT, 100,30)]

Результат:

> head(dt)
     Item        LT      ddlt
1: 123456  8.120639  845.6967
2: 123456 10.550930 1112.5837
3: 123456  7.493114  733.3808
4: 123456 14.785842 1516.8916
5: 123456 10.988523 1101.0449
6: 123456  7.538595  898.3760
...