## Observations: 12,299
## Variables: 17
## $ TaskNumber <chr> "1735", "1742", "1971", "2134", "2251", "2283"...
## $ Summary <chr> "Flag RI on SCM Message Summary screen using m...
## $ Priority <dbl> 1, 1, 2, 5, 10, 1, 5, 5, 6, 5, 2, 1, 3, 1, 1, ...
## $ RaisedByID <chr> "58", "58", "7", "50", "46", "13", "13", "13",...
## $ AssignedToID <chr> "58", "42", "58", "42", "13", "13", "13", "58"...
## $ AuthorisedByID <chr> "6", "6", "6", "6", "6", "58", "6", "6", "6", ...
## $ StatusCode <chr> "FINISHED", "FINISHED", "FINISHED", "FINISHED"...
## $ ProjectCode <chr> "PC2", "PC2", "PC2", "PC2", "PC2", "PC9", "PC2...
## $ ProjectBreakdownCode <chr> "PBC42", "PBC21", "PBC75", "PBC42", "PBC21", "...
## $ Category <chr> "Development", "Development", "Operational", "...
## $ SubCategory <chr> "Enhancement", "Enhancement", "In House Suppor...
## $ HoursEstimate <dbl> 14.00, 7.00, 0.70, 0.70, 3.50, 7.00, 7.00, 7.0...
## $ HoursActual <dbl> 1.75, 7.00, 0.70, 0.70, 3.50, 7.00, 7.00, 7.00...
## $ DeveloperID <chr> "58", "42", "58", "42", "13", "13", "43", "58"...
## $ DeveloperHoursActual <dbl> 1.75, 7.00, 0.70, 0.70, 3.50, 7.00, 7.00, 7.00...
## $ TaskPerformance <dbl> 12.25, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.0...
## $ DeveloperPerformance <dbl> 12.25, 0.00, 0.00, 0.00, 0.00, 0.00, NA, 0.00,...
| Name | Piped data |
| Number of rows | 12299 |
| Number of columns | 4 |
| _______________________ | |
| Column type frequency: | |
| character | 2 |
| numeric | 2 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| ProjectCode | 0 | 1 | 3 | 4 | 0 | 20 | 0 |
| TaskNumber | 0 | 1 | 4 | 5 | 0 | 10266 | 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| HoursEstimate | 0 | 1 | 10.15 | 28.84 | 0.01 | 1 | 3 | 7.0 | 910.00 | ▇▁▁▁▁ |
| HoursActual | 0 | 1 | 13.18 | 68.72 | 0.01 | 1 | 3 | 8.5 | 2490.16 | ▇▁▁▁▁ |
Temos 20 projetos, com 12299 estimativas_raw. Não há apenas uma estimativa por tarefa, já que há apenas 10266 valores distintos de TaskNumber.
## # A tibble: 1,384 x 2
## # Groups: TaskNumber [1,384]
## TaskNumber n
## <chr> <int>
## 1 10605 8
## 2 6889 8
## 3 10089 7
## 4 10974 7
## 5 11056 7
## 6 11270 7
## 7 13124 7
## 8 13190 7
## 9 13253 7
## 10 3812 7
## # ... with 1,374 more rows
Para nossa análise, usaremos uma estimativa por task. Caso haja mais de uma usaremos a média das estimativas_raw:
# Vamos inicialmente plotar os dados de horas estimadas e horas reais para verificar se existe alguma distorção de valores que precisam ser ajustados.
estimativas_raw %>% ggplot(aes(x = HoursEstimate, y = HoursActual)) + geom_point()
# Com essa plotagem é possível verificar que existem pontos que fogem dos valores normais para essa informação. Para uma melhor análise, vamos plotar um histograma e verificar onde encontra-se a maior frequência de valores tanto para a Hora estimada como para Hora atual.
hist_he <- estimativas_raw %>% ggplot() + geom_histogram(aes(x = HoursEstimate), bins = 20) + ggtitle("Hora estimada da tarefa")
hist_ha <- estimativas_raw %>% ggplot() + geom_histogram(aes(x = HoursActual), bins = 20) + ggtitle("Hora atual da tarefa")
grid.arrange(hist_he, hist_ha, ncol = 2)
# Agora é possível verificar que a maior frequência de valores para Hora estimada encontra-se abaixo de 50h e para a hora atual fica abaixo 25h.
# Vamos agora ajustar os dados retirando da amostra valores que não esteja no intervalo de 0 até 50 para hora estimada e de 0 até 25 para hora atual. Aplicando o filtro (HoursEstimate<=50 & HoursActual<=25), vamo também ajustar a escalas dos eixos para uma escala logarítmica.
estimativas_raw %>% filter((HoursEstimate<=50 & HoursActual<=25)) %>% ggplot() + geom_point(aes(x = HoursEstimate, y = HoursActual), alpha = .5) + ggtitle("Gráfico Hora estimada por Hora atual") + scale_x_log10() + scale_y_log10()
# Para verificar a relação entre as duas variáveis vamos construir um modelo de regressão linear. O comando abaixo irá calcular e montar o modelo para verificar qual a relação do valor da hora estimada em função do valor da variável hora atual.
dados2 <- estimativas_raw
modelo <- lm(log(HoursActual) ~ log(HoursEstimate) , data = dados2)
# Exibindo os valores que foram gerados pelo comando acima, vamos ter:
summary(modelo)
##
## Call:
## lm(formula = log(HoursActual) ~ log(HoursEstimate), data = dados2)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.6546 -0.4141 -0.0894 0.4535 5.5109
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.250778 0.010666 23.51 <2e-16 ***
## log(HoursEstimate) 0.823931 0.005812 141.76 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.9129 on 12297 degrees of freedom
## Multiple R-squared: 0.6204, Adjusted R-squared: 0.6204
## F-statistic: 2.01e+04 on 1 and 12297 DF, p-value: < 2.2e-16
# Após a exibição dos dados é possível fazer algumas considerações:
# 1. Para ambos os coeficientes B0 e B1 é possível identificar que ambos apresentam um nível de significância considerável.
# 2. Com um erro padrão de 0.8099 que nos diz que a distância média dos pontos de dados para a linha de ajuste da regressão é de cerca de 80.99%.
# 3. O modeo de regressão apresenta a seguinte expressão: HoursActual = 0.25 + 0.71 HoraEstimate
# Identificando os tipos de categorias existenes:
dados2 %>% group_by(dados2$Category) %>% summarise(cont=n())
## # A tibble: 3 x 2
## `dados2$Category` cont
## <chr> <int>
## 1 Development 8220
## 2 Management 2105
## 3 Operational 1974
dados2 %>% filter(Category=="Management")
## # A tibble: 2,105 x 17
## TaskNumber Summary Priority RaisedByID AssignedToID AuthorisedByID StatusCode
## <chr> <chr> <dbl> <chr> <chr> <chr> <chr>
## 1 3459 Send O~ 1 58 58 58 FINISHED
## 2 3533 Staff ~ 1 58 58 58 FINISHED
## 3 3559 Genera~ 1 58 58 58 FINISHED
## 4 3568 Manage~ 1 58 58 58 FINISHED
## 5 3628 SiP Ma~ 1 58 58 58 FINISHED
## 6 3661 Attatc~ 1 58 58 58 FINISHED
## 7 3689 Genera~ 1 58 58 58 FINISHED
## 8 3705 Arrang~ 1 23 58 58 FINISHED
## 9 3722 SiP Fr~ 5 58 58 58 FINISHED
## 10 3723 SiP Pr~ 2 58 58 58 FINISHED
## # ... with 2,095 more rows, and 10 more variables: ProjectCode <chr>,
## # ProjectBreakdownCode <chr>, Category <chr>, SubCategory <chr>,
## # HoursEstimate <dbl>, HoursActual <dbl>, DeveloperID <chr>,
## # DeveloperHoursActual <dbl>, TaskPerformance <dbl>,
## # DeveloperPerformance <dbl>
# Para incluir a coluna de "Category" é preciso criar uma nova coluna e fazer uma conversão dos três tipos de Category para valores numéricos, como 1, 2 e 3. O comando abaixo cria uma nova coluna no dataframe dados2 com o nome Categoria2.
dados2$Categoria2 <- ifelse(dados2$Category=="Development",1,ifelse(dados2$Category=="Management",2,3))
# Agora vamos adicionar essa coluna nova coluna no modelo para verificar qual a influência da Categoria na definição da hora estimada.
modelo<-lm(log(HoursActual) ~log(HoursEstimate)+ Categoria2,data=dados2)
# Exibindo os valores que foram gerados pelo comando acima, vamos ter:
summary(modelo)
##
## Call:
## lm(formula = log(HoursActual) ~ log(HoursEstimate) + Categoria2,
## data = dados2)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.7115 -0.4236 -0.1102 0.4610 5.4936
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.197030 0.019817 9.943 <2e-16 ***
## log(HoursEstimate) 0.825095 0.005821 141.744 <2e-16 ***
## Categoria2 0.035110 0.010912 3.218 0.0013 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.9126 on 12296 degrees of freedom
## Multiple R-squared: 0.6207, Adjusted R-squared: 0.6206
## F-statistic: 1.006e+04 on 2 and 12296 DF, p-value: < 2.2e-16
# Após a exibição dos dados é possível fazer outras considerações:
# 1. É possível verificar que não houve nenhum acréscimo ao R quadrado, metrica que apresenta a representação da variável ao modelo.
# 2. O modeo de regressão apresenta a seguinte expressão: HoursActual = 0.17 + 0.71 HoraEstimate + 0.05 Category
# 3.Não houve nenhuma alteração ao erro padrão do modelo, permandente em 0.809
## Aqui vamos utilizar o dataframe por_time que agrupa os desenvolvedores por código de projeto e também já criar duas colunas: erro_medio_abs e estimativas, com isso é possível construir um gráfico que pode identificar como é possível representar o número médio de erros por tamanho da equipe. Vamos utilizar uma plotagem em três dimensões para representar as informações de horas estimadas, erros cometidos e tamanho da equipe.
por_time %>% ggplot() + geom_point(aes(x=erro_medio_abs, y=estimativas, size = devs),alpha=.3) + scale_size(range = c(5, 15)) + ggtitle("Gráfico de Horas estimadas X erro X equipes")
## Numa primeira análise é possível observar que existe uma certa concentração de equipes entre 4 e 8 pessoas, o tamanho da bola, onde é possível verificar uma faixa de erros entre 0 e 25 e números de horas estimadas entre 0 e 1000h, podendo levar a concluir que equipes menores produzem mais erros e tem valores de estimativas até 1000h.
## Então, iremos utilizar as medidas dos coeficientes de correlação, para saber se com eles é possível descobrir a relação existente entre essas variáveis.
## Para melhor explorar os dados dentro do intervalo das horas estimadas e os erros, vamos plotar os dados agora dividindo em dois grupos, com equipes menor ou igual a 8 e maiores que 8.
line1 <- por_time %>% filter(devs<=8)%>% ggplot() + geom_line(aes(x = estimativas, y= erro_medio_abs),color="grey") + ggtitle("Gráfico de Horas estimadas X erro")
line2 <- por_time %>% filter(devs>8)%>% ggplot() + geom_line(aes(x = estimativas, y= erro_medio_abs),color="grey") + ggtitle("Gráfico de Horas estimadas X erro")
grid.arrange(line1,line2, ncol = 2)
## Nessa plotagem agora é possível perceber que as equipes menores apresentam um maior número de erros em relação as maiores, apesar de existir um momento de pico em ambas as equipes.
## Para melhor explicar a existência ou não da corelação entre o tamanho das equipes e a estimativa de horas vamos utilizar os coeficientes de correlação.
Medidascc <- por_time %>% summarise(Medida1=cor(devs, erro_medio_abs,method="pearson"),Medida2=cor(devs, erro_medio_abs, method = "spearman"),Medida3=cor(devs, erro_medio_abs, method = "kendall"))
Medidascc
## # A tibble: 1 x 3
## Medida1 Medida2 Medida3
## <dbl> <dbl> <dbl>
## 1 -0.137 0.0438 0.0324
## Diante desses coeficientes é possível verificar que sua correlação é muito baixa, quase todos apresentam valores muito próximo a zero, ou seja, não é possível afirmar que o tamanho das equipes pode influenciar na definição da hora estimada.