Referências para leitura deste material:


1 Lendo um conjunto de dados de um arquivo externo

Nas primeiras quatro seções deste material discutiremos exemplos que utilizam o seguinte conjunto de dados, extraído do Capítulo 2 da referência Morettin & Bussab (2010). A função read.table() pode ser usada para ler um arquivo externo do tipo .txt. A função read.csv() faz o mesmo para arquivos do tipo .csv (comma-separated values file).

df0 <- read.table(file="tab.txt",header=TRUE,stringsAsFactors=FALSE)
df0
##     N estado_civil grau_instrucao n_filhos salario idade reg_procedencia
## 1   1     solteiro    fundamental       NA    4.00    26        interior
## 2   2       casado    fundamental        1    4.56    32         capital
## 3   3       casado    fundamental        2    5.25    36         capital
## 4   4     solteiro          medio       NA    5.73    20           outra
## 5   5     solteiro    fundamental       NA    6.26    40           outra
## 6   6       casado    fundamental        0    6.66    28        interior
## 7   7     solteiro    fundamental       NA    6.86    41        interior
## 8   8     solteiro    fundamental       NA    7.39    43         capital
## 9   9       casado          medio        1    7.59    34         capital
## 10 10     solteiro          medio       NA    7.44    23           outra
## 11 11       casado          medio        2    8.12    33        interior
## 12 12     solteiro    fundamental       NA    8.46    27         capital
## 13 13     solteiro          medio       NA    8.74    37           outra
## 14 14       casado    fundamental        3    8.95    44           outra
## 15 15       casado          medio        0    9.13    30        interior
## 16 16     solteiro          medio       NA    9.35    38           outra
## 17 17       casado          medio        1    9.77    31         capital
## 18 18       casado    fundamental        2    9.80    39           outra
## 19 19     solteiro       superior       NA   10.53    25        interior
## 20 20     solteiro          medio       NA   10.76    37        interior
## 21 21       casado          medio        1   11.06    30           outra
## 22 22     solteiro          medio       NA   11.59    34         capital
## 23 23     solteiro    fundamental       NA   12.00    41           outra
## 24 24       casado       superior        0   12.79    26           outra
## 25 25       casado          medio        2   13.23    32        interior
## 26 26       casado          medio        2   13.60    35           outra
## 27 27     solteiro    fundamental       NA   13.85    46           outra
## 28 28       casado          medio        0   14.69    29        interior
## 29 29       casado          medio        5   14.71    40        interior
## 30 30       casado          medio        2   15.99    35         capital
## 31 31     solteiro       superior       NA   16.22    31           outra
## 32 32       casado          medio        1   16.61    36        interior
## 33 33       casado       superior        3   17.26    43         capital
## 34 34     solteiro       superior       NA   18.75    33         capital
## 35 35       casado          medio        2   19.40    48         capital
## 36 36       casado       superior        3   23.30    42        interior

2 Entendendo a estrutura do conjunto de dados

Uma vez que o conjunto de dados foi lido e armazenada em um objeto, é necessário conhecer sua estrutura. Isto significa, saber quantas observações existem, quantas e quais são as variáveis envolvidas, seus tipos e valores. Esta tarefa pode ser feita com a função str(). A função head() mostra as 6 primeiras linhas de um conjunto de dados e a função tail() mostra as 6 últimas linhas. A função class() retorna a estrutura de dados que foi utilizada para armazenar as variáveis do conjunto de dados em questão. No caso a estrutura utilizada foi um data frame.

str(df0)
## 'data.frame':    36 obs. of  7 variables:
##  $ N              : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ estado_civil   : chr  "solteiro" "casado" "casado" "solteiro" ...
##  $ grau_instrucao : chr  "fundamental" "fundamental" "fundamental" "medio" ...
##  $ n_filhos       : int  NA 1 2 NA NA 0 NA NA 1 NA ...
##  $ salario        : num  4 4.56 5.25 5.73 6.26 6.66 6.86 7.39 7.59 7.44 ...
##  $ idade          : int  26 32 36 20 40 28 41 43 34 23 ...
##  $ reg_procedencia: chr  "interior" "capital" "capital" "outra" ...
head(df0)
##   N estado_civil grau_instrucao n_filhos salario idade reg_procedencia
## 1 1     solteiro    fundamental       NA    4.00    26        interior
## 2 2       casado    fundamental        1    4.56    32         capital
## 3 3       casado    fundamental        2    5.25    36         capital
## 4 4     solteiro          medio       NA    5.73    20           outra
## 5 5     solteiro    fundamental       NA    6.26    40           outra
## 6 6       casado    fundamental        0    6.66    28        interior
tail(df0)
##     N estado_civil grau_instrucao n_filhos salario idade reg_procedencia
## 31 31     solteiro       superior       NA   16.22    31           outra
## 32 32       casado          medio        1   16.61    36        interior
## 33 33       casado       superior        3   17.26    43         capital
## 34 34     solteiro       superior       NA   18.75    33         capital
## 35 35       casado          medio        2   19.40    48         capital
## 36 36       casado       superior        3   23.30    42        interior
class(df0)
## [1] "data.frame"

3 Funções para síntese numérica de um conjunto de dados

A função summary() proporciona uma síntese numérica rápida e simplificada para todas as variáveis de um conjunto de dados.

summary(df0)
##        N         estado_civil       grau_instrucao        n_filhos   
##  Min.   : 1.00   Length:36          Length:36          Min.   :0.00  
##  1st Qu.: 9.75   Class :character   Class :character   1st Qu.:1.00  
##  Median :18.50   Mode  :character   Mode  :character   Median :2.00  
##  Mean   :18.50                                         Mean   :1.65  
##  3rd Qu.:27.25                                         3rd Qu.:2.00  
##  Max.   :36.00                                         Max.   :5.00  
##                                                        NA's   :16    
##     salario           idade       reg_procedencia   
##  Min.   : 4.000   Min.   :20.00   Length:36         
##  1st Qu.: 7.553   1st Qu.:30.00   Class :character  
##  Median :10.165   Median :34.50   Mode  :character  
##  Mean   :11.122   Mean   :34.58                     
##  3rd Qu.:14.060   3rd Qu.:40.00                     
##  Max.   :23.300   Max.   :48.00                     
## 

Note que a função summary não proporcionou uma síntese adequada para as variáveis categóricas: estado civil, grau de instrução e região de procedência. Isso ocorreu porque estas variáveis estão armazenadas em df0 como vetores de caracteres (veja a estrutura de df0 para confirmar esta observação). Ainda que em situações simples seja possível realizar análises de variáveis categóricas armazenadas como vetores de caracteres, é mais adequado utilizar a estrutura factor() (fator em Português) para armazenar tais variáveis. O script que segue realiza esta conversão de vetores de caracteres para fatores para as variáveis em questão.

#
# Vamos preservar df0 apenas para comparação
#
df <- df0 
niveis.ec <- c("solteiro","casado")
niveis.gi <- c("fundamental","medio","superior")
niveis.rp <- c("capital","interior","outra")
df$estado_civil <- factor(df$estado_civil,levels=niveis.ec)
df$grau_instrucao <- factor(df$grau_instrucao,levels=niveis.gi,ordered=TRUE)
df$reg_procedencia <- factor(df$reg_procedencia,levels=niveis.rp)
#
# Variáveis como fatores em df
#
df$estado_civil
##  [1] solteiro casado   casado   solteiro solteiro casado   solteiro solteiro
##  [9] casado   solteiro casado   solteiro solteiro casado   casado   solteiro
## [17] casado   casado   solteiro solteiro casado   solteiro solteiro casado  
## [25] casado   casado   solteiro casado   casado   casado   solteiro casado  
## [33] casado   solteiro casado   casado  
## Levels: solteiro casado
df$grau_instrucao
##  [1] fundamental fundamental fundamental medio       fundamental fundamental
##  [7] fundamental fundamental medio       medio       medio       fundamental
## [13] medio       fundamental medio       medio       medio       fundamental
## [19] superior    medio       medio       medio       fundamental superior   
## [25] medio       medio       fundamental medio       medio       medio      
## [31] superior    medio       superior    superior    medio       superior   
## Levels: fundamental < medio < superior
df$reg_procedencia
##  [1] interior capital  capital  outra    outra    interior interior capital 
##  [9] capital  outra    interior capital  outra    outra    interior outra   
## [17] capital  outra    interior interior outra    capital  outra    outra   
## [25] interior outra    outra    interior interior capital  outra    interior
## [33] capital  capital  capital  interior
## Levels: capital interior outra

Compare agora com as estruturas de df e df0.

str(df)
## 'data.frame':    36 obs. of  7 variables:
##  $ N              : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ estado_civil   : Factor w/ 2 levels "solteiro","casado": 1 2 2 1 1 2 1 1 2 1 ...
##  $ grau_instrucao : Ord.factor w/ 3 levels "fundamental"<..: 1 1 1 2 1 1 1 1 2 2 ...
##  $ n_filhos       : int  NA 1 2 NA NA 0 NA NA 1 NA ...
##  $ salario        : num  4 4.56 5.25 5.73 6.26 6.66 6.86 7.39 7.59 7.44 ...
##  $ idade          : int  26 32 36 20 40 28 41 43 34 23 ...
##  $ reg_procedencia: Factor w/ 3 levels "capital","interior",..: 2 1 1 3 3 2 2 1 1 3 ...
str(df0)
## 'data.frame':    36 obs. of  7 variables:
##  $ N              : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ estado_civil   : chr  "solteiro" "casado" "casado" "solteiro" ...
##  $ grau_instrucao : chr  "fundamental" "fundamental" "fundamental" "medio" ...
##  $ n_filhos       : int  NA 1 2 NA NA 0 NA NA 1 NA ...
##  $ salario        : num  4 4.56 5.25 5.73 6.26 6.66 6.86 7.39 7.59 7.44 ...
##  $ idade          : int  26 32 36 20 40 28 41 43 34 23 ...
##  $ reg_procedencia: chr  "interior" "capital" "capital" "outra" ...

Compare agora com o summary(df) com o summary(df0).

summary(df)
##        N           estado_civil     grau_instrucao    n_filhos   
##  Min.   : 1.00   solteiro:16    fundamental:12     Min.   :0.00  
##  1st Qu.: 9.75   casado  :20    medio      :18     1st Qu.:1.00  
##  Median :18.50                  superior   : 6     Median :2.00  
##  Mean   :18.50                                     Mean   :1.65  
##  3rd Qu.:27.25                                     3rd Qu.:2.00  
##  Max.   :36.00                                     Max.   :5.00  
##                                                    NA's   :16    
##     salario           idade       reg_procedencia
##  Min.   : 4.000   Min.   :20.00   capital :11    
##  1st Qu.: 7.553   1st Qu.:30.00   interior:12    
##  Median :10.165   Median :34.50   outra   :13    
##  Mean   :11.122   Mean   :34.58                  
##  3rd Qu.:14.060   3rd Qu.:40.00                  
##  Max.   :23.300   Max.   :48.00                  
## 
summary(df0)
##        N         estado_civil       grau_instrucao        n_filhos   
##  Min.   : 1.00   Length:36          Length:36          Min.   :0.00  
##  1st Qu.: 9.75   Class :character   Class :character   1st Qu.:1.00  
##  Median :18.50   Mode  :character   Mode  :character   Median :2.00  
##  Mean   :18.50                                         Mean   :1.65  
##  3rd Qu.:27.25                                         3rd Qu.:2.00  
##  Max.   :36.00                                         Max.   :5.00  
##                                                        NA's   :16    
##     salario           idade       reg_procedencia   
##  Min.   : 4.000   Min.   :20.00   Length:36         
##  1st Qu.: 7.553   1st Qu.:30.00   Class :character  
##  Median :10.165   Median :34.50   Mode  :character  
##  Mean   :11.122   Mean   :34.58                     
##  3rd Qu.:14.060   3rd Qu.:40.00                     
##  Max.   :23.300   Max.   :48.00                     
## 

3.1 Variável numérica contínua

Uma síntese detalhada pode ser obtida com as seguintes funções. Como exemplo de síntese numérica de uma variável quantitativa contínua, considere a variável salário.

df$salario
##  [1]  4.00  4.56  5.25  5.73  6.26  6.66  6.86  7.39  7.59  7.44  8.12  8.46
## [13]  8.74  8.95  9.13  9.35  9.77  9.80 10.53 10.76 11.06 11.59 12.00 12.79
## [25] 13.23 13.60 13.85 14.69 14.71 15.99 16.22 16.61 17.26 18.75 19.40 23.30
summary(df$salario)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   4.000   7.553  10.165  11.122  14.060  23.300
mean(df$salario)
## [1] 11.12222
median(df$salario)
## [1] 10.165
quantile(df$salario,c(0.25,0.50,0.75))
##     25%     50%     75% 
##  7.5525 10.1650 14.0600
IQR(df$salario) # Retorna a distância interquartil = Q3 - Q1.
## [1] 6.5075
min(df$salario)
## [1] 4
max(df$salario)
## [1] 23.3
var(df$salario)
## [1] 21.04477
sd(df$salario)
## [1] 4.587458

3.2 Variável numérica discreta

Como exemplo de síntese numérica de uma variável quantitativa discreta, considere a variável número de filhos.

df$n_filhos
##  [1] NA  1  2 NA NA  0 NA NA  1 NA  2 NA NA  3  0 NA  1  2 NA NA  1 NA NA  0  2
## [26]  2 NA  0  5  2 NA  1  3 NA  2  3
summary(df$n_filhos)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##    0.00    1.00    2.00    1.65    2.00    5.00      16
mean(df$n_filhos)
## [1] NA
#
# Note que a função mean() não retornou a média da variável número de filhos. 
# Isto aconteceu porque na variável em questão existem valores não disponíveis 
# (valores NA - Not Available values). Neste caso, é necessário informar ao R 
# que estes valores não disponíveis devem ser removidos e que o cálculo deve ser
# realizado com as observações restantes. Isto é feito definindo o argumento 
# na.rm como TRUE. Observação análoga vale para outras estatísticas.
#
mean(df$n_filhos,na.rm=TRUE)
## [1] 1.65
median(df$n_filhos,na.rm=TRUE)
## [1] 2
quantile(df$n_filhos,c(0.25,0.50,0.75),na.rm=TRUE)
## 25% 50% 75% 
##   1   2   2
IQR(df$n_filhos,na.rm=TRUE)
## [1] 1
min(df$n_filhos,na.rm=TRUE)
## [1] 0
max(df$n_filhos,na.rm=TRUE)
## [1] 5
var(df$n_filhos,na.rm=TRUE)
## [1] 1.607895
sd(df$n_filhos,na.rm=TRUE)
## [1] 1.268028
table(df$n_filhos,useNA="no")
## 
## 0 1 2 3 5 
## 4 5 7 3 1
round(prop.table(table(df$n_filhos,useNA="no"))*100,2)
## 
##  0  1  2  3  5 
## 20 25 35 15  5

Uma tabela de frequências para a variável número de filhos pode ser construída com o seguinte script.

num.filhos <- c(names(table(df$n_filhos)),"Total")
frequencias <- c(table(df$n_filhos),sum(table(df$n_filhos)))
proporcoes <- round((frequencias/sum(table(df$n_filhos)))*100,2)
df.num.filhos <- data.frame(num.filhos,frequencias,proporcoes)
rownames(df.num.filhos) <- 1:length(num.filhos)
colnames(df.num.filhos) <- c("Número de filhos","Frequência","Frequência (%)")
df.num.filhos
##   Número de filhos Frequência Frequência (%)
## 1                0          4             20
## 2                1          5             25
## 3                2          7             35
## 4                3          3             15
## 5                5          1              5
## 6            Total         20            100
Número de filhos Frequência Frequência (%)
0 4 20
1 5 25
2 7 35
3 3 15
5 1 5
Total 20 100

3.3 Variável categórica

Como exemplo de síntese de uma variável categórica, considere a variável grau de instrução.

df$grau_instrucao
##  [1] fundamental fundamental fundamental medio       fundamental fundamental
##  [7] fundamental fundamental medio       medio       medio       fundamental
## [13] medio       fundamental medio       medio       medio       fundamental
## [19] superior    medio       medio       medio       fundamental superior   
## [25] medio       medio       fundamental medio       medio       medio      
## [31] superior    medio       superior    superior    medio       superior   
## Levels: fundamental < medio < superior
table(df$grau_instrucao)
## 
## fundamental       medio    superior 
##          12          18           6
round((table(df$grau_instrucao)/sum(table(df$grau_instrucao)))*100,2)
## 
## fundamental       medio    superior 
##       33.33       50.00       16.67
round(prop.table(table(df$grau_instrucao))*100,2)
## 
## fundamental       medio    superior 
##       33.33       50.00       16.67

Note que a função table() retorna as frequências nominais dos valores observados da variável grau de instrução. Sendo assim, uma tabela de frequências para esta variável pode ser construída com o seguinte script.

grau <- c(names(table(df$grau_instrucao)),"Total")
frequencias <- c(table(df$grau_instrucao),sum(table(df$grau_instrucao)))
proporcoes <- round((frequencias/sum(table(df$grau_instrucao)))*100,2)
df.instrucao <- data.frame(grau,frequencias,proporcoes)
rownames(df.instrucao) <- 1:length(grau)
colnames(df.instrucao) <- c("Grau de instrução","Frequência","Frequência (%)")
df.instrucao
##   Grau de instrução Frequência Frequência (%)
## 1       fundamental         12          33.33
## 2             medio         18          50.00
## 3          superior          6          16.67
## 4             Total         36         100.00
Grau de instrução Frequência Frequência (%)
fundamental 12 33.33
medio 18 50.00
superior 6 16.67
Total 36 100.00

4 Funções para visualização de um conjunto de dados

4.1 Histograma

Considere novamente a variável salário. Uma tabela de frequências para a variável salário pode ser construída com o seguinte script.

salario.d <- cut(df$salario,breaks=seq(4,24,4),right=FALSE)
classes <- levels(salario.d)
freq <- as.vector(table(salario.d))
freq.r <- round(100*as.vector(prop.table(freq)),2)
freq.a <- cumsum(freq.r)
df.salario <- data.frame(c(classes,"Total"),c(freq,sum(freq)),c(freq.r,sum(freq.r)),c(freq.a,NaN))
colnames(df.salario) <- c("Faixa salarial","Frequência","Frequência (%)","Frequência acumulada")
df.salario
##   Faixa salarial Frequência Frequência (%) Frequência acumulada
## 1          [4,8)         10          27.78                27.78
## 2         [8,12)         12          33.33                61.11
## 3        [12,16)          8          22.22                83.33
## 4        [16,20)          5          13.89                97.22
## 5        [20,24)          1           2.78               100.00
## 6          Total         36         100.00                  NaN
Faixa salarial Frequência Frequência (%) Frequência acumulada
[4,8) 10 27.78 27.78
[8,12) 12 33.33 61.11
[12,16) 8 22.22 83.33
[16,20) 5 13.89 97.22
[20,24) 1 2.78 100.00
Total 36 100.00 NaN

A função hist() pode ser usada para construir o histograma para a variável salário.

hist(df$salario,breaks=seq(4,24,4),freq=TRUE,right=FALSE,
     xlim=c(0,25),ylim=c(0,14),col="lightblue",
     xlab="Salario",ylab="Frequência",main="")

dev.off()
## null device 
##           1

Alternativamente, é possível também construir o histograma densidade para a variável salário. No histograma densidade, a altura de cada barra é definida de tal forma que a área da barra é igual à frequência percentual da classe que ela representa. Assim, a soma das áreas de todas as barras do histograma é igual a 1. Em outras palavras, a área total do histograma é padronizada para 1 (ou 100%).

hist(df$salario,breaks=seq(4,24,4),freq=FALSE,right=FALSE,
     xlim=c(0,25),ylim=c(0,0.10),col="lightsalmon",
     xlab="Salario",ylab="Densidade",main="")

dev.off()
## null device 
##           1

4.2 Gráfico de barras

Considere novamente a variável número de filhos, resumida na seguinte tabela de frequências.

Número de filhos Frequência Frequência (%)
0 4 20
1 5 25
2 7 35
3 3 15
5 1 5
Total 20 100

A função barplot() pode ser usada para construir o gráfico de barras para a variável número de filhos.

barplot(table(df$n_filhos),col="lightgoldenrod",main="",xlab="Número de filhos",ylab="Frequência")

dev.off()
## null device 
##           1

4.3 Gráfico de setores

Considere novamente a variável grau de instrução, resumida na seguinte tabela de frequências.

Grau de instrução Frequência Frequência (%)
fundamental 12 33.33
medio 18 50.00
superior 6 16.67
Total 36 100.00

A função pie() pode ser usada para construir o gráfico de setores para a variável grau de instrução.

rotulos <- c("Fundamental","Médio","Superior")
cores <- c("lightblue","lightsalmon","lightgreen")
pie(table(df$grau_instrucao),labels=rotulos,col=cores)

dev.off()
## null device 
##           1

4.4 Box-plot

Por fim, considere uma vez mais a variável salário. A função boxplot() pode ser usada para construir o gráfico box-plot para a variável salário.

summary(df$salario)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   4.000   7.553  10.165  11.122  14.060  23.300
limite.superior <- min(max(df$salario),quantile(df$salario,0.75)+1.5*IQR(df$salario))
limite.inferior <- max(min(df$salario),quantile(df$salario,0.25)-1.5*IQR(df$salario))
c(limite.inferior,limite.superior)
## [1]  4.0 23.3
boxplot(df$salario,ylab="Salário",col="lightblue")

dev.off()
## null device 
##           1

5 Análise bivariada: variáveis categóricas

Nesta seção iremos considerar o seguinte conjunto de dados bivariado, extraído do Capítulo 4 da referência Morettin & Bussab (2010). Estamos interessados em verificar se a criação de determinado tipo de cooperativa está associado com o fator regional.

niveis.e <- c("SP","PR","RS")
niveis.c <- c("consumidor","produtor","escola","outras")
cooperativa.sp <- rep(niveis.c,c(214,237,78,119))
cooperativa.pr <- rep(niveis.c,c(51,102,126,22))
cooperativa.rs <- rep(niveis.c,c(111,304,139,48))
estado <- factor(rep(niveis.e,c(648,301,602)),levels=niveis.e)
cooperativa <- factor(c(cooperativa.sp,cooperativa.pr,cooperativa.rs),levels=niveis.c)
df1 <- data.frame(Estado=estado,Tipo.cooperativa=cooperativa)
str(df1)
## 'data.frame':    1551 obs. of  2 variables:
##  $ Estado          : Factor w/ 3 levels "SP","PR","RS": 1 1 1 1 1 1 1 1 1 1 ...
##  $ Tipo.cooperativa: Factor w/ 4 levels "consumidor","produtor",..: 1 1 1 1 1 1 1 1 1 1 ...
head(df1)
##   Estado Tipo.cooperativa
## 1     SP       consumidor
## 2     SP       consumidor
## 3     SP       consumidor
## 4     SP       consumidor
## 5     SP       consumidor
## 6     SP       consumidor
tail(df1)
##      Estado Tipo.cooperativa
## 1546     RS           outras
## 1547     RS           outras
## 1548     RS           outras
## 1549     RS           outras
## 1550     RS           outras
## 1551     RS           outras
dim(df1)
## [1] 1551    2

5.1 Tabela de frequências (absolutas)

Considerando o conjunto de dados desta seção. Uma tabela de frequências de dupla entrada (ou tabela de contingência) para as variáveis estado e tipo de cooperativa pode ser construída aplicando as seguintes funções: table()e addmargins().

tf <- table(df1[,1],df1[,2])
tf
##     
##      consumidor produtor escola outras
##   SP        214      237     78    119
##   PR         51      102    126     22
##   RS        111      304    139     48
rownames(tf)
## [1] "SP" "PR" "RS"
colnames(tf)
## [1] "consumidor" "produtor"   "escola"     "outras"
margin.table(tf,1)
## 
##  SP  PR  RS 
## 648 301 602
margin.table(tf,2)
## 
## consumidor   produtor     escola     outras 
##        376        643        343        189
tf1 <- addmargins(tf)
tf1
##      
##       consumidor produtor escola outras  Sum
##   SP         214      237     78    119  648
##   PR          51      102    126     22  301
##   RS         111      304    139     48  602
##   Sum        376      643    343    189 1551
is.matrix(tf) # confirma que a estrutura de dados de tf é uma matriz
## [1] TRUE
is.matrix(tf1) # confirma que a estrutura de dados de tf1 é uma matriz
## [1] TRUE

Alternativamente, podemos obter o mesmo resultado aplicando as seguintes funções: apply(), rbind() e cbind().

apply(tf,1,sum)
##  SP  PR  RS 
## 648 301 602
apply(tf,2,sum)
## consumidor   produtor     escola     outras 
##        376        643        343        189
tf2 <- rbind(cbind(tf,apply(tf,1,sum)),apply(cbind(tf,apply(tf,1,sum)),2,sum))
rownames(tf2) <- c(rownames(tf),"total")
colnames(tf2) <- c(colnames(tf),"total")
tf2
##       consumidor produtor escola outras total
## SP           214      237     78    119   648
## PR            51      102    126     22   301
## RS           111      304    139     48   602
## total        376      643    343    189  1551
is.matrix(tf2)
## [1] TRUE
consumidor produtor escola outras total
SP 214 237 78 119 648
PR 51 102 126 22 301
RS 111 304 139 48 602
total 376 643 343 189 1551

5.2 Tabela de frequências relativas

Uma tabela de frequências relativas de dupla entrada para as variáveis estado e tipo de cooperativa pode ser construída com um dos seguintes scripts.

#
# Script 1
#
tf.p <- (tf/sum(tf))
tf3 <- (tf.p)*100
tf3 <- addmargins(tf3)
rownames(tf3) <- c(rownames(tf),"total")
colnames(tf3) <- c(colnames(tf),"total")
round(tf3,1)
##        
##         consumidor produtor escola outras total
##   SP          13.8     15.3    5.0    7.7  41.8
##   PR           3.3      6.6    8.1    1.4  19.4
##   RS           7.2     19.6    9.0    3.1  38.8
##   total       24.2     41.5   22.1   12.2 100.0
#
# Alternativamente, script 2
#
tf4 <- (tf.p)*100
tf4 <- rbind(cbind(tf4,apply(tf4,1,sum)),apply(cbind(tf4,apply(tf4,1,sum)),2,sum))
rownames(tf4) <- c(rownames(tf),"total")
colnames(tf4) <- c(colnames(tf),"total")
round(tf4,1)
##       consumidor produtor escola outras total
## SP          13.8     15.3    5.0    7.7  41.8
## PR           3.3      6.6    8.1    1.4  19.4
## RS           7.2     19.6    9.0    3.1  38.8
## total       24.2     41.5   22.1   12.2 100.0

5.3 Tabela de frequências relativas condicionais

Uma tabela de frequências relativas condicionais de dupla entrada para as variáveis estado e tipo de cooperativa pode ser construída utilizando a função prop.table(). O segundo argumento desta função indica se frequências relativas condicionais devem ser calculadas em relação aos totais marginais das linhas (se margin=1) ou se frequências relativas condicionais devem ser calculadas em relação aos totais marginais das colunas (se margin=2).

tf5 <- prop.table(tf,margin=1)
round(tf5*100,1)
##     
##      consumidor produtor escola outras
##   SP       33.0     36.6   12.0   18.4
##   PR       16.9     33.9   41.9    7.3
##   RS       18.4     50.5   23.1    8.0
tf5 <- rbind(tf5,margin.table(tf,2)/sum(tf))
tf5 <- cbind(tf5,margin.table(tf5,1))
rownames(tf5) <- c(rownames(tf),"total")
colnames(tf5) <- c(colnames(tf),"total")
round(tf5*100,1)
##       consumidor produtor escola outras total
## SP          33.0     36.6   12.0   18.4   100
## PR          16.9     33.9   41.9    7.3   100
## RS          18.4     50.5   23.1    8.0   100
## total       24.2     41.5   22.1   12.2   100

5.4 Gráfico de barras

A função barplot() também pode ser usada para construir gráficos de barras a partir de tabelas de frequências de dupla entrada, quer sejam frequências absolutas, relativas ou relativas condicionais. Como exemplo, considere o conjunto de dados bivariado desta seção envolvendo as variáveis estado e tipo de cooperativa.

tf
##     
##      consumidor produtor escola outras
##   SP        214      237     78    119
##   PR         51      102    126     22
##   RS        111      304    139     48
t(tf)
##             
##               SP  PR  RS
##   consumidor 214  51 111
##   produtor   237 102 304
##   escola      78 126 139
##   outras     119  22  48
cores <- c("blue","red","green","yellow")
legenda <- c("Consumidor","Produtor","Escola","Outras")
barplot(t(tf),col=cores,ylab="Frequência",ylim=c(0,700))
legend(1.45,645,legend=legenda,fill=cores)

round(100*prop.table(tf,1),1)
##     
##      consumidor produtor escola outras
##   SP       33.0     36.6   12.0   18.4
##   PR       16.9     33.9   41.9    7.3
##   RS       18.4     50.5   23.1    8.0
round(100*t(prop.table(tf,1)),1)
##             
##                SP   PR   RS
##   consumidor 33.0 16.9 18.4
##   produtor   36.6 33.9 50.5
##   escola     12.0 41.9 23.1
##   outras     18.4  7.3  8.0
cores <- c("blue","red","green","yellow")
legenda <- c("Consumidor","Produtor","Escola","Outras")
barplot(t(prop.table(tf,1)),col=cores,ylab="Frequência relativa condicional",ylim=c(0,1))
legend(1.45,0.86,legend=legenda,fill=cores)

dev.off()
## null device 
##           1

5.5 Associação entre variáveis categóricas

A função chisq.test() pode ser utilizada para realiza o seguinte teste de hipóteses envolvendo duas variáveis categóricas: \[ \begin{cases} H_{0}: & \mbox{$X$ e $Y$ são independentes} \\ H_{1}: & \mbox{$X$ e $Y$ não são independentes} \\ & \mbox{($X$ e $Y$ estão associadas)} \end{cases} \] Como exemplo, considere o conjunto de dados bivariado desta seção envolvendo as variáveis estado e tipo de cooperativa. Se \(X\) representa estado e \(Y\) representa tipo de cooperativa, podemos usar a função chisq.test() para testar se estado e tipo de cooperativa são variáveis independentes. O resultado deste teste mostra que não existem evidências nos dados que suportam a hipótese nula \(H_{0}\) de independência entre as variáveis (observe que o p-value do teste é muito pequeno). Isto significa que existe associação (ou dependência) entre as variáveis estado e tipo de cooperativa. Em outras palavras, existem evidências nos dados que o tipo de cooperativa depende do estado (ou seja, da localização).

tf
##     
##      consumidor produtor escola outras
##   SP        214      237     78    119
##   PR         51      102    126     22
##   RS        111      304    139     48
round(100*prop.table(tf,1),1)
##     
##      consumidor produtor escola outras
##   SP       33.0     36.6   12.0   18.4
##   PR       16.9     33.9   41.9    7.3
##   RS       18.4     50.5   23.1    8.0
round(100*prop.table(tf,2),1)
##     
##      consumidor produtor escola outras
##   SP       56.9     36.9   22.7   63.0
##   PR       13.6     15.9   36.7   11.6
##   RS       29.5     47.3   40.5   25.4
chisq.test(tf)
## 
##  Pearson's Chi-squared test
## 
## data:  tf
## X-squared = 173.38, df = 6, p-value < 2.2e-16

O resultado que o tipo de cooperativa depende do estado está em concordância com a análise gráfica. Se estado e tipo de cooperativa fossem variáveis independentes, a distribuição de frequências relativas do tipo de cooperativa condicionada ao estado não iria variar significativamente com a localidade. O que observamos no seguinte gráfico é exatamente o contrário. De fato, o gráfico mostra que a distribuição de frequências relativas do tipo de cooperativa condicionada ao estado varia significativamente com a localidade.

## null device 
##           1

6 Análise bivariada: variáveis numéricas

Nesta seção conside o seguinte conjunto de dados bivariado, extraído do Capítulo 4 da referência Morettin & Bussab (2010). A variável \(x\) representa a renda bruta familiar mensal e a variável \(y\) representa a porcentagem da renda bruta familiar mensal que é gasta com saúde. Estamos interessados em verificar se a variável \(y\) pode ser explicada em função da variável \(x\) através de um modelo linear definido por: \[ \hat{y}=\hat{a}+\hat{b}x \] onde \(\hat{a}\) e \(\hat{b}\) são os parâmetros estimados do modelo (estimados a partir dos dados) e \(\hat{y}\) é o valor predito para a porcentagem da renda bruta familiar mensal que é gasta com saúde para um dado valor \(x\) da renda bruta familiar mensal. Os dados são:

# x: renda bruta familiar mensal
x <- c(12,16,18,20,28,30,40,48,50,54)
# y: porcentagem da renda bruta familiar mensal gasta com saúde
y <- c(7.2,7.4,7.0,6.5,6.6,6.7,6.0,5.6,6.0,5.5)
f <- LETTERS[1:10]
df2a <- data.frame(Familia=f,x,y)
df2a
##    Familia  x   y
## 1        A 12 7.2
## 2        B 16 7.4
## 3        C 18 7.0
## 4        D 20 6.5
## 5        E 28 6.6
## 6        F 30 6.7
## 7        G 40 6.0
## 8        H 48 5.6
## 9        I 50 6.0
## 10       J 54 5.5
is.data.frame(df2a)
## [1] TRUE
str(df2a)
## 'data.frame':    10 obs. of  3 variables:
##  $ Familia: chr  "A" "B" "C" "D" ...
##  $ x      : num  12 16 18 20 28 30 40 48 50 54
##  $ y      : num  7.2 7.4 7 6.5 6.6 6.7 6 5.6 6 5.5
Familia x y
A 12 7.2
B 16 7.4
C 18 7.0
D 20 6.5
E 28 6.6
F 30 6.7
G 40 6.0
H 48 5.6
I 50 6.0
J 54 5.5

6.1 Gráfico de dispersão

Considere o conjunto de dados desta seção. Podemos visualizar este conjunto de dados através de um gráfico chamado de gráfico de dispersão. Este gráfico pode ser construído utilizando a função plot() conforme o script que segue.

#
# Para construir o gráfico de dispersão não 
# necessitaremos da coluna Familia. Sendo
# assim, vamos considerar apenas as colunas
# correspondentes às variáveis x e y.
#
df2 <- df2a[,-1] 
df2
##     x   y
## 1  12 7.2
## 2  16 7.4
## 3  18 7.0
## 4  20 6.5
## 5  28 6.6
## 6  30 6.7
## 7  40 6.0
## 8  48 5.6
## 9  50 6.0
## 10 54 5.5
plot(df2$x,df2$y,type="p",xlim=c(10,60),ylim=c(4,9),xlab="Renda bruta mensal",ylab="% Gasto com saúde",pch=16)

dev.off()
## null device 
##           1

6.2 Associação linear entre variáveis numéricas

O conjunto de dados desta seção pode ser visto como duas amostras pareadas das variáveis \(x\) e \(y\), onde cada observação \(x_{i}\) na primeira amostra está pareada com uma observação \(y_{i}\) da segunda amostra, formando assim um par \((x_{i},y_{i})\) das variáveis \(x\) e \(y\), observado numa unidade experimental que, neste caso, é uma família. Após o gráfico de dispersão dos dados, outro passo importante que deve ser feito no estudo que desejamos realizar nesta seção e verificar se existe associação linear entre as variáveis \(x\) e \(y\). Como \(x\) e \(y\) são ambas variáveis numéricas, isto pode ser feito calculando o coeficiente de correlação amostral (de Pearson) definido por \[ r=\frac{\sum_{i}(x_{i}-\bar{x})(y_{i}-\bar{y})} {\sqrt{\sum_{i}(x_{i}-\bar{x})^{2}\cdot\sum_{i}(y_{i}-\bar{y})^{2}}} \] que é um estimador do coeficiente de correlação populacional entre \(x\) e \(y\), definido por \[ \rho=\rho(x,y)=\frac{Cov(x,y)}{\sigma_{x}\cdot\sigma_{y}} \] e geralmente desconhecido. Além disso, o seguinte teste de hipóteses deve ser realizado: \[ \begin{cases} H_{0}: & \rho=0\hspace{0.5cm}(\mbox{Não existe correlação entre $x$ e $y$})\\ H_{1}: & \rho\not=0 \hspace{0.5cm}(\mbox{Existe correlação entre $x$ e $y$}). \end{cases} \] O seguinte script porporciona funções para calcular \(r\) (a função cor()) e testar \(H_{0}:\rho=0\) (a função cor.test()).

summary(df2)
##        x              y        
##  Min.   :12.0   Min.   :5.500  
##  1st Qu.:18.5   1st Qu.:6.000  
##  Median :29.0   Median :6.550  
##  Mean   :31.6   Mean   :6.450  
##  3rd Qu.:46.0   3rd Qu.:6.925  
##  Max.   :54.0   Max.   :7.400
c(var(df2$x),var(df2$y))
## [1] 238.0444444   0.4316667
c(sd(df2$x),sd(df2$y))
## [1] 15.4286890  0.6570134
cov(df2$x,df2$y)
## [1] -9.533333
cor(df2$x,df2$y)
## [1] -0.9404625
cov(df2)
##            x          y
## x 238.044444 -9.5333333
## y  -9.533333  0.4316667
cor(df2,method="pearson")
##            x          y
## x  1.0000000 -0.9404625
## y -0.9404625  1.0000000
cor.test(df2$x,df2$y,method="pearson")
## 
##  Pearson's product-moment correlation
## 
## data:  df2$x and df2$y
## t = -7.826, df = 8, p-value = 5.114e-05
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.9861500 -0.7621149
## sample estimates:
##        cor 
## -0.9404625

Os resultados mostram que \(r=\hat{\rho}=-0.9404625\). Ou seja, a variável renda bruta familiar mensal é fortemente correlacionada como a variável porcentagem da renda bruta familiar mensal gasta com saúde e esta correlação é negativa, que significa que quanto maior for a renda bruta menor será a porcentagem da renda bruta gasta com saúde e vice-versa. Além disso, o resultado do teste mostra que não existem evidências nos dados que suportam a hipótese \(H_{0}\) de correlação nula (independência entre as variáveis supondo normalidade). Observe que o p-value do teste é muito pequeno. Isto significa que a correlação linear (ou associação linear ou dependência linear) entre as variáveis renda bruta familiar mensal e porcentagem da renda bruta familiar mensal gasta com saúde é estatisticamente significativa.

6.3 Estimação da reta de mínimos quadrados

Como existe uma correlação estatisticamente significativa entre as variáveis renda bruta familiar mensal (representada por \(x\)) e porcentagem da renda bruta familiar mensal gasta com saúde (representada por \(y\)), estamos agora interessados em construir o modelo linear definido por: \[ \hat{y}=\hat{a}+\hat{b}x \] onde \(\hat{a}\) e \(\hat{b}\) são parâmetros estimados do modelo e \(\hat{y}\) é o valor predito para a porcentagem da renda bruta familiar mensal que é gasta com saúde para um dado valor \(x\) da renda bruta familiar mensal. Podemos usar a função lm() para desenvolver este modelo, conforme o seguinte script.

modelo <- lm(y~x,data=df2)
summary(modelo)
## 
## Call:
## lm(formula = y ~ x, data = df2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.41456 -0.09842 -0.01481  0.14090  0.32524 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  7.715534   0.178214  43.294 8.94e-11 ***
## x           -0.040049   0.005117  -7.826 5.11e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2369 on 8 degrees of freedom
## Multiple R-squared:  0.8845, Adjusted R-squared:   0.87 
## F-statistic: 61.25 on 1 and 8 DF,  p-value: 5.114e-05
anova(modelo)
## Analysis of Variance Table
## 
## Response: y
##           Df Sum Sq Mean Sq F value    Pr(>F)    
## x          1 3.4362  3.4362  61.246 5.114e-05 ***
## Residuals  8 0.4488  0.0561                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
plot(df2,type="p",xlim=c(10,60),ylim=c(4,9),xlab="Renda bruta mensal",ylab="% Gasto com saúde",pch=16)
abline(modelo,col="red")

dev.off()
## null device 
##           1

Os resultados mostram que o modelo estimado é dado por: \[ \hat{y}=7.715534-0.040049x. \] Este modelo está representado pela linha vermelha no gráfico acima e pode ser aplicado para proporcionar um valor predito para a porcentagem da renda bruta familiar mensal que é gasta com saúde para um dado valor \(x\) da renda bruta familiar mensal inicialmente não observada nos dados. Por exemplo, digamos que queremos prever a porcentagem da renda bruta familiar mensal que é gasta com saúde para o valor \(x=33\) de renda bruta familiar mensal. Manualmente, basta fazer a seguinte conta: \[ \hat{y}=7.715534-0.040049(33)=6.393917. \] Alternativamente, esta predição pode ser feita automática utilizando a função predict().

predict(modelo,data.frame(x=33))
##        1 
## 6.393932
#
# Se desejar predições para diversos valores ao mesmo tempo
#
predict(modelo,data.frame(x=c(23,33,43)))
##        1        2        3 
## 6.794417 6.393932 5.993447
#
# Note que também
#
names(modelo)
##  [1] "coefficients"  "residuals"     "effects"       "rank"         
##  [5] "fitted.values" "assign"        "qr"            "df.residual"  
##  [9] "xlevels"       "call"          "terms"         "model"
coefficients(modelo)
## (Intercept)           x 
##  7.71553398 -0.04004854
x0 <- c(23,33,43)
y.hat <- coefficients(modelo)[1]+coefficients(modelo)[2]*x0
y.hat
## [1] 6.794417 6.393932 5.993447

7 Análise bivariada: categórica e numérica

Nesta seção considere novamente o conjunto de dados utilizado nas quatro primeiras seções deste material. Particularmente, aqui nesta seção, estamos interessados no conjunto de dados bivariado envolvendo as variáveis grau de instrução e salário. Este conjunto de dados contém, portanto, uma variável categórica e outra numérica. Os dados são:

df3 <- subset(df,select=c("grau_instrucao","salario"))
colnames(df3) <- c("Grau_instrucao","Salario")
levels(df3$Grau_instrucao) <- c("Fundamental","Medio","Superior")
str(df3)
## 'data.frame':    36 obs. of  2 variables:
##  $ Grau_instrucao: Ord.factor w/ 3 levels "Fundamental"<..: 1 1 1 2 1 1 1 1 2 2 ...
##  $ Salario       : num  4 4.56 5.25 5.73 6.26 6.66 6.86 7.39 7.59 7.44 ...
head(df3)
##   Grau_instrucao Salario
## 1    Fundamental    4.00
## 2    Fundamental    4.56
## 3    Fundamental    5.25
## 4          Medio    5.73
## 5    Fundamental    6.26
## 6    Fundamental    6.66

Nossa análise se torna mais fácil se ordenarmos os dados conforme os níveis da variável grau de instrução.

f <- which(df3$Grau_instrucao==levels(df3$Grau_instrucao)[1])
m <- which(df3$Grau_instrucao==levels(df3$Grau_instrucao)[2])
s <- which(df3$Grau_instrucao==levels(df3$Grau_instrucao)[3])
df3o <- df3[c(f,m,s),]
df3o
##    Grau_instrucao Salario
## 1     Fundamental    4.00
## 2     Fundamental    4.56
## 3     Fundamental    5.25
## 5     Fundamental    6.26
## 6     Fundamental    6.66
## 7     Fundamental    6.86
## 8     Fundamental    7.39
## 12    Fundamental    8.46
## 14    Fundamental    8.95
## 18    Fundamental    9.80
## 23    Fundamental   12.00
## 27    Fundamental   13.85
## 4           Medio    5.73
## 9           Medio    7.59
## 10          Medio    7.44
## 11          Medio    8.12
## 13          Medio    8.74
## 15          Medio    9.13
## 16          Medio    9.35
## 17          Medio    9.77
## 20          Medio   10.76
## 21          Medio   11.06
## 22          Medio   11.59
## 25          Medio   13.23
## 26          Medio   13.60
## 28          Medio   14.69
## 29          Medio   14.71
## 30          Medio   15.99
## 32          Medio   16.61
## 35          Medio   19.40
## 19       Superior   10.53
## 24       Superior   12.79
## 31       Superior   16.22
## 33       Superior   17.26
## 34       Superior   18.75
## 36       Superior   23.30

Podemos usar a função boxplot() para obter uma visualização gráfica deste conjunto de dados.

boxplot(df3o$Salario~df3o$Grau_instrucao,
        xlab="Grau de instrução",ylab="Salário",
        col=c("lightblue","lightsalmon","lightgreen"))

Sintese numérica por ser obtida como segue:

n <- as.vector(c(table(df3o$Grau_instrucao),sum(table(df3o$Grau_instrucao))))
todos <- as.vector(summary(df3o$Salario))
g.f <- summary(subset(df3o,subset=Grau_instrucao==levels(df3o$Grau_instrucao)[1])$Salario)
g.m <- summary(subset(df3o,subset=Grau_instrucao==levels(df3o$Grau_instrucao)[2])$Salario)
g.s <- summary(subset(df3o,subset=Grau_instrucao==levels(df3o$Grau_instrucao)[3])$Salario)
g.f <- as.vector(g.f);g.m <- as.vector(g.m);g.s <- as.vector(g.s)
dp.f <- sd(subset(df3o,subset=Grau_instrucao==levels(df3o$Grau_instrucao)[1])$Salario)
dp.m <- sd(subset(df3o,subset=Grau_instrucao==levels(df3o$Grau_instrucao)[2])$Salario)
dp.s <- sd(subset(df3o,subset=Grau_instrucao==levels(df3o$Grau_instrucao)[3])$Salario)
dp.t <- sd(df3o$Salario)
dp <- c(dp.f,dp.m,dp.s,dp.t);var <- dp^(2)
resumo <- data.frame(Fundamental=g.f,Médio=g.m,Superior=g.s,Todos=todos)
resumo <- rbind(n,resumo,var,dp)
rownames(resumo) <- c("n","Min","Q1","Mediana","Média","Q3","Máx","Variância","Desvio Padrão")
resumo
##               Fundamental     Médio  Superior     Todos
## n               12.000000 18.000000  6.000000 36.000000
## Min              4.000000  5.730000 10.530000  4.000000
## Q1               6.007500  8.837500 13.647500  7.552500
## Mediana          7.125000 10.910000 16.740000 10.165000
## Média            7.836667 11.528333 16.475000 11.122222
## Q3               9.162500 14.417500 18.377500 14.060000
## Máx             13.850000 19.400000 23.300000 23.300000
## Variância        8.740679 13.802297 20.271950 21.044766
## Desvio Padrão    2.956464  3.715144  4.502438  4.587458