library(dplyr)
library(DT)
library(ggplot2)
library(here)
library(hrbrthemes)
library(readr)
library(scales)

theme_set(theme_ipsum_tw())

source(here('code/lib.R'))
estimativas_raw = read_projectdata()

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())

scientific_10 <- function(x) {
  parse(text = gsub('e\\+*', ' %*% 10^', scientific_format()(x)))
}

min_esforco_real <- estimativas$HoursActual %>% min()
max_esforco_real <- estimativas$HoursActual %>% max()
min_esforco_estimado <- estimativas$HoursEstimate %>% min()
max_esforco_estimado <- estimativas$HoursEstimate %>% max()

Qual a relação entre as estimativas e horas reais tomadas na empresa como um todo e em diferentes categorias de tarefa?

Visando examinar essa relação, optamos por visualizar a princípio a dispersão das horas reais em relação às estimativas de todo o conjunto de dados. Para melhorar a visualização da relação entre as duas variáveis se fez necessário aplicar transformações não-lineares a ambas. Mais especificamente, colocamos ambas em escala logarítmica (base 10) e percebemos que existe uma relação linear, positiva e forte entre as duas variáveis quando submetidas a essas transformações. Essa observação é suportada pelos valores do coeficiente de correlação, como o de Pearson, de 0.816. Também é possível notar a existência de alguns pontos mais dispersos em relação ao todo, mas eles não se destacam o suficiente para serem considerados pontos extremos. Quanto à distribuição dessas variáveis, os valores de ambas estão fortemente concentrados em valores mais baixos (à esquerda). Além disso, suas amplitudes também diferem bastante. Ainda que apresentem o mesmo valor mínimo, de 0.01 horas, o valor máximo do esforço real é quase 3 vez superior ao esforço máximo estimado (2490.16 e 910, respectivamente).

estimativas %>%
    ggplot(aes(x = HoursActual, y = HoursEstimate)) +
    geom_point(size = 0.9, alpha = 0.3, color = '#ff6b6b') +
    labs(x = 'Esforço Necessário (em horas)', y = 'Esforço Estimado (em horas)') +
    scale_x_log10(label = scientific_10) +
    scale_y_log10(label = scientific_10) +
    theme(axis.title.x = element_text(family = 'Times New Roman', face = 'bold',
                                    vjust = -2, hjust = 0.5, size = 14),
        axis.title.y = element_text(family = 'Times New Roman', face = 'bold',
                                    vjust = 3, hjust = 0.5, size = 14),
        axis.text.x = element_text(family = 'Times New Roman', size = 12),
        axis.text.y = element_text(family = 'Times New Roman', size = 12))

estimativas %>% 
    summarise(corr_pearson = cor(log10(HoursActual), log10(HoursEstimate), method = 'pearson'),
              corr_kendall = cor(log10(HoursActual), log10(HoursEstimate), method = 'kendall'),
              corr_spearman = cor(log10(HoursActual), log10(HoursEstimate), method = 'spearman')) %>%
     mutate(`Coeficiente de Correlação (Pearson)` = round(corr_pearson, 3),
           `Coeficiente de Correlação (Kendall)` = round(corr_kendall, 3),
           `Coeficiente de Correlação (Spearman)` = round(corr_spearman, 3)) %>%
    select(`Coeficiente de Correlação (Pearson)`,
           `Coeficiente de Correlação (Kendall)`,
           `Coeficiente de Correlação (Spearman)`) %>%
    datatable()

Visualizando os pontos relativos a cada categoria, percebemos que em cada uma há uma tendência similar à observada para o conjunto inteiro: relações lineares, positivas e fortes. A categoria de Development tem os valores mais concentrados em uma mesma região, o que parece ser um indicativo de uma correlação mais forte – o mesmo ocorre para Operational. Em relação à categoria de Management, percebe-se uma quantidade maior de pontos distantes da massa principal de dados, principalmente relativos a estimativas baixas para tarefas que necessitaram de muitas horas para ser completadas. Calculando as correlações de Pearson, Kendall e Spearman para cada categoria, percebe-se que Development e Operational têm valores similares, enquanto Management tem valores um pouco menores. Vale notar ainda que as características das distribuições por categoria são bastante semelhantes às do conjunto de dados completo, exceto pelo valor máximo do esforço real para a categoria Operational, que é de apenas 150 horas.

estimativas %>%
    ggplot(aes(x = HoursActual, y = HoursEstimate, color = Category)) +
    geom_point(size = 0.75, alpha = 0.3, show.legend = FALSE) +
    scale_color_manual(values = c('#e63946', '#f77f00', '#fcbf49')) +
    facet_wrap(~Category, ncol = 2) +
    labs(x = 'Esforço Necessário (em horas)', y = 'Esforço Estimado (em horas)') +
    scale_x_log10(label = scientific_10) +
    scale_y_log10(label = scientific_10) +
    theme(axis.title.x = element_text(family = 'Times New Roman', face = 'bold',
                                    vjust = -2, hjust = 0.5, size = 14),
        axis.title.y = element_text(family = 'Times New Roman', face = 'bold',
                                    vjust = 3, hjust = 0.5, size = 14),
        axis.text.x = element_text(family = 'Times New Roman', size = 12),
        axis.text.y = element_text(family = 'Times New Roman', size = 12),
        strip.text = element_text(family = 'Times New Roman', face = 'bold',
                                    vjust = 2, hjust = 0.5, size = 14))

estimativas %>% 
    group_by(Category) %>%
    summarise(corr_pearson = cor(log10(HoursActual), log10(HoursEstimate), method = 'pearson'),
              corr_kendall = cor(log10(HoursActual), log10(HoursEstimate), method = 'kendall'),
              corr_spearman = cor(log10(HoursActual), log10(HoursEstimate), method = 'spearman')) %>%
    mutate(`Coeficiente de Correlação (Pearson)` = round(corr_pearson, 3),
           `Coeficiente de Correlação (Kendall)` = round(corr_kendall, 3),
           `Coeficiente de Correlação (Spearman)` = round(corr_spearman, 3)) %>%
    select(Category,
           `Coeficiente de Correlação (Pearson)`,
           `Coeficiente de Correlação (Kendall)`,
           `Coeficiente de Correlação (Spearman)`) %>%
    datatable()

Dessa forma, conclui-se que as estimativas feitas na empresa para a realização de tarefas costumam ser satisfatórias, isto é, tarefas que foram estimadas grandes realmente levam tempos maiores para ser realizadas. Naturalmente, isso significa dizer que as duas variáveis estão claramente relacionadas.

Equipes com mais desenvolvedores produzem estimativas com mais ou menos erro que equipes menores?

Como há apenas 20 projetos, é possível visualizar facilmente a dispersão dos valores de estimativa e número de desenvolvedores por time.

por_time %>% 
    ggplot(aes(x = devs, y = erro_medio_abs)) +
    geom_point(size = 2, color = '#ff6b6b') +
    labs(x = 'Número de Desenvolvedores', y = 'Erro Abs. de Estimativa (em horas)') +
    theme(axis.title.x = element_text(family = 'Times New Roman', face = 'bold',
                                    vjust = -2, hjust = 0.5, size = 14),
        axis.title.y = element_text(family = 'Times New Roman', face = 'bold',
                                    vjust = 3, hjust = 0.5, size = 14),
        axis.text.x = element_text(family = 'Times New Roman', size = 12),
        axis.text.y = element_text(family = 'Times New Roman', size = 12))

Percebe-se a presença de dois pontos extremos, ambos com erros médios próximos a 100 horas, um valor muito acima dos demais. Esses pontos correspondem a um time com dois desenvolvedores (projeto PC20) e outro com 11 (PC14). Explorando os dados originais, percebe-se que o projeto PC20 só teve cinco estimativas, com uma das suas atividades sendo canceladas (e correspondendo a duas estimativas), o que ocasionou no valor elevado do erro médio.

estimativas_raw %>% 
    filter(ProjectCode == 'PC20') %>%
    mutate(`Esforço Estimado (em horas)` = HoursEstimate,
           `Esforço Real (em horas)` = HoursActual,
           `Status` = StatusCode) %>%
    select(`Esforço Estimado (em horas)`,
           `Esforço Real (em horas)`,
           `Status`) %>%
    datatable()

Os demais projetos têm erros médios, em sua maioria, num intervalo de 0 a 25 horas, o que não parece ser influenciado pelo número de integrantes dos times. Mesmo removendo os dois pontos extremos, as correlações de Pearson, Kendall e Spearman dão suporte à ideia de que não há uma relação linear forte entre as duas variáveis, apresentando resultados próximos a 0. Sendo assim, as estimativas das equipes não melhoram nem pioram de acordo com a quantidade de integrantes dos times – de acordo com as observações, tendem a ser similares independentemente dos tamanhos dos times.

por_time %>% 
    filter(erro_medio_abs < 50) %>% 
    summarise(corr_pearson = cor(devs, erro_medio_abs, method = 'pearson'),
              corr_kendall = cor(devs, erro_medio_abs, method = 'kendall'),
              corr_spearman = cor(devs, erro_medio_abs, method = 'spearman')) %>%
    mutate(`Coeficiente de Correlação (Pearson)` = round(corr_pearson, 3),
           `Coeficiente de Correlação (Kendall)` = round(corr_kendall, 3),
           `Coeficiente de Correlação (Spearman)` = round(corr_spearman, 3)) %>%
    select(`Coeficiente de Correlação (Pearson)`,
           `Coeficiente de Correlação (Kendall)`,
           `Coeficiente de Correlação (Spearman)`) %>%
    datatable()