library(tidyverse)
library(here)
library(hrbrthemes)
source(here::here("code/lib.R"))
theme_set(theme_ipsum_rc())
options(scipen = 99999)
estimativas_raw = read_projectdata()
glimpse(estimativas_raw)
## Observations: 12,299
## Variables: 17
## $ TaskNumber <chr> "1735", "1742", "1971", "2134", "2251", "2283", …
## $ Summary <chr> "Flag RI on SCM Message Summary screen using met…
## $ Priority <dbl> 1, 1, 2, 5, 10, 1, 5, 5, 6, 5, 2, 1, 3, 1, 1, 8,…
## $ 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", "5…
## $ StatusCode <chr> "FINISHED", "FINISHED", "FINISHED", "FINISHED", …
## $ ProjectCode <chr> "PC2", "PC2", "PC2", "PC2", "PC2", "PC9", "PC2",…
## $ ProjectBreakdownCode <chr> "PBC42", "PBC21", "PBC75", "PBC42", "PBC21", "PB…
## $ Category <chr> "Development", "Development", "Operational", "De…
## $ SubCategory <chr> "Enhancement", "Enhancement", "In House Support"…
## $ HoursEstimate <dbl> 14.00, 7.00, 0.70, 0.70, 3.50, 7.00, 7.00, 7.00,…
## $ 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.00,…
## $ DeveloperPerformance <dbl> 12.25, 0.00, 0.00, 0.00, 0.00, 0.00, NA, 0.00, 0…
estimativas_raw %>%
select(ProjectCode, TaskNumber, HoursEstimate, HoursActual) %>%
skimr::skim()
| 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.
estimativas_raw %>%
group_by(TaskNumber) %>%
mutate(estimativas = n()) %>%
filter(estimativas > 1) %>%
count(TaskNumber, sort = T)
## # 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:
estimativas = estimativas_raw %>%
group_by(ProjectCode, TaskNumber, Category, Priority, Summary) %>%
summarise(
HoursEstimate = mean(HoursEstimate),
HoursActual = mean(HoursActual),
DeveloperPerformance = mean(DeveloperPerformance)
) %>%
ungroup()
por_time = estimativas_raw %>%
group_by(ProjectCode) %>%
summarise(devs = NROW(unique(DeveloperID)),
erro_medio_abs = mean(abs(HoursEstimate - HoursActual)),
estimativas = n())
Uma forma de verificar se existem relações entre essas variáveis é observar o comportamento dos dados quando uma está em função da outra.
estimativas %>%
ggplot(aes(x = HoursEstimate,
y = HoursActual)) +
geom_point(colour = "#06D6A0",
alpha = .5) +
labs(x = "Duração estimada (horas)",
y = "Duração real (horas)",
title = "Relação entre duração estimada e real.") +
theme(plot.title = element_text(face = "plain"))
A distribuição dos dados no gráfico dificulta a identificação de alguma relação entre as variáveis, já que a grande maioria está concentrada na mesma faixa de valores. Observamos, ainda, a existência de algumas observações distoantes do restante dos dados (outliers). Vamos identificar estes valores.
estimativas %>%
filter(HoursActual > 1000 | HoursEstimate > 500) %>%
select(TaskNumber, Category, HoursEstimate, HoursActual) %>%
group_by(Category)
## # A tibble: 4 x 4
## # Groups: Category [2]
## TaskNumber Category HoursEstimate HoursActual
## <chr> <chr> <dbl> <dbl>
## 1 13505 Development 700 23.5
## 2 12159 Development 30 2005.
## 3 11148 Operational 21 2490.
## 4 12816 Development 910 209.
Os outliers identificados são as tarefas com duração estimada superiores à 600 horas ou cuja duração real superou as 1000 horas.
Já que em escala linear não foi possível observar relações entre os dados, vejamos como estes se comportam em escala logarítmica.
estimativas %>%
ggplot(aes(x = HoursEstimate,
y = HoursActual)) +
geom_point(colour = "#06D6A0",
alpha = .5) +
scale_x_log10() +
scale_y_log10() +
labs(x = "Duração estimada (horas)",
y = "Duração real (horas)",
title = "Relação entre duração estimada e real.",
subtitle = "Em escala logarítmica") +
theme(plot.title = element_text(face = "plain"),
plot.subtitle = element_text(family = hrbrthemes::font_rc,
face = "plain"))
Nesta escala, é possível observar que os valores de duração real para a realização da tarefa aumenta de acordo com a duração que foi estimada.
Uma forma de quantificar relação entre variáveis numéricas é utilizando coeficientes de correlação. Este coeficiente mede a relação linear entre variáveis numéricas, ou seja, o quanto a distribuição de seus dados no espaço quando uma dessas variáveis está em função da outra aproxima-se de uma reta. O valor desse coeficiente varia entre -1 e 1 e quantifica a força e direção da relação através de seu valor absoluto e sinal, respectivamente.
Como foi verificado anteriormente durante o entedimento dos dados, as variáveis em questão não seguem uma distribuição normal e possuem outliers. Portanto, utilizaremos três diferentes coeficientes de correlação. Um deles, o coeficiente de Pearson, não funciona bem para distribuições que não sigam a distribuição normal e possuam outliers, enquanto que os outros, Spearman e , são mais robustos e conseguem lidar com essas limitações. Contudo, todos os coeficientes serão utilizados para que possamos realizar comparações entre os resultados obtidos pelos três métodos para o mesmo conjunto de dados com e sem outliers.
Vejamos, inicialmente, os valores destes coeficientes para os dados com os outliers.
estimativas %>%
summarise(pearson = cor(HoursActual, HoursEstimate, method = "pearson"),
spearman = cor(HoursActual, HoursEstimate, method = "spearman"),
kendall = cor(HoursActual, HoursEstimate, method = "kendall"))
## # A tibble: 1 x 3
## pearson spearman kendall
## <dbl> <dbl> <dbl>
## 1 0.316 0.826 0.696
Todos os coeficientes indicaram a existência de uma correlação positiva entre os dados. Com relação a força da correlação, os coeficientes de Spearman e quantificaram uma correlação mais forte que o de Pearson. Isto era esperado, já que neste caso estamos utilizando dados que não seguem uma distribuição normal e considerando os outliers. Vejamos agora os valores desses coeficientes quando os outliers são desconsiderados.
estimativas %>%
filter(HoursActual <= 1000 & HoursEstimate <= 500) %>%
summarise(pearson = cor(HoursActual, HoursEstimate, method = "pearson"),
spearman = cor(HoursActual, HoursEstimate, method = "spearman"),
kendall = cor(HoursActual, HoursEstimate, method = "kendall"))
## # A tibble: 1 x 3
## pearson spearman kendall
## <dbl> <dbl> <dbl>
## 1 0.496 0.826 0.696
Sem outliers, o valor do coeficiente de Pearson aumentou, aproximando-se mais dos valores dos outros coeficientes, embora continue menor. Não há uma diferença signficativa entre os valores dos outros coeficientes considerando ou não outliers, já que eles são mais resistentes a estes valores.
Agora, vamos verificaremos esta relação considerando as diferentes categorias de tarefas.
Mais uma vez, iniciaremos observando a distribuição dos dados das variáveis em função uma da outra.
estimativas %>%
ggplot(aes(x = HoursEstimate,
y = HoursActual,
colour = Category)) +
geom_point(alpha = .5) +
guides(colour = F) +
facet_grid(~Category) +
scale_colour_manual(values = c("#06D6A0", "#FFC43D", "#EF476F")) +
labs(x = "Duração estimada (horas)",
y = "Duração real (horas)",
title = "Relação entre duração estimada e real por categoria.") +
theme(plot.title = element_text(face = "plain"))
Para as categorias, o comportamento é semelhante ao observado nos dados como um todo. Vejamos em escala logarítmica.
estimativas %>%
ggplot(aes(x = HoursEstimate,
y = HoursActual,
colour = Category)) +
geom_point(alpha = .5) +
scale_x_log10() +
scale_y_log10() +
guides(colour = F) +
facet_grid(~Category) +
scale_colour_manual(values = c("#06D6A0", "#FFC43D", "#EF476F")) +
labs(x = "Duração estimada (horas)",
y = "Duração real (horas)",
title = "Relação entre duração estimada e real por categoria.",
subtitle = "Em escala logarítmica") +
theme(plot.title = element_text(face = "plain"),
plot.subtitle = element_text(family = hrbrthemes::font_rc,
face = "plain"))
Novamente, o comportamento entre as categorias é semelhante aos dos dados como um todo. Agora, quantificaremos as relações com os mesmos coeficientes de correlação utilizados anteriormente.
estimativas %>%
group_by(Category) %>%
summarise(pearson = cor(HoursActual, HoursEstimate, method = "pearson"),
spearman = cor(HoursActual, HoursEstimate, method = "spearman"),
kendall = cor(HoursActual, HoursEstimate, method = "kendall"))
## # A tibble: 3 x 4
## Category pearson spearman kendall
## <chr> <dbl> <dbl> <dbl>
## 1 Development 0.377 0.835 0.700
## 2 Management 0.456 0.753 0.635
## 3 Operational 0.159 0.842 0.729
Considerando outliers, novamente a relação entre as variáveis para cada categoria é positiva. Contudo, com relação a força da relação, a relação mais fraca, de acordo com o coeficiente de Pearson, pertence a categoria Operational. Aqui podemos destacar a influência dos outliers no resultado vendo a diferença entre este valor para as categorias Development e Operational. Embora ambas possuam uma observação com um valor de duração real bastante superior aos outros, a mais penalizada foi Operational, ja o valor de seu outlier é maior até mesmo que o de Development. Para todas as categorias, de acordo com os outros coeficientes, esta relação varia entre moderada e forte.
Vejamos agora os valores dos coeficientes para as categorias quando desconsideramos os outliers.
estimativas %>%
filter(HoursActual <= 1000 & HoursEstimate <= 600) %>%
group_by(Category) %>%
summarise(pearson = cor(HoursActual, HoursEstimate, method = "pearson"),
spearman = cor(HoursActual, HoursEstimate, method = "spearman"),
kendall = cor(HoursActual, HoursEstimate, method = "kendall"))
## # A tibble: 3 x 4
## Category pearson spearman kendall
## <chr> <dbl> <dbl> <dbl>
## 1 Development 0.532 0.834 0.700
## 2 Management 0.456 0.753 0.635
## 3 Operational 0.342 0.842 0.729
Desconsiderando outliers, não há diferenças significativas entre os valores dos coeficientes, exceto pelos de Pearson, cujos valores aumentaram. Todos os valores continuam indicando uma relação positiva entre as variáveis por categoria, cujas forças variam entre moderadas e fortes. Notamos também que a interpretação da relação para a categoria Operational mudam entre os coeficientes de Pearson e Spearman, já que estes representam, respectivamente, o menor e maior valor de correlação entre todas as categorias.
Assim, considerando os dados como um todo ou por categorias, podemos dizer que a duração estimada e a real possuem uma correlação de moderada a forte.
Para responder esta pergunta, utilizaremos a mesma abordagem da questão anterior. Primeiramente analisaremos o comportamento dos dados quando as variáveis estão em função uma da outra e depois quantificaremos a relação utilizando os valores dos coeficientes de correlação.
Vejamos o comportamentos dos dados em escala linear.
por_time %>%
ggplot(aes(x = devs,
y = erro_medio_abs)) +
geom_point(colour = "#06D6A0") +
labs(x = "Tamanho da equipe",
y = "Erro",
title = "Relação entre tamanho da equipe e erro na estimativa.") +
theme(plot.title = element_text(face = "plain"))
Vemos pelo gráfico que os dados concentram-se em faixas semelhantes de valores, com duas observações mais distantes de onde os dados estão concentrados. Consideraremos essas observações como sendo outliers.
por_time %>%
filter(erro_medio_abs > 90)
## # A tibble: 2 x 4
## ProjectCode devs erro_medio_abs estimativas
## <chr> <int> <dbl> <int>
## 1 PC14 11 90.4 105
## 2 PC20 2 98.7 5
Os outliers identificados são referentes à projetos cujo valor de erro ultrapasse os 90.
Vejamos o comportamento dos dados em escala logarítmica.
por_time %>%
ggplot(aes(x = devs,
y = erro_medio_abs)) +
geom_point(colour = "#06D6A0") +
scale_x_log10() +
scale_y_log10() +
labs(x = "Tamanho da equipe",
y = "Erro",
title = "Relação entre tamanho da equipe e erro na estimativa.",
subtitle = "Em escala logarítmica") +
theme(plot.title = element_text(face = "plain"),
plot.subtitle = element_text(family = hrbrthemes::font_rc,
face = "plain"))
Mesmo em escala logarítmica, não é possível observar alguma relação clara entre as variáveis.
Considerando os outliers, vejamos os valores dos coeficientes de correlação.
por_time %>%
summarise(pearson = cor(devs, erro_medio_abs, method = "pearson"),
spearman = cor(devs, erro_medio_abs, method = "spearman"),
kendall = cor(devs, erro_medio_abs, method = "kendall"))
## # A tibble: 1 x 3
## pearson spearman kendall
## <dbl> <dbl> <dbl>
## 1 -0.137 0.0438 0.0324
Para todos os coeficientes, a força da relação é fraca. Observamos, ainda, que há uma discordância entre a direção da correlação entre os coeficientes. Vejamos o que acontece ao desconsiderar os outliers.
por_time %>%
filter(erro_medio_abs <= 90) %>%
summarise(pearson = cor(devs, erro_medio_abs, method = "pearson"),
spearman = cor(devs, erro_medio_abs, method = "spearman"),
kendall = cor(devs, erro_medio_abs, method = "kendall"))
## # A tibble: 1 x 3
## pearson spearman kendall
## <dbl> <dbl> <dbl>
## 1 -0.0892 0.124 0.0873
Observamos um pequeno aumento nos valores dos coeficientes para os dados sem outliers, mas a relação entre as variáveis continua fraca.
Em ambas as situações, não é possível afirmar que a quantidade de desenvolvedores influencia o erro nas estimativas.