From Simio and Simulation: Modeling, Analysis, Applications
Looking at the results of Stats::Fit, an Exponential or Lognormal distribution could be appropriate for these data based on the “eyeball test” and the output of the goodness-of-fit tests.
The Exponential distribution would be the first one to try for modeling interarrival times in Simio. The expression would be:
2.+Random.Exponential(9.92)
(Lognormal: 2.+Random.Lognormal(1.72, 1.28))
Looking at the results of Stats::Fit, an Exponential or Lognormal distribution could be appropriate for these data based on the “eyeball test” and the output of the goodness-of-fit tests. Based on the p-value from the goodness-of-fit tests, I would recommend the lognomral distribution.
For importing the Lognormal distribution into Simio for modeling call duration, the expression would be:
2.76+Random.Lognormal(1.84, 0.717)
For this problem, the data were modeled as a discrete distribution with Binomial and Poisson distributions looking to be appropriate.
Of these, the Binomial distribution has a slightly higher goodness-of-fit p-value. The P-P Plot in this case is too close to differentiate between the two.
For importing the Binomial distribution into Simio for modeling call center support staff needed, the expression would be:
Random.Binomial(0.185, 16.)
The CDF for a continuous uniform distribution between real numbers a and b is given by:
\[ F(x) = \begin{cases} 0, x \lt a \\ \frac{x - a}{b - a} , a \le x \le b \\ 1, x \gt b \end{cases} \]
Using the inverse transform method,
\[ F(X) = (X - a)/(b - a) = R \]
or \[ R = (X - a)/(b - a) \]
Solving for X:
$ R(b - a) = X - a $
$ a + (b - a)R = X $ or
\[ X = a + (b - a)R \]
The Weibull distribution a model for time failure for machines or electronic components.
\[ f(x) = \begin{cases} \frac{\beta}{\sigma^\beta}x^{\beta-1}e^{-(x/\sigma)^\beta}, x \ge 0 \\ \frac{x - a}{b - a} , a \le x \le b \\ 0, otherwise \end{cases} \]
To generate a Weibull variate:
Determine the CDF which is given by:
\[ F(X) = 1 - e^{-(x/\sigma)^\beta} \space\space where \space \space x \ge 0 \]
Set $F(X) = 1 - e{-(X/)} = R $
or
\[ R = 1 - e^{-(X/\sigma)^\beta} \]
\[ e^{-(X/\sigma)^\beta} = 1 - R \]
\[ -(X/\sigma)^\beta = ln(1 - R) \] \[ (X/\sigma)^\beta = -ln(1 - R) \] \[ (X)^\beta = \sigma[-ln(1 - R)] \] Giving us X in terms of R:
\[ X = \sigma[-ln(1 - R)]^{1\beta} \]
# oats
oats <- data.frame(type = 'oats',
qty=c(0, 0.5, 1.0, 1.5, 2.0, 3, 4, 5, 7.5, 10),
prob=c(0.05, 0.07, 0.09, 0.11, 0.15, 0.25, 0.1, 0.09, 0.06, 0.03))
oats$cumulative_prob <- cumsum(oats$prob)
# peas
peas <- data.frame(type = 'peas',
qty = c(0,0.5,1,1.5,2,3),
prob= c(0.1,0.2,0.2,0.3,0.1,0.1))
peas$cumulative_prob <- cumsum(peas$prob)
# beans
beans <- data.frame(type = 'beans',
qty= c(0,1,3,4.5),
prob = c(0.2,0.4,0.3,0.1))
beans$cumulative_prob <- cumsum(beans$prob)
# barley
barley <- data.frame(type = 'barley',
qty=c(0,0.5,1,3.5),
prob = c(0.2,0.4,0.3,0.1))
barley$cumulative_prob <- cumsum(barley$prob)
# Combine them all into single data frame
crop_prob_table <- rbind(oats, peas, beans, barley)
crop_prob_table$type <- as.character(crop_prob_table$type)
# create the crop reference data for acquisition cose and sale price for each crop
crop_data <-
data.frame(
crop = c("oats", "peas", "beans", "barley"),
wac = c(1.05, 3.17, 1.99, 0.95), # acquisition cost
sell = c(1.29, 3.76, 2.23, 1.65), # selling price
crop_demand = 0, # simulated daily demand for the given crop; uniform distribution
cost = 0, # crop simulated cost (wac * simulated demand)
revenue = 0, # crop simulated revenue value (selling price * simulated demand)
profit = 0, # crop simulated profit value (selling price * simulated demand)
stringsAsFactors = F)
## Function to simulate a crop season
sim_crop_season <- function(run_num, days) {
# replicate each crop entry by the number of days in the season to simulate
crop__sim <- as.data.frame(lapply(crop_data, rep, days))
# set the iteration number
crop__sim$run_num <- run_num
crop__sim$crop <- as.character(crop__sim$crop) # convert from factor to character
# daily daily demain as a uniform random number
crop__sim$daily_demand <- replicate(nrow(crop__sim), runif(1))
# set the day number
crop__sim$day <- ceiling(seq(1:nrow(crop__sim))/4)
for (i in 1:nrow(crop__sim)) {
crop__sim$crop_demand[i] <-subset(crop_prob_table, type == crop__sim$crop[i] &
cumulative_prob >= crop__sim$daily_demand[i],
select=qty)[1,1]
crop__sim$cost[i] <- crop__sim$crop_demand[i] * crop__sim$wac[i]
crop__sim$revenue[i] <- crop__sim$crop_demand[i] * crop__sim$sell[i]
crop__sim$profit[i] <- crop__sim$revenue[i] - crop__sim$cost[i]
}
return (crop__sim)
}
# calcualte for one season
sim1 <- sim_crop_season(1, 90)
| crop | wac | sell | crop_demand | cost | revenue | profit | run_num | daily_demand | day |
|---|---|---|---|---|---|---|---|---|---|
| oats | 1.05 | 1.29 | 4.0 | 4.200 | 5.160 | 0.960 | 1 | 0.7883051 | 1 |
| peas | 3.17 | 3.76 | 1.0 | 3.170 | 3.760 | 0.590 | 1 | 0.4089769 | 1 |
| beans | 1.99 | 2.23 | 3.0 | 5.970 | 6.690 | 0.720 | 1 | 0.8830174 | 1 |
| barley | 0.95 | 1.65 | 3.5 | 3.325 | 5.775 | 2.450 | 1 | 0.9404673 | 1 |
| oats | 1.05 | 1.29 | 0.0 | 0.000 | 0.000 | 0.000 | 1 | 0.0455565 | 2 |
| peas | 3.17 | 3.76 | 1.5 | 4.755 | 5.640 | 0.885 | 1 | 0.5281055 | 2 |
sim <- rbindlist(lapply(1:30, function(x) sim_crop_season(x, 90))) %>% as.data.frame()
sim %>%
group_by(run_num) %>% summarise(mean_profit = sum(profit)/90,
mean_cost = sum(cost)/90,
mean_revenue = sum(revenue)/90) -> agg
## Warning: package 'bindrcpp' was built under R version 3.3.3
Walther doesn’t appear to be making much money with this approach
| run_num | mean_profit | mean_cost | mean_revenue |
|---|---|---|---|
| 1 | 2.454500 | 10.92189 | 13.37639 |
| 2 | 2.413889 | 10.52683 | 12.94072 |
| 3 | 2.293889 | 10.73489 | 13.02878 |
| 4 | 2.528722 | 11.60683 | 14.13556 |
| 5 | 2.418389 | 10.86444 | 13.28283 |
| 6 | 2.432556 | 11.21150 | 13.64406 |
| 7 | 2.419333 | 11.49667 | 13.91600 |
| 8 | 2.477333 | 11.42444 | 13.90178 |
| 9 | 2.568556 | 11.71267 | 14.28122 |
| 10 | 2.475889 | 11.30211 | 13.77800 |
| 11 | 2.387056 | 11.33761 | 13.72467 |
| 12 | 2.321389 | 10.73328 | 13.05467 |
| 13 | 2.513111 | 11.42172 | 13.93483 |
| 14 | 2.369778 | 10.63772 | 13.00750 |
| 15 | 2.500056 | 11.21778 | 13.71783 |
| 16 | 2.566389 | 11.62422 | 14.19061 |
| 17 | 2.423222 | 11.32961 | 13.75283 |
| 18 | 2.480222 | 11.58050 | 14.06072 |
| 19 | 2.416778 | 11.23383 | 13.65061 |
| 20 | 2.363722 | 11.18600 | 13.54972 |
| 21 | 2.387500 | 10.46561 | 12.85311 |
| 22 | 2.477111 | 11.39967 | 13.87678 |
| 23 | 2.315889 | 10.79744 | 13.11333 |
| 24 | 2.368667 | 11.19406 | 13.56272 |
| 25 | 2.352778 | 10.75539 | 13.10817 |
| 26 | 2.476556 | 11.90239 | 14.37894 |
| 27 | 2.489167 | 11.65811 | 14.14728 |
| 28 | 2.547111 | 11.48178 | 14.02889 |
| 29 | 2.290222 | 10.42800 | 12.71822 |
| 30 | 2.571167 | 11.33056 | 13.90172 |
# Run t-tests on the mean values:
t.test(agg$mean_profit)
##
## One Sample t-test
##
## data: agg$mean_profit
## t = 164.01, df = 29, p-value < 2.2e-16
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## 2.406313 2.467083
## sample estimates:
## mean of x
## 2.436698
t.test(agg$mean_cost)
##
## One Sample t-test
##
## data: agg$mean_cost
## t = 152.02, df = 29, p-value < 2.2e-16
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## 11.03345 11.33438
## sample estimates:
## mean of x
## 11.18392
t.test(agg$mean_revenue)
##
## One Sample t-test
##
## data: agg$mean_revenue
## t = 159.72, df = 29, p-value < 2.2e-16
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## 13.44620 13.79503
## sample estimates:
## mean of x
## 13.62062