Моделирование Монте-Карло (треугольное распределение) по строкам данных о затратах в формате CSV

У меня есть список csv, содержащий оценки затрат, где каждая строка содержит оценку нижнего (l), центрального (c) и верхнего (u) диапазона для каждой оценки позиции, которая подготовлена ​​в Excel пользователями, не являющимися R. Пример данных CSV, которые я прочитал в R, выглядит следующим образом:

         Item     l     c     u
        <chr> <int> <int> <int>
1 “CostItem1”  1500  1900  2600
2 “CostItem2”  2400  3200  4400
3 “CostItem3”   500  1000  1500

Каждая строка затем используется в треугольной функции распределения (библиотека (треугольник)) следующим образом в течение ряда итераций (в данном случае количество прогонов = 10000):

CostItem1 <- rtriangle(runs, l, u, c)

В настоящее время я вручную ввожу данные оценки диапазона для каждого элемента затрат (CostItem1, CostItem2 и т. Д.) В функции rtriangle.

У меня вопрос:

Как я могу создать функцию цикла или другой подход, чтобы сделать это прямо из файла CSV, когда он читается в R? Как новичок, я понятия не имею, как с этим справиться, и весь поиск в Google ничего не показал.

Затем данные элемента затрат объединяются в новый фрейм данных (TotalCostEstimate), который содержит 10000 симуляций, и каждая строка суммируется для предоставления смоделированных данных общих затрат (TotalCost):

 TotalCostEstimate<-data.frame(CostItem1 ,CostItem2 ,TotalCost=rowSums(x)) 

Отсюда данные могут быть построены и представлены для анализа и принятия решений. Для небольшого количества статей затрат ручной ввод не так уж и плох, но иногда у меня есть строки ›50, и я не хочу делать это 50+ раз !!

Большое спасибо, что нашли время посмотреть на это.


person Nick    schedule 14.06.2017    source источник


Ответы (3)


Вместо того, чтобы делать это непосредственно из CSV, вам лучше прочитать CSV в матрице, создать свою матрицу общих затрат, а затем запустить цикл for для имитации значений.

Например так:

runs<-1000 #Set number of runs
Info_costs<- read.csv( "Your_file_name.csv") #Read in the information
Total_cost_items<-matrix(,nrow=runs,ncol=length(Info_costs$Item)) #Create an empty matrix to contain your simulations
for (i in 1:length(Info_costs$Item))
   {Total_cost_items[,i]<-rtriangle(n=runs,Info_costs$l[i],Info_costs$u[i],Info_costs$c[i]) } 
#Fill the matrix
Total_cost_items<-data.frame(Total_cost_items, rowSums(Total_cost_items)) #append the matrix with the row sums

Возможно, вам придется настроить функцию read.csv с помощью параметров и, конечно же, правильного имени файла, чтобы он правильно читал ваш файл. Также вы можете позже переименовать столбцы фрейма данных во что-то более полезное.

person Maarten Punt    schedule 14.06.2017
comment
Мартен, спасибо, это действительно хорошо работает. Как вы говорите, мне нужно будет изменить имена столбцов. Я думаю, что буду основывать их на количестве строк данных CSV, чтобы можно было добавить несколько элементов, а затем создать расположение строк «n» для упрощения именования. - person Nick; 14.06.2017
comment
@nick_dawe Пожалуйста. Название столбца звучит как хорошая идея, если вы хотите использовать код позже в добавленном CSV. Не уверен, что вы имеете в виду, говоря о расположении рядов "n" - person Maarten Punt; 14.06.2017

Вы можете прочитать свои данные с помощью read.csv и сохранить их как data.frame. Вот некоторые фиктивные данные:

df <- data.frame(Item=letters[1:3], l=1:3, c=2:4, u=3:5)
df

  Item l c u
1    a 1 2 3
2    b 2 3 4
3    c 3 4 5

Вы можете использовать foreach и dplyr для достижения желаемого:

library(foreach)
library(dplyr)

df <- foreach(I=1:nrow(df), .combine=rbind) %do% rtriangle(10,df$l[I],df$c[I],df$u[I]) %>%
as.data.frame() %>%
mutate( sum = rowSums(.))

Это будет перебирать каждую строку df, выполнять rtriangle, связывать полученные данные в matrix, конвертировать matrix в data.frame, по которому вы можете вычислить rowSums.

Мои результаты

   V1  V2  V3  V4  V5  V6  V7  V8  V9 V10 sum
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
person CPak    schedule 14.06.2017
comment
Чи Пак, спасибо за ответ. Когда я запустил ваш код, он создал 10 столбцов на основе строк. Код Маартена дал мне нужный ответ. Еще раз спасибо. - person Nick; 14.06.2017
comment
Думаю, ваш ответ можно найти в столбце sum, но все же рад, что вы его получили. - person CPak; 14.06.2017

Решено - Спасибо @Maarten Punt!

Думал, что опубликую окончательное рабочее решение:

TotalCostEstimate<-matrix(,nrow=runs,ncol=length(basedata$Item)) #Create an empty matrix to contain your simulations
for (i in 1:length(basedata$Item)) # Prepare distributions based on the distribution type select (1 [triangle] or 2 [discrete])
{if (basedata$DistType[i] == 1) { 
        TotalCostEstimate[,i]<-rtriangle(n=runs,basedata$l[i],basedata$u[i],basedata$c[i]) 
}else{
        TotalCostEstimate[,i]<- sample(c(0,basedata$u[i]),runs,replace=TRUE)        
        }}
#Fill the matrix
TotalCostEstimate<-data.frame(TotalCostEstimate, rowSums(TotalCostEstimate)) #append the matrix with the row sums
for (i in 1:length(basedata$Item))
{colnames(TotalCostEstimate)[i]<-basedata$Item[i] } # Rename the column names to the cost items from base data
#Rename the last column based on the number of cost items
i<-length(basedata$Item)
colnames(TotalCostEstimate)[i+1]<-"TotalCost"

Важно отметить, что я изменил CSV, включив в него новое поле DistType, которое позволяет пользователю выбирать тип распределения для использования в моделировании - дискретный (включен или выключен) или треугольный:

          Item     l     c     u DistType
            <chr> <int> <int> <int>    <int>
1     “CostItem1”  1500  1900  2600        1
2     “CostItem2”  2400  3200  4400        1
3     “CostItem3”   500  1000  1500        1
4 “DiscCostItem4”     0     0  1500        2

Я также изменил функцию цикла, чтобы взять имена элементов затрат из файла CSV и распределить их по столбцам вывода, причем последний суммированный столбец [i + 1] получил имя «TotalCost». Это позволило автоматически присваивать названия выходным данным / графикам (опять же с использованием цикла) на основе имен столбцов.

person Nick    schedule 14.06.2017
comment
Извините, я не могу использовать для этого свой мобильный телефон. Я имел в виду: хорошо, но на самом деле вам не нужен цикл для имен столбцов. colnames (TotalCostEstimate) [1: length (basedata $ Item)] ‹- basedata $ Item должно помочь и ускорить вычисления - person Maarten Punt; 14.06.2017
comment
Еще раз спасибо Maarten, попробую. - person Nick; 15.06.2017