O que são os dados

## Rows: 12,299
## Columns: 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…

Entendendo os dados

Data summary
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

1 estimativa por task

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

Para entender melhor os dados, saber o que nos oferecem e se precisaremos fazer alguma modificação antes de analisar, vamos sumarizá-los novamente.

summary(estimativas)
##  ProjectCode         TaskNumber          Category            Priority     
##  Length:10268       Length:10268       Length:10268       Min.   : 1.000  
##  Class :character   Class :character   Class :character   1st Qu.: 1.000  
##  Mode  :character   Mode  :character   Mode  :character   Median : 1.000  
##                                                           Mean   : 2.184  
##                                                           3rd Qu.: 3.000  
##                                                           Max.   :10.000  
##                                                                           
##    Summary          HoursEstimate      HoursActual       DeveloperPerformance
##  Length:10268       Min.   :  0.010   Min.   :   0.010   Min.   :-803.8000   
##  Class :character   1st Qu.:  1.000   1st Qu.:   1.000   1st Qu.:   0.0000   
##  Mode  :character   Median :  2.500   Median :   2.500   Median :   0.0000   
##                     Mean   :  8.816   Mean   :   9.273   Mean   :   1.0293   
##                     3rd Qu.:  7.000   3rd Qu.:   7.000   3rd Qu.:   0.7575   
##                     Max.   :910.000   Max.   :2490.160   Max.   : 402.0000   
##                                                          NA's   :1434
# Classificação de variáveis

Apenas com a sumarização podemos já observar informações interessantes sobre as variáveis quantitativas. A média de horas estimadas é 8.81, enquanto a média de horas já gastas é 9.273. A variável que representa a peformance do desenvolvedor possui alguns valores ‘N/A’, ou seja, para algumas tasks isso não foi registrado, contudo podemos resolver essa falha calculando esse valor (horas estimadas - horas atuais).

estimativas = estimativas %>% mutate( DevPeformance = ifelse(is.na(DeveloperPerformance), HoursEstimate - HoursActual, DeveloperPerformance))

Dados por time

Uma forma interessante de observar melhor nossos dados pode ser a partir dos times (ProjectCode). Vamos ordernar por quantidade de devs no time.

por_time = estimativas_raw %>% 
    group_by(ProjectCode) %>% 
    summarise(devs = NROW(unique(DeveloperID)), 
              erro_medio_abs = mean(abs(HoursEstimate - HoursActual)), 
              estimativas = n())
a <- arrange(por_time ,desc(devs))
### ordenar 
a %>% kable(align = 'c') %>% 
  kable_styling(bootstrap_options = c('striped', 'hover', 'responsive'))
ProjectCode devs erro_medio_abs estimativas
PC2 16 4.150092 4553
PC18 15 14.163224 2888
PC9 14 11.912057 1755
PC11 11 4.604863 292
PC14 11 90.409429 105
PC8 11 6.071094 64
PC17 10 14.981537 449
PC7 10 10.787793 145
PC16 8 9.592105 114
PC4 8 4.953268 511
PC5 8 12.230494 648
PC13 6 8.500351 171
PC6 6 10.708537 287
PC3 5 5.033218 87
PC1 4 18.514444 54
PC10 4 35.907123 73
PC12 3 8.271852 54
PC15 3 1.866667 3
PC20 2 98.684000 5
PC19 1 3.896342 41

A partir da tabela vemos que o projeto que conta com mais devs é PC2, com 16, e que seu erro médio entre horas gastas e horas estimadas é de mais ou menos 4.1, um valor próximo dos times PC11 (11 devs) e PC4(8 devs) e um valor distante dos times PC20 (2 devs) e PC14(11 devs). É possível questionar se a quantidade de devs pode influenciar no erro das estimativas (pra mais ou pra menos) ou se a quantidade de estimativas pode ter relação com o erro médio, etc. Poderemos usar tais questionamentos para responder as perguntas propostas futuramente.

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

ggplot(estimativas, aes(y = HoursEstimate, x = HoursActual)) + 
  geom_point(alpha = 0.4)  + labs(title = "Distribuição das horas estimadas pelo tempo real gasto.", x="Horas gastas", y = "Horas estimadas")

Nesse gráfio de dispersão é possível observar alguns outliers, o que pode dificultar a visualização de uma possível relação entre as variáveis usadas. Sabendo que medidas como correlação ou regressão podem ser influenciadas por outliers, vamos aplicar a transformação nas escalas e tentar reduzir o efeito do viés.

Aplicando a transformação:

ggplot(estimativas, aes(y = HoursEstimate, x = HoursActual)) + 
  geom_point(alpha = 0.4) + scale_x_log10() + scale_y_log10() + labs(title = "Distribuição das horas estimadas pelo tempo real gasto.", x="log10(Horas gastas)", y = "log10(Horas estimadas)")

Agora, com uma visualização que tenta evitar o viés podemos observar mais facilmente a relação linear entre as duas variáveis exploradas, e aparentemente, pelo formato, existe uma relação positiva. Para confirmar ou não se as variáveis possuem uma relação vamos usar o cálculo de correlação, que pode ser realizado usando três métodos diferentes:

  • Spearman: Indica a força e direção da correlação baseda em ranking, é resistente a outliers e tem relação muito forte entre [+-9, +-1]
  • Pearson: Coeficiente de correlação linear amostral e é pouco resistente a outliers. A relação é muito forte quando esse coeficiente está entre [+-7, +-1]
  • Kendall: Funciona baseado em pares concordantes e discordantes, é ainda mais resistente a outliers do que Spearman e é considerado muito forte entre [+-9, +-1]

Como temos dados que aparentam ter uma relação linear, vamos eliminar outliers para obter os coeficientes.

semoutliers %>% summarise(spearman = cor(HoursEstimate, HoursActual, method = "spearman"),
              pearson = cor(HoursEstimate, HoursActual, method = "pearson"),
              kendall = cor(HoursEstimate, HoursActual, method = "kendall"))  %>% kable(align = 'c', caption='Coeficientes de correlação Horas Gastas x Horas Estimadas') %>% 
  kable_styling(bootstrap_options = c('striped', 'hover', 'responsive'))
Coeficientes de correlação Horas Gastas x Horas Estimadas
spearman pearson kendall
0.8259529 0.7801166 0.6960477

A partir do coeficiente linear, usando pearson, dizemos que a correlação entre Horas Estimadas e Horas gastas é muito forte e positiva. Respondendo a primeira parte da pergunta: Devido a força da correlação, é muito provavel que quando Horas estimadas aumentam, Horas gastas também aumentam linearmente.

Visualizando por categoria.

Agora, vamos separar por categoria e tentar observar se o comportamente continua o mesmo independente das mesmas.

ggplot(estimativas, aes(y = HoursEstimate, x = HoursActual)) + 
  geom_point(alpha = 0.4) + 
  geom_smooth(method = "lm", se = FALSE) + facet_grid(. ~ Category) + scale_x_log10() + scale_y_log10()
## `geom_smooth()` using formula 'y ~ x'

Para essa segunda parte, já plotamos os gráficos com as transformações das escalas. É possível notar a semelhança, apesar de uma categoria ser mais numerosa que outras. Para saber se a relação continua forte, mesmo divindo por categorias, vamos medir a correlação novamente, mas agora separadamente.

dev <- semoutliers %>% filter(Category == "Development")
man <- semoutliers %>% filter(Category == "Management")
ope <- semoutliers %>% filter(Category == "Operational")

Correlações por categoria

dev %>% summarise(spearman = cor(HoursEstimate, HoursActual, method = "spearman"),
              pearson = cor(HoursEstimate, HoursActual, method = "pearson"),
              kendall = cor(HoursEstimate, HoursActual, method = "kendall"))  %>% kable(align = 'c', caption='Development - 6919 tasks') %>% 
  kable_styling(bootstrap_options = c('striped', 'hover', 'responsive'))
Development - 6919 tasks
spearman pearson kendall
0.831504 0.7732493 0.6979937
man %>% summarise(spearman = cor(HoursEstimate, HoursActual, method = "spearman"),
              pearson = cor(HoursEstimate, HoursActual, method = "pearson"),
              kendall = cor(HoursEstimate, HoursActual, method = "kendall"))  %>% kable(align = 'c', caption='Management - 1562 tasks') %>% 
  kable_styling(bootstrap_options = c('striped', 'hover', 'responsive'))
Management - 1562 tasks
spearman pearson kendall
0.7589755 0.8405642 0.6405298
ope %>% summarise(spearman = cor(HoursEstimate, HoursActual, method = "spearman"),
              pearson = cor(HoursEstimate, HoursActual, method = "pearson"),
              kendall = cor(HoursEstimate, HoursActual, method = "kendall")) %>% kable(align = 'c', caption='Operational- 1787 tasks') %>% 
  kable_styling(bootstrap_options = c('striped', 'hover', 'responsive'))
Operational- 1787 tasks
spearman pearson kendall
0.8499229 0.7160461 0.7351554

Apesar dos coeficientes sofrerem uma variação, a correlação, usando o método de pearson, continua muito forte. Então, mesmo observando as categorias separadamente, podemos afirmar que quando as horas estimadas aumentam, as horas gastas também aumentam.

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

Inicialmente vamos visualizar a dispersão entre número de devs e erro médio absoluto já com transformação nas escalas já que anteriormente, “no olho” já foi possível observar que erro podia ser parecido mesmo com quantidades diferentes de devs no time.

ggplot(por_time, aes(y = devs, x = erro_medio_abs)) + 
  geom_point(alpha = 0.4) + 
  geom_smooth(method = "lm", se = FALSE) + scale_x_log10()  + scale_y_log10()
## `geom_smooth()` using formula 'y ~ x'

Já a partir da visualização é possível notar que a correlação entre a quantidade de devs e o erro médio da estimativa e horas realmente gastas chega muito próximo de 0, com a dispersão dos pontos não é possível também dizer claramente se existem outliers. Para confirmar que uma variável influencia muito pouco ou quase nada na outra, vamos medir o os coeficientes de correlação como foi feito na questão anterior.

 por_time %>% 
    summarise(spearman = cor(devs, erro_medio_abs, method = "spearman"),
              pearson = cor(devs, erro_medio_abs, method = "pearson"),
              kendall = cor(devs, erro_medio_abs, method = "kendall"))   %>% kable(align = 'c', caption='Coeficientes de correlação entre Quantidade de Devs x Erro Médio Absoluto') %>% 
  kable_styling(bootstrap_options = c('striped', 'hover', 'responsive'))
Coeficientes de correlação entre Quantidade de Devs x Erro Médio Absoluto
spearman pearson kendall
0.0438071 -0.1365125 0.0324443

Observando esses resultados agora podemos afirmar que a relação entre quantidade de devs e erro médio absoluto é muito fraca. Assim, respondendo a pergunta inicial, ter mais ou menos devs na equipe não influencia na precisão da estimativa, ou seja no erro médio calculado.