In [1]:
suppressMessages ( library ( dplyr ) )
suppressMessages ( library ( ggplot2 ) )
options(dplyr.summarise.inform = FALSE)

1. Um estudo observacional caso-controle foi conduzido para investigar a associação entre a ocorrência de uma mutação e uma doença. Os dados coletados de duas populações são apresentados a seguir. tabela1Lista3.PNG

a) Calcule (à mão) a estatística razão de chances (OR: odds ratio) para cada população. Adote um modelo de regressão logística para analisar os dados de cada população. Obtenha o intervalo de confiança para o OR. Interprete.

In [2]:
# Construindo dataframe's por pop
# pop 1
pop1 = cbind ( c ( c ( rep ( "Casos" , 100 ) , rep ( "Controles" , 900 ) ) ) , c ( rep ( "Mutacao" , 10 ) , rep ( "Normal" , 90 ) , rep ( "Mutacao" , 90 ) , rep ( "Normal" , 810 ) ) )
pop1Df = pop1 %>% as.data.frame ( ) %>% rename ( "doenca" = "V1" , "status" = "V2" ) %>% mutate ( "Pop" = 1 )
# pop 2
pop2 = cbind ( c ( c ( rep ( "Casos" , 60 ) , rep ( "Controles" , 30 ) ) ) , c ( rep ( "Mutacao" , 40 ) , rep ( "Normal" , 20 ) , rep ( "Mutacao" , 20 ) , rep ( "Normal" , 10 ) ) )
pop2Df = pop2 %>% as.data.frame ( ) %>% rename ( "doenca" = "V1" , "status" = "V2" ) %>% mutate ( "Pop" = 2 )

# Juntando Dataframes
dfTot = rbind ( pop1Df , pop2Df )
In [3]:
# Construindo tabelas
tablePop1 = table ( dfTot [ dfTot$Pop == 1 , "doenca" ] , dfTot [ dfTot$Pop == 1 , "status" ] )
tablePop2 = table ( dfTot [ dfTot$Pop == 2 , "doenca" ] , dfTot [ dfTot$Pop == 2 , "status" ] )
# Checando se foram construídos corretamente
print ( tablePop1 )
print ( tablePop2 )
           
            Mutacao Normal
  Casos          10     90
  Controles      90    810
           
            Mutacao Normal
  Casos          40     20
  Controles      20     10
In [4]:
# Calculo manual
orPop1Manual = ( tablePop1 [ 1 , 1 ] / tablePop1 [ 2 , 1 ] ) / ( tablePop1 [ 1 , 2 ] / tablePop1 [ 2 , 2 ] )
orPop2Manual = ( tablePop2 [ 1 , 1 ] / tablePop2 [ 2 , 1 ] ) / ( tablePop2 [ 1 , 2 ] / tablePop2 [ 2 , 2 ] )

print ( paste ( "Temos que a OR para a população 1 é dada por:" , orPop1Manual ) )
print ( paste ( "Temos que a OR para a população 2 é dada por:" , orPop2Manual ) )
[1] "Temos que a OR para a população 1 é dada por: 1"
[1] "Temos que a OR para a população 2 é dada por: 1"
In [5]:
# Ajuste no dataframe
dfTot = dfTot %>% mutate ( resposta = ifelse ( doenca == "Casos" , 1 , 0 ) , status = relevel ( status , ref = "Normal" ) )

# Ajustes do modelo logístico
modeloPop1 = glm ( resposta ~ status , family = binomial ( link = "logit" ) , data = dfTot [ dfTot$Pop == 1 , ] )
modeloPop2 = glm ( resposta ~ status , family = binomial ( link = "logit" ) , data = dfTot [ dfTot$Pop == 2 , ] )
In [6]:
tabelaResumoPop1 = summary ( modeloPop1 )
print ( tabelaResumoPop1 )
Call:
glm(formula = resposta ~ status, family = binomial(link = "logit"), 
    data = dfTot[dfTot$Pop == 1, ])

Deviance Residuals: 
   Min      1Q  Median      3Q     Max  
-0.459  -0.459  -0.459  -0.459   2.146  

Coefficients:
                Estimate Std. Error z value Pr(>|z|)    
(Intercept)   -2.197e+00  1.111e-01  -19.78   <2e-16 ***
statusMutacao -1.248e-15  3.513e-01    0.00        1    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 650.17  on 999  degrees of freedom
Residual deviance: 650.17  on 998  degrees of freedom
AIC: 654.17

Number of Fisher Scoring iterations: 4

In [7]:
# Possibilidade - ja envolvendo conceito de contrastes
# pop1OrInf = exp ( modeloPop1$coefficients[2] - ( qnorm ( 0.975 ) * sqrt ( t( c ( 0 , 1 ) ) %*% vcov ( modeloPop1 ) %*% c ( 0 , 1 ) ) ) )
# pop1OrSup = exp ( modeloPop1$coefficients[2] + ( qnorm ( 0.975 ) * sqrt ( t( c ( 0 , 1 ) ) %*% vcov ( modeloPop1 ) %*% c ( 0 , 1 ) ) ) )

pop1OrInf = exp ( tabelaResumoPop1$coefficients[2,1] - ( qnorm ( 0.975 ) * tabelaResumoPop1$coefficients[2,2] ) )
pop1OrSup = exp ( tabelaResumoPop1$coefficients[2,1] + ( qnorm ( 0.975 ) * tabelaResumoPop1$coefficients[2,2] ) )

print ( paste0 ( "O intervalo de confiança para a OR da pop 1 é de [" , round ( pop1OrInf , 2 ) , ";" , round ( pop1OrSup , 2 ) , "]" ) )
[1] "O intervalo de confiança para a OR da pop 1 é de [0.5;1.99]"
In [8]:
tabelaResumoPop2 = summary ( modeloPop2 )
print ( tabelaResumoPop2 )
Call:
glm(formula = resposta ~ status, family = binomial(link = "logit"), 
    data = dfTot[dfTot$Pop == 2, ])

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.4823  -1.4823   0.9005   0.9005   0.9005  

Coefficients:
               Estimate Std. Error z value Pr(>|z|)  
(Intercept)   6.931e-01  3.873e-01    1.79   0.0735 .
statusMutacao 3.686e-16  4.743e-01    0.00   1.0000  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 114.57  on 89  degrees of freedom
Residual deviance: 114.57  on 88  degrees of freedom
AIC: 118.57

Number of Fisher Scoring iterations: 4

In [9]:
pop2OrInf = exp ( tabelaResumoPop2$coefficients[2,1] - ( qnorm ( 0.975 ) * tabelaResumoPop2$coefficients[2,2] ) )
pop2OrSup = exp ( tabelaResumoPop2$coefficients[2,1] + ( qnorm ( 0.975 ) * tabelaResumoPop2$coefficients[2,2] ) )

print ( paste0 ( "O intervalo de confiança para a OR da pop 2 é de [" , round ( pop2OrInf , 2 ) , ";" , round ( pop2OrSup , 2 ) , "]" ) )
[1] "O intervalo de confiança para a OR da pop 2 é de [0.39;2.53]"

Conclusão: Para ambas as populações, não rejeitamos a hipótese de que não há efeito de mutação sobre a razão de chances de se ter a doença. Isto é, não rejeitamos a hipótese de que indivíduos que tenham a mutação tenham uma chance maior se ter a doença ao se comparar com a chance de indivíduos que não a tenham, pois em ambos os casos, o intervalo de 95% de confiança incluir o valor 1 (chances iguais).

b) Some as correspondentes caselas de dados das duas populações e calcule (à mão) a estatística OR. Como em a), adote um modelo de regressão logística para analisar os dados. Obtenha o intervalo de confiança para o OR. Interprete.

In [10]:
# Tabela (desconsiderando pops)
tabelaTot = table ( dfTot$doenca , dfTot$status )
print ( tabelaTot )
           
            Normal Mutacao
  Casos        110      50
  Controles    820     110
In [11]:
# Calculo manual
orTotManual = ( tabelaTot [ 1 , 1 ] / tabelaTot [ 2 , 1 ] ) / ( tabelaTot [ 1 , 2 ] / tabelaTot [ 2 , 2 ] )

print ( paste ( "Temos que a OR para a população total é dada por:" , orTotManual ) )
[1] "Temos que a OR para a população total é dada por: 0.295121951219512"
In [12]:
modeloTot = glm ( resposta ~ status , family = binomial ( link = "logit" ) , data = dfTot )

tabelaResumoTot = summary ( modeloTot )
print ( tabelaResumoTot )
Call:
glm(formula = resposta ~ status, family = binomial(link = "logit"), 
    data = dfTot)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-0.8657  -0.5018  -0.5018  -0.5018   2.0663  

Coefficients:
              Estimate Std. Error z value Pr(>|z|)    
(Intercept)    -2.0088     0.1015 -19.784  < 2e-16 ***
statusMutacao   1.2204     0.1985   6.148 7.85e-10 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 909.27  on 1089  degrees of freedom
Residual deviance: 874.83  on 1088  degrees of freedom
AIC: 878.83

Number of Fisher Scoring iterations: 4

In [13]:
popTotOrInf = exp ( tabelaResumoTot$coefficients[2,1] - ( qnorm ( 0.975 ) * tabelaResumoTot$coefficients[2,2] ) )
popTotOrSup = exp ( tabelaResumoTot$coefficients[2,1] + ( qnorm ( 0.975 ) * tabelaResumoTot$coefficients[2,2] ) )

print ( paste0 ( "O intervalo de confiança para a OR da pop tot é de [" , round ( popTotOrInf , 2 ) , ";" , round ( popTotOrSup , 2 ) , "]" ) )
[1] "O intervalo de confiança para a OR da pop tot é de [2.3;5]"

Conclusão: Analisando agora as duas populações conjuntamente, rejeitamos a hipótese de que não há efeito de mutação sobre a razão de chances de se ter a doença. Isto é, concluímos que indivíduos que tenham a mutação têm uma chance entre 2,3 e 5 vezes maior de ter a doença ao se comparar com indivíduos que não a tenham, considerando o intervalo de 95% de confiança.

c) Com base nos resultados obtidos em a) e b), use o Paradoxo de Simpson para explicar um possível efeito de confundimento que pode ocorrer em estudos de associação considerando dados estratificados desse tipo.

Quando o resultado de associação marginal possui uma direção diferente para cada associação condicional, temos o paradoxo de Simpson. No caso dos itens anteriores, observamos que não existia associação entre a doença e e a mutação observando as populações separadamente (associações condicionais). Porém, ao observarmos o resultado marginal (populações combinadas), obervamos a associação entre as covariáveis (conclusão na direção oposta).

d) Para realizar uma meta-análise destes dados, adote um modelo de regressão logística considerando os estratos populacionais como um fator sob estudo.

In [14]:
dfFin = dfTot %>% mutate ( Pop = as.factor ( Pop ) )
modeloCompleto = glm ( resposta ~ status + Pop , family = binomial ( link = "logit" ) , data = dfFin )

tabelaResumoCompleto = summary ( modeloCompleto )
print ( tabelaResumoCompleto )
Call:
glm(formula = resposta ~ status + Pop, family = binomial(link = "logit"), 
    data = dfFin)

Deviance Residuals: 
   Min      1Q  Median      3Q     Max  
-1.482  -0.459  -0.459  -0.459   2.146  

Coefficients:
                Estimate Std. Error z value Pr(>|z|)    
(Intercept)   -2.197e+00  1.091e-01 -20.137   <2e-16 ***
statusMutacao -4.631e-15  2.823e-01   0.000        1    
Pop2           2.890e+00  2.945e-01   9.816   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 909.27  on 1089  degrees of freedom
Residual deviance: 764.74  on 1087  degrees of freedom
AIC: 770.74

Number of Fisher Scoring iterations: 4

In [15]:
statusOrInf = exp ( tabelaResumoCompleto$coefficients[2,1] - ( qnorm ( 0.975 ) * tabelaResumoCompleto$coefficients[2,2] ) )
statusOrSup = exp ( tabelaResumoCompleto$coefficients[2,1] + ( qnorm ( 0.975 ) * tabelaResumoCompleto$coefficients[2,2] ) )

popOrInf = exp ( tabelaResumoCompleto$coefficients[3,1] - ( qnorm ( 0.975 ) * tabelaResumoCompleto$coefficients[3,2] ) )
popOrSup = exp ( tabelaResumoCompleto$coefficients[3,1] + ( qnorm ( 0.975 ) * tabelaResumoCompleto$coefficients[3,2] ) )

print ( paste0 ( "O intervalo de confiança para a OR de mutação em relação normal é de [" , round ( statusOrInf , 2 ) , ";" , round ( statusOrSup , 2 ) , "]" ) )
print ( paste0 ( "O intervalo de confiança para a OR da pop 2 em relação a pop 1 é de [" , round ( popOrInf , 2 ) , ";" , round ( popOrSup , 2 ) , "]" ) )
[1] "O intervalo de confiança para a OR de mutação em relação normal é de [0.58;1.74]"
[1] "O intervalo de confiança para a OR da pop 2 em relação a pop 1 é de [10.11;32.06]"

Conclusão: não rejeitamos a hipótese de que indivíduos que tenham a mutação têm uma chance maior se ter a doença ao se comparar com a chance de indivíduos que não a tenham, pois o intervalo de 95% de confiança inclui o valor 1 (chances iguais). Porém, rejeitamos a hipótese de que não há efeitos de populações sobre a chance de se ter a doença. Estima-se que indivíduos da população 2 tenham uma chance entre 10,11 e 32,06 maior de se ter a doença ao se comparar com indivíduos da população 1 (levando-se em consideração o intervalo de confiança de 95%).

2. A tabela a seguir apresenta resultados de um estudo de associação de um SNP de interesse com uma doença. Para validação dos resultados do estudo também foram genotipados 20 marcadores considerados neutrais (isto é, que não estão associados com a doença e nem com o SNP sob estudo). As estatísticas Qui-quadrado (com 1 g.l.) da associação destes marcadores com a doença estão também apresentadas. tabela2Lista3.PNG

a) Preencha, a seu critério, a casela (casos, GG) com um valor de frequência. Realize um teste de associação do SNP com a doença com base na razão de chances (OR). Considere os seguintes casos: 2 graus de liberdade e 1 grau de liberdade (efeito linear do SNP). Interprete os resultados.

In [16]:
casosGG = 9

infoSnps = cbind ( c ( c ( rep ( "Casos" , 25+20+casosGG ) , rep ( "Controles" , 5+20+45 ) ) ) , c ( rep ( "CC" , 25 ) , rep ( "CG" , 20 ) , rep ( "GG" , casosGG ) , rep ( "CC" , 5 ) , rep ( "CG" , 20 ) , rep ( "GG" , 45 ) ) )
dfSnps = infoSnps %>% as.data.frame ( ) %>% rename ( "doenca" = "V1" , "snp" = "V2" )

table ( dfSnps$doenca , dfSnps$snp )
           
            CC CG GG
  Casos     25 20  9
  Controles  5 20 45
In [17]:
# caso com 2 g.l.
df2Graus = dfSnps %>% mutate ( snp = as.factor ( snp ) , resposta = ifelse ( doenca == "Casos" , 1 , 0 ) ) %>% mutate ( snp = relevel ( snp , ref = "CC" ) )

modelo2Graus = glm ( resposta ~ snp , family = binomial ( link = "logit" ) , data = df2Graus )

tabelaResumo2Graus = summary ( modelo2Graus )
print ( tabelaResumo2Graus )
Call:
glm(formula = resposta ~ snp, family = binomial(link = "logit"), 
    data = df2Graus)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.8930  -0.6039  -0.6039   0.6039   1.8930  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)   1.6094     0.4899   3.285  0.00102 ** 
snpCG        -1.6094     0.5831  -2.760  0.00578 ** 
snpGG        -3.2189     0.6110  -5.268 1.38e-07 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 169.83  on 123  degrees of freedom
Residual deviance: 131.15  on 121  degrees of freedom
AIC: 137.15

Number of Fisher Scoring iterations: 3

In [18]:
snpCGInf2G = exp ( tabelaResumo2Graus$coefficients[2,1] - ( qnorm ( 0.975 ) * tabelaResumo2Graus$coefficients[2,2] ) )
snpCGSup2G = exp ( tabelaResumo2Graus$coefficients[2,1] + ( qnorm ( 0.975 ) * tabelaResumo2Graus$coefficients[2,2] ) )

snpGGInf2G = exp ( tabelaResumo2Graus$coefficients[3,1] - ( qnorm ( 0.975 ) * tabelaResumo2Graus$coefficients[3,2] ) )
snpGGSup2G = exp ( tabelaResumo2Graus$coefficients[3,1] + ( qnorm ( 0.975 ) * tabelaResumo2Graus$coefficients[3,2] ) )

print ( paste0 ( "A OR do genótipo CG em relação ao genótipo CC é: " , round ( exp ( tabelaResumo2Graus$coefficients[2,1] ) , 2 ) ) )
print ( paste0 ( "A OR do genótipo GG em relação ao genótipo CC é: " , round ( exp ( tabelaResumo2Graus$coefficients[3,1] ) , 2 ) ) )

print ( paste0 ( "O intervalo de confiança para a OR do genótipo CG em relação ao genótipo CC é de [" , round ( snpCGInf2G , 2 ) , ";" , round ( snpCGSup2G , 2 ) , "]" ) )
print ( paste0 ( "O intervalo de confiança para a OR do genótipo GG em relação ao genótipo CC é de [" , round ( snpGGInf2G , 2 ) , ";" , round ( snpGGSup2G , 2 ) , "]" ) )
[1] "A OR do genótipo CG em relação ao genótipo CC é: 0.2"
[1] "A OR do genótipo GG em relação ao genótipo CC é: 0.04"
[1] "O intervalo de confiança para a OR do genótipo CG em relação ao genótipo CC é de [0.06;0.63]"
[1] "O intervalo de confiança para a OR do genótipo GG em relação ao genótipo CC é de [0.01;0.13]"
In [19]:
df1Grau = dfSnps %>% mutate ( qtG = ifelse ( snp == "CC" , 0 , ifelse ( snp == "CG" , 1 , 2 ) ) , resposta = ifelse ( doenca == "Casos" , 1 , 0 ) )

modelo1Grau = glm ( resposta ~ qtG , family = binomial ( link = "logit" ) , data = df1Grau )

tabelaResumo1Grau = summary ( modelo1Grau )
print ( tabelaResumo1Grau )
Call:
glm(formula = resposta ~ qtG, family = binomial(link = "logit"), 
    data = df1Grau)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.8930  -0.6039  -0.6039   0.6039   1.8930  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)   1.6094     0.4068   3.956 7.62e-05 ***
qtG          -1.6094     0.2994  -5.375 7.65e-08 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 169.83  on 123  degrees of freedom
Residual deviance: 131.15  on 122  degrees of freedom
AIC: 135.15

Number of Fisher Scoring iterations: 3

In [20]:
snpCGInf1G = exp ( tabelaResumo1Grau$coefficients[2,1] - ( qnorm ( 0.975 ) * tabelaResumo1Grau$coefficients[2,2] ) )
snpCGSup1G = exp ( tabelaResumo1Grau$coefficients[2,1] + ( qnorm ( 0.975 ) * tabelaResumo1Grau$coefficients[2,2] ) )

snpGGInf1G = exp ( 2 * tabelaResumo1Grau$coefficients[2,1] - ( qnorm ( 0.975 ) * 2 * tabelaResumo1Grau$coefficients[2,2] ) )
snpGGSup1G = exp ( 2 * tabelaResumo1Grau$coefficients[2,1] + ( qnorm ( 0.975 ) * 2 * tabelaResumo1Grau$coefficients[2,2] ) )

print ( paste0 ( "A OR do genótipo CG em relação ao genótipo CC é: " , round ( exp ( tabelaResumo1Grau$coefficients[2,1] ) , 2 ) ) )
print ( paste0 ( "A OR do genótipo GG em relação ao genótipo CC é: " , round ( exp ( 2 * tabelaResumo1Grau$coefficients[2,1] ) , 2 ) ) )

print ( paste0 ( "O intervalo de confiança para a OR do genótipo CG em relação ao genótipo CC é de [" , round ( snpCGInf1G , 2 ) , ";" , round ( snpCGSup1G , 2 ) , "]" ) )
print ( paste0 ( "O intervalo de confiança para a OR do genótipo GG em relação ao genótipo CC é de [" , round ( snpGGInf1G , 2 ) , ";" , round ( snpGGSup1G , 2 ) , "]" ) )
[1] "A OR do genótipo CG em relação ao genótipo CC é: 0.2"
[1] "A OR do genótipo GG em relação ao genótipo CC é: 0.04"
[1] "O intervalo de confiança para a OR do genótipo CG em relação ao genótipo CC é de [0.11;0.36]"
[1] "O intervalo de confiança para a OR do genótipo GG em relação ao genótipo CC é de [0.01;0.13]"

Conclusão: Em ambos os modelos, há efeito estatisticamente significante de associação do SNP com a doença. No modelo com 2 graus de liberdade, estimamos a OR da doença para os genótipos CG e GG em relação a CC, que resultou em 0,2 e 0,04 respectivamente. Neste cenário, o intervalo de 95% de confiança para a primeira OR é $[0,06 ; 0,63]$, e o da segunda é dado por $[0,01 ; 0,13]$. Isto é, a chance de um indivíduo de genótipo CG ter a doença é entre 6% e 63% da chance de um indivíduo cujo genótipo é CC. Já a chance de um indivíduo de genótipo GG ter a doença é entre 1% e 13% da chance de um indivíduo cujo genótipo é CC.

Já no modelo com efeito linear de SNP (1 grau de liberdade), temos que o parâmetro estimado $\beta$ trata-se do acréscimo no log da OR em relação ao genótipo CC esperado para cada alelo G acrescentado no genótipo do indivíduo. A OR em relação ao genótipo CC para este modelo coincide com o modelo anterior (0,2 e 0,04 para os genótipos CG e GG) apesar da mudança de interpretação do coeficiente estimado. Para este modelo, os intervalos de confiança calculados para a OR de se ter a doença dos genótipos CG e GG em relação ao CC são dados respectivamente por $[0,11;0,36]$ e $[0,01;0,13]$. A interpretação segue da mesma forma como a anterior.

Observação: Repare que no caso acima, o ajuste dos modelos com 1 e com 2 graus de liberdade resultaram nas mesmas estimativas para as OR. Porém este fenômeno nem sempre ocorre, e por isto segue o contraexemplo, ilustrando outro cenário.

In [21]:
casosGG2 = 25

infoSnps2 = cbind ( c ( c ( rep ( "Casos" , 25+20+casosGG2 ) , rep ( "Controles" , 5+20+45 ) ) ) , c ( rep ( "CC" , 25 ) , rep ( "CG" , 20 ) , rep ( "GG" , casosGG2 ) , rep ( "CC" , 5 ) , rep ( "CG" , 20 ) , rep ( "GG" , 45 ) ) )
dfSnps2 = infoSnps2 %>% as.data.frame ( ) %>% rename ( "doenca" = "V1" , "snp" = "V2" )

table ( dfSnps2$doenca , dfSnps2$snp )
           
            CC CG GG
  Casos     25 20 25
  Controles  5 20 45
In [22]:
# caso com 2 g.l.
df2Graus2 = dfSnps2 %>% mutate ( snp = as.factor ( snp ) , resposta = ifelse ( doenca == "Casos" , 1 , 0 ) ) %>% mutate ( snp = relevel ( snp , ref = "CC" ) )

modelo2Graus2 = glm ( resposta ~ snp , family = binomial ( link = "logit" ) , data = df2Graus2 )

tabelaResumo2Graus2 = summary ( modelo2Graus2 )
print ( tabelaResumo2Graus2 )
Call:
glm(formula = resposta ~ snp, family = binomial(link = "logit"), 
    data = df2Graus2)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.8930  -0.9400  -0.1681   1.1774   1.4350  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)   1.6094     0.4899   3.285  0.00102 ** 
snpCG        -1.6094     0.5831  -2.760  0.00578 ** 
snpGG        -2.1972     0.5497  -3.997 6.42e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 194.08  on 139  degrees of freedom
Residual deviance: 173.73  on 137  degrees of freedom
AIC: 179.73

Number of Fisher Scoring iterations: 4

In [23]:
snpCGInf2G2 = exp ( tabelaResumo2Graus2$coefficients[2,1] - ( qnorm ( 0.975 ) * tabelaResumo2Graus2$coefficients[2,2] ) )
snpCGSup2G2 = exp ( tabelaResumo2Graus2$coefficients[2,1] + ( qnorm ( 0.975 ) * tabelaResumo2Graus2$coefficients[2,2] ) )

snpGGInf2G2 = exp ( tabelaResumo2Graus2$coefficients[3,1] - ( qnorm ( 0.975 ) * tabelaResumo2Graus2$coefficients[3,2] ) )
snpGGSup2G2 = exp ( tabelaResumo2Graus2$coefficients[3,1] + ( qnorm ( 0.975 ) * tabelaResumo2Graus2$coefficients[3,2] ) )

print ( paste0 ( "A OR do genótipo CG em relação ao genótipo CC é: " , round ( exp ( tabelaResumo2Graus2$coefficients[2,1] ) , 2 ) ) )
print ( paste0 ( "A OR do genótipo GG em relação ao genótipo CC é: " , round ( exp ( tabelaResumo2Graus2$coefficients[3,1] ) , 2 ) ) )

print ( paste0 ( "O intervalo de confiança para a OR do genótipo CG em relação ao genótipo CC é de [" , round ( snpCGInf2G2 , 2 ) , ";" , round ( snpCGSup2G2 , 2 ) , "]" ) )
print ( paste0 ( "O intervalo de confiança para a OR do genótipo GG em relação ao genótipo CC é de [" , round ( snpGGInf2G2 , 2 ) , ";" , round ( snpGGSup2G2 , 2 ) , "]" ) )
[1] "A OR do genótipo CG em relação ao genótipo CC é: 0.2"
[1] "A OR do genótipo GG em relação ao genótipo CC é: 0.11"
[1] "O intervalo de confiança para a OR do genótipo CG em relação ao genótipo CC é de [0.06;0.63]"
[1] "O intervalo de confiança para a OR do genótipo GG em relação ao genótipo CC é de [0.04;0.33]"
In [24]:
df1Grau2 = dfSnps2 %>% mutate ( qtG = ifelse ( snp == "CC" , 0 , ifelse ( snp == "CG" , 1 , 2 ) ) , resposta = ifelse ( doenca == "Casos" , 1 , 0 ) )

modelo1Grau2 = glm ( resposta ~ qtG , family = binomial ( link = "logit" ) , data = df1Grau2 )

tabelaResumo1Grau2 = summary ( modelo1Grau2 )
print ( tabelaResumo1Grau2 )
Call:
glm(formula = resposta ~ qtG, family = binomial(link = "logit"), 
    data = df1Grau2)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.7492  -0.9045  -0.1029   1.0523   1.4774  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)   1.2857     0.3726   3.451 0.000559 ***
qtG          -0.9840     0.2420  -4.065 4.79e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 194.08  on 139  degrees of freedom
Residual deviance: 175.25  on 138  degrees of freedom
AIC: 179.25

Number of Fisher Scoring iterations: 4

In [25]:
snpCGInf1G2 = exp ( tabelaResumo1Grau2$coefficients[2,1] - ( qnorm ( 0.975 ) * tabelaResumo1Grau2$coefficients[2,2] ) )
snpCGSup1G2 = exp ( tabelaResumo1Grau2$coefficients[2,1] + ( qnorm ( 0.975 ) * tabelaResumo1Grau2$coefficients[2,2] ) )

snpGGInf1G2 = exp ( 2 * tabelaResumo1Grau2$coefficients[2,1] - ( qnorm ( 0.975 ) * 2 * tabelaResumo1Grau2$coefficients[2,2] ) )
snpGGSup1G2 = exp ( 2 * tabelaResumo1Grau2$coefficients[2,1] + ( qnorm ( 0.975 ) * 2 * tabelaResumo1Grau2$coefficients[2,2] ) )

print ( paste0 ( "A OR do genótipo CG em relação ao genótipo CC é: " , round ( exp ( tabelaResumo1Grau2$coefficients[2,1] ) , 2 ) ) )
print ( paste0 ( "A OR do genótipo GG em relação ao genótipo CC é: " , round ( exp ( 2 * tabelaResumo1Grau2$coefficients[2,1] ) , 2 ) ) )

print ( paste0 ( "O intervalo de confiança para a OR do genótipo CG em relação ao genótipo CC é de [" , round ( snpCGInf1G2 , 2 ) , ";" , round ( snpCGSup1G2 , 2 ) , "]" ) )
print ( paste0 ( "O intervalo de confiança para a OR do genótipo GG em relação ao genótipo CC é de [" , round ( snpGGInf1G2 , 2 ) , ";" , round ( snpGGSup1G2 , 2 ) , "]" ) )
[1] "A OR do genótipo CG em relação ao genótipo CC é: 0.37"
[1] "A OR do genótipo GG em relação ao genótipo CC é: 0.14"
[1] "O intervalo de confiança para a OR do genótipo CG em relação ao genótipo CC é de [0.23;0.6]"
[1] "O intervalo de confiança para a OR do genótipo GG em relação ao genótipo CC é de [0.05;0.36]"

Conclusão: Em ambos os modelos, há efeito estatisticamente significante de associação do SNP com a doença. No modelo com 2 graus de liberdade, estimamos a OR da doença para os genótipos CG e GG em relação a CC, que resultou em 0,2 e 0,11 respectivamente. Neste cenário, o intervalo de 95% de confiança para a primeira OR é $[0,06 ; 0,63]$, e o da segunda é dado por $[0,04 ; 0,33]$. Isto é, a chance de um indivíduo de genótipo CG ter a doença é entre 6% e 63% da chance de um indivíduo cujo genótipo é CC. Já a chance de um indivíduo de genótipo GG ter a doença é entre 4% e 33% da chance de um indivíduo cujo genótipo é CC.

Já no modelo com efeito linear de SNP (1 grau de liberdade), temos que o parâmetro estimado $\beta$ trata-se do acréscimo no log da OR em relação ao genótipo CC esperado para cada alelo G acrescentado no genótipo do indivíduo. A OR em relação ao genótipo CC para este modelo não coincide com o modelo anterior, sendo 0,37 e 0,14 para os genótipos CG e GG, respectivamente. Para este modelo, os intervalos de confiança calculados para a OR de se ter a doença dos genótipos CG e GG em relação ao CC são dados respectivamente por $[0,23;0,60]$ e $[0,05;0,36]$. A interpretação segue da mesma forma como a anterior.

b) Use a informação dos marcadores neutrais para validação dos resultados do estudo. Para isso, considere os seguintes procedimentos:

  • Pritchard e Rosenberg (1999) propuseram o uso de marcadores neutrais para construir um teste da inexistência de confundimento devido à estrutura de população (hipótese H0). Considerando os testes de associação de cada um de L marcadores neutrais obtém-se a estatística
    $\chi^2_p = \chi^2_{M1} + \chi^2_{M2} + ... + \chi^2_{ML}$
    cuja significância é verificada com base na distribuição Qui-quadrado com L graus de liberdade. Se não houver indicação de estrutura de população por este teste, a associação com o gene candidato deve ser considerada válida.
  • Devlin e Roeder (1999) propuseram corrigir a estatística Qui-quadrado do gene candidato (digamos, $\chi^2_c$) dividindo por um fator de inflação, tal que:
    $\chi^2_{GC} = \frac{\chi^2_c}{max\{\hat{\lambda} , 1\}}; \hat{\lambda} = \frac{mediana(\chi^2_{M1},...,\chi^2_{ML})}{0.4549}$
    O valor 0.4549 corresponde ao quantil 50% da distribuição Qui-quadrado com 1 g.l. Os L marcadores são denominados neutrais ou de controle genômico (GC). A associação do gene candidato é então testada avaliando a significância da estatística corrigida, $\chi^2_{GC}$, na distribuição Qui-quadrado com 1 g.l.
In [26]:
# valores Dados
chiQuadrados = c ( 0.1101,0.1485,1.3233,0.0191,0.1935,0.0158,1.0742,0.0642,0.0039,0.0101,0.7083,0.0268,2.4173,2.2925,6.4653,0.2750,10.8274,4.7093,0.3573, 0.5707 )

# Primeiro criterio
valorSoma = sum(chiQuadrados)
print ( "Primeiro critério:" )
print ( paste0 ( "O valor da soma das estatísticas Qui-quadrado dos marcadores é dada por " , round ( valorSoma , 2 ) ) )
print ( paste0 ( "Considerando 95% de confiança, temos que o intervalo de não rejeição de H0 é dado por [" , round ( qchisq ( 0.025 , df = length ( chiQuadrados ) ) , 2 ) , "," , round ( qchisq ( 0.975 , df = length ( chiQuadrados ) ) , 2 ) , "]" ) )

# Segundo criterio
lambdaHat = quantile ( chiQuadrados , .5 )[[1]] / qchisq ( .5 , 1)
fatorCorrecao = max ( 1 , lambdaHat )
print ( "Segundo critério:" )
print ( paste0 ( "O fator de correção é dado por: " , fatorCorrecao ) )

# Modelo 2 g.l.
print ( "Para o modelo com 2 graus de liberdade:" )
probCorrigidaBetaCG = 1 - pchisq ( ( tabelaResumo2Graus$coefficients[2,3] ^ 2)/fatorCorrecao  , df = 1 )
print ( paste0 ( "O nível descritivo do teste é: " , probCorrigidaBetaCG ) )

probCorrigidaBetaGG = 1 - pchisq ( ( tabelaResumo2Graus$coefficients[3,3] ^ 2)/fatorCorrecao  , df = 1 )
print ( paste0 ( "O nível descritivo do teste é: " , probCorrigidaBetaGG  ) )

# Modelo 1 g.l.
print ( "Para o modelo com 1 grau de liberdade:" )
probCorrigidaBeta = 1 - pchisq ( ( tabelaResumo1Grau$coefficients[2,3] ^ 2)/fatorCorrecao  , df = 1 )
print ( paste0 ( "O nível descritivo do teste é: " , probCorrigidaBeta ) )
[1] "Primeiro critério:"
[1] "O valor da soma das estatísticas Qui-quadrado dos marcadores é dada por 31.61"
[1] "Considerando 95% de confiança, temos que o intervalo de não rejeição de H0 é dado por [9.59,34.17]"
[1] "Segundo critério:"
[1] "O fator de correção é dado por: 1"
[1] "Para o modelo com 2 graus de liberdade:"
[1] "O nível descritivo do teste é: 0.00577670687294218"
[1] "O nível descritivo do teste é: 1.37764214813707e-07"
[1] "Para o modelo com 1 grau de liberdade:"
[1] "O nível descritivo do teste é: 7.65050465201256e-08"

Conclusão: Pela primeira abordagem, concluímos que não há indícios de subestrutura de população (pois a estatística observada 31,61 pertence à região de não rejeição de $H_0$). Logo, se validam as conclusões já feitas a respeito da relação do gene com a doença. Pela segunda abordagem, temos que não houve correção, pois $\hat{\lambda} < 1$. Logo, as conclusões permanecem as mesmas também, como esperado.

3. Condidere os dados do GAW16 (Genetic Analysis Workshop 16) disponíveis no edisciplinas. O arquivo “phen.txt” contém informações fenotípicas de 2062 indivíduos classificados de acordo com o diagnóstico de artrite reumatóide, sendo 868 cases (Affection=1) e 1194 controles (Affection=0). Para esses mesmos indivíduos, os arquivos “gene6.6.txt, gene6.7.txt, gene6.8.txt, gene6.9.txt e gene6.10.txt” contêm genótipos de SNPs no cromossomo 6, em que 0, 1 e 2 correspondem ao número de cópias de um alelo alvo.

a) Realize uma análise de associação de cada SNP com a doença (casos e controles). Adote um modelo de regressão logística. Apresente os resultados em um gráfico Manhattan e em um gráfico Vulcão. Há SNPs significantes?

In [27]:
gen = read.table ( "~/Monitoria/Dados/gen6.6.txt" , sep = "," , header = T, quote = '"')

for ( indice in 7:10 ){
    
    baseAux = read.table ( paste0 ( "~/Monitoria/Dados/gen6.", indice ,".txt" ) , sep = "," , header = T, quote = '"')
    gen = cbind ( gen , baseAux )
    
}


phen = read.table ( "~/Monitoria/Dados/phen.txt" , sep = "," , header = T )
head ( gen , 5 )
head ( phen , 5 )
A data.frame: 5 × 4743
rs1033955rs17658803rs13196368rs834362rs10484378rs12529004rs986759rs834372rs834370rs634162...rs16890428rs10807192rs742538rs10456462rs13206817rs1931765rs12214213rs4299828rs12176364rs6458047
<int><int><int><int><int><int><int><int><int><int>...<int><int><int><int><int><int><int><int><int><int>
11011001000...1011000 000
20110100100...0200202 000
32002002010...0110202 000
41011001010...0101010NA01
51011001010...0111101 000
A data.frame: 5 × 10
IDAffectionSexDRB1_1DRB1_2SENumSEStatusAntiCCPRFUWDRB
<fct><int><fct><int><int><int><fct><dbl><dbl><int>
1D00249490F012yesNANA1
2D00243020F001yesNANA0
3D00231510F001yesNANA0
4D00220420F001yesNANA0
5D00212750F001yesNANA0
In [28]:
gen$ID2 = 1:nrow ( gen )
phen$ID2 = 1:nrow ( phen )
mergeDf = merge ( phen , gen , by = "ID2" )
head ( mergeDf )
A data.frame: 6 × 4754
ID2IDAffectionSexDRB1_1DRB1_2SENumSEStatusAntiCCPRFUW...rs16890428rs10807192rs742538rs10456462rs13206817rs1931765rs12214213rs4299828rs12176364rs6458047
<int><fct><int><fct><int><int><int><fct><dbl><dbl>...<int><int><int><int><int><int><int><int><int><int>
11D00249490F012yesNANA...1011000 000
22D00243020F001yesNANA...0200202 000
33D00231510F001yesNANA...0110202 000
44D00220420F001yesNANA...0101010NA01
55D00212750F001yesNANA...0111101 000
66D00211630F001yesNANA...0200111 101
In [29]:
snpNames = colnames ( gen ) [ colnames ( gen ) != "ID2" ]
infoRelevante = NULL

for ( snp in snpNames ){
    
# Modelo aditivo
    mergeFilt = mergeDf [ !(is.na ( mergeDf$Affection ) ) & !( is.na ( mergeDf[ , snp ] ) ) ,  ]
    modeloAdit = glm ( mergeFilt$Affection ~ mergeFilt[ , snp ] , family = binomial ( link = "logit" ) )
    tabelaResumoAdit = summary ( modeloAdit )
    
    infoRelevante = rbind ( infoRelevante , c ( snp , tabelaResumoAdit$coefficients[ 2 , 1 ] , tabelaResumoAdit$coefficients[ 2 , 4 ] ) )
    
}
infosDf = infoRelevante %>% as.data.frame ( )
infosDf %>% head ( 5 )
A data.frame: 5 × 3
V1V2V3
<fct><fct><fct>
1rs1033955 -0.1419798212050530.0306058477522889
2rs17658803-0.1222767621823790.226015904048075
3rs131963680.179610020090004 0.00539406162568879
4rs834362 -0.1882334153744880.00623558272950267
5rs10484378-0.0448815765113980.709217708493499
In [30]:
infosDfExp = infosDf %>% 
mutate ( snpName = as.character ( V1 ) , beta = as.numeric ( as.character ( V2 ) ) , valorP = as.numeric ( as.character ( V3 ) ) , tam = nchar ( as.character ( V1 ) ) ) %>% 
select ( snpName , beta , valorP , tam ) %>% 
arrange ( tam , snpName ) %>% 
mutate ( Ord = 1:nrow ( infosDf ) , escalaManhattan = -log10 ( valorP ) , chr = 6 ) %>% 
arrange ( -escalaManhattan )

infosDfExp %>% head ( 5 )
A data.frame: 5 × 7
snpNamebetavalorPtamOrdescalaManhattanchr
<chr><dbl><dbl><int><int><dbl><dbl>
1rs23951751.7658558.915784e-909157389.049846
2rs660895 1.6935411.095295e-878 42586.960476
3rs69100711.5355081.429079e-789280677.844946
4rs23951631.5182641.031410e-769157075.986576
5rs37633091.4613792.352862e-739224972.628406
In [31]:
bfLimit = -log10 ( 0.05 / nrow ( infosDfExp ) )
infosDfExp %>% ggplot ( ) + 
geom_point ( data = subset ( infosDfExp , escalaManhattan < bfLimit ) , aes ( x = Ord , y = escalaManhattan ) ) +
geom_hline ( yintercept = bfLimit , col = "red" ) +
geom_text( data = subset ( infosDfExp , escalaManhattan > bfLimit ) , aes ( Ord , escalaManhattan , label = snpName ) , col = "red") +
labs ( x = "Índice SNP" , y = "-log10p" , title = "Gráfico Manhattan" )
In [32]:
print ( paste0 ( "Temos que " , sum ( infosDfExp$escalaManhattan > bfLimit ) , " em " , nrow(infosDfExp) ,
               ", isto é, ", 100 * round ( sum ( infosDfExp$escalaManhattan > bfLimit ) / nrow(infosDfExp) , 4 ) ,
                "% dos snps possuem significância estatística considerando o critério selecionado"
               )  )
[1] "Temos que 503 em 4743, isto é, 10.61% dos snps possuem significância estatística considerando o critério selecionado"
In [33]:
bfLimit = -log10 ( 0.05 / nrow ( infosDfExp ) )
infosDfExp %>% ggplot ( ) + 
geom_point ( data = subset ( infosDfExp , escalaManhattan < bfLimit ) , aes ( x = beta , y = escalaManhattan ) ) +
geom_hline ( yintercept = bfLimit , col = "red" ) +
geom_text( data = subset ( infosDfExp , escalaManhattan > bfLimit ) , aes ( beta , escalaManhattan , label = snpName ) , col = "red") +
labs ( x = "Variação esperada no logOR para cada unidade do alelo alternativo" , y = "-log10p" , title = "Gráfico de Vulcão" )
In [34]:
print ( paste0 ( "Temos que " , sum ( infosDfExp$escalaManhattan > bfLimit & infosDfExp$beta > 0 ) ,
                " snp's possuem beta > 0 e que " , 
               sum ( infosDfExp$escalaManhattan > bfLimit & infosDfExp$beta < 0 ) ,
                " snp's possuem beta < 0"
               )  )
[1] "Temos que 218 snp's possuem beta > 0 e que 285 snp's possuem beta < 0"

Conclusão: A partir das análises feitas sobre modelos com apenas 1 grau de liberdade e levando-se em consideração a correção de Bonferroni, nota-se que há 503 SNP's com efeito estatisticamente siginificante, dos quais em 218 deles a quantidade de alelos alternativos aumenta a chance de se ter artrite reumatóide em relação ao genótipo de referência, enquanto que o efeito é o oposto para 285 snp's.

b) Considere todos os 5 arquivos com dados de genótipos de SNPs. Padronize esses dados, subtraindo a média e dividindo pelo desvio padrão, e obtenha os dois primeiros Componentes Principais (CP). Usando esses CP, construa um gráfico de dispersão dos 2062 indivíduos. Identifique os grupos caso e controle. Os CP discriminam os indivíduos? Comente.

In [35]:
dfPadronizado = mergeDf
dfPadronizado[ , snpNames ] = scale ( dfPadronizado[ , snpNames ] )
dfPadronizado %>% head ( 5 )
A data.frame: 5 × 4754
ID2IDAffectionSexDRB1_1DRB1_2SENumSEStatusAntiCCPRFUW...rs16890428rs10807192rs742538rs10456462rs13206817rs1931765rs12214213rs4299828rs12176364rs6458047
<int><fct><int><fct><int><int><int><fct><dbl><dbl>...<dbl><dbl><dbl><dbl><dbl><dbl><dbl><dbl><dbl><dbl>
11D00249490F012yesNANA... 2.5129715-1.2676895 0.3739146 0.8569724-1.2573422-0.704084-1.2538545-0.7048728-0.4264573-0.703887
22D00243020F001yesNANA...-0.3564104 1.6085338-1.0821611-0.8195714 1.6209784-0.704084 1.6259390-0.7048728-0.4264573-0.703887
33D00231510F001yesNANA...-0.3564104 0.1704222 0.3739146-0.8195714 1.6209784-0.704084 1.6259390-0.7048728-0.4264573-0.703887
44D00220420F001yesNANA...-0.3564104 0.1704222-1.0821611 0.8569724-1.2573422 1.038799-1.2538545 NA-0.4264573 1.041854
55D00212750F001yesNANA...-0.3564104 0.1704222 0.3739146 0.8569724 0.1818181-0.704084 0.1860422-0.7048728-0.4264573-0.703887
In [36]:
nenhum_na <- function(x) !any(is.na(x))
PCdf = dfPadronizado[ , snpNames ] %>% select_if ( nenhum_na )
colunasRestantes = colnames ( PCdf )
In [37]:
print ( paste0 ( "Temos " , length ( colunasRestantes ) , " snps com preenchimento completo" ) )
matrizCov = cov( PCdf )
decomp = eigen ( matrizCov )
rownames ( decomp$vectors ) = colnames ( matrizCov )
[1] "Temos 1279 snps com preenchimento completo"
In [38]:
decomp$values %>% as.data.frame ( ) %>%
rename ( "autoValores" = "." ) %>% 
mutate ( order = 1 : n() ) %>% 
ggplot ( ) + geom_point ( aes ( x = order ,  y = autoValores ) ) + 
labs ( x = "Índice" , y = "Auto valor" , "Gráfico de autovalores" )

print ( paste0 ( "Os dois primeiros componentes principais representam " , 
                100*round ( sum ( decomp$values[1:2] ) / sum ( decomp$values ) , 4) ,
               "% da variância total dos dados que não possuem informações faltantes") )
[1] "Os dois primeiros componentes principais representam 5.25% da variância total dos dados que não possuem informações faltantes"
In [39]:
dfParaGrafico = dfPadronizado [ , c ( "ID" , "Affection" , colunasRestantes ) ]
matrizCalculo = as.matrix ( dfParaGrafico [ , colunasRestantes ] , ncol = length ( colunasRestantes ) )
rownames ( matrizCalculo ) = dfPadronizado$ID
In [40]:
dfParaGrafico$PC1 = matrizCalculo %*% decomp$vectors[,1]
dfParaGrafico$PC2 = matrizCalculo %*% decomp$vectors[,2]

dfParaGrafico %>% ggplot ( aes ( x = PC1 , y = PC2 , col = as.factor ( Affection ) ) ) +
geom_point ( ) +
labs ( x = "Componente 1" , y = "Componente 2" , col = "Affection" , title = "Gráfico dos dois primeiros CP's" )

Conclusão Após padronizar os dados e fazer a análise de componentes principais, conclui-se que os CP não discriminam os indivíduos nas duas primeiras dimensões.

c) Ajuste modelos de regressão logística usando os dois primeiros CP como covariáveis além do sexo dos indivíduos. Construa os gráficos Manhattan e Vulcão. Há SNPs significantes?

In [41]:
dfMergePcs = merge ( mergeDf , dfParaGrafico [ , c ( "ID" , "PC1" , "PC2" )] , by = "ID" )

infoRelevantePt2 = NULL

for ( snp in snpNames ){
    
# Modelo aditivo
    mergeFilt = dfMergePcs [ !(is.na ( dfMergePcs$Affection ) ) & !( is.na ( dfMergePcs[ , snp ] ) ) ,  ]
    modeloAdit = glm ( mergeFilt$Affection ~ mergeFilt$PC1 + mergeFilt$PC2 + mergeFilt$Sex + mergeFilt[ , snp ] , family = binomial ( link = "logit" ) )
    tabelaResumoAdit = summary ( modeloAdit )
    
    infoRelevantePt2 = rbind ( infoRelevantePt2 , c ( snp , tabelaResumoAdit$coefficients[ 5 , 1 ] , tabelaResumoAdit$coefficients[ 5 , 4 ] ) )
    
}
infosDfPt2 = infoRelevantePt2 %>% as.data.frame ( )
infosDfPt2 %>% head ( 5 )
A data.frame: 5 × 3
V1V2V3
<fct><fct><fct>
1rs1033955 -0.1539593654300420.0231349078774273
2rs17658803-0.1346193083050070.198008109974658
3rs131963680.200348472865067 0.00267890801796891
4rs834362 -0.2114416941898610.00298304276653166
5rs10484378-0.0810451744626260.517191258974479
In [42]:
infosDfExpPt2 = infosDfPt2 %>% 
mutate ( snpName = as.character ( V1 ) , beta = as.numeric ( as.character ( V2 ) ) , valorP = as.numeric ( as.character ( V3 ) ) , tam = nchar ( as.character ( V1 ) ) ) %>% 
select ( snpName , beta , valorP , tam ) %>% 
arrange ( tam , snpName ) %>% 
mutate ( Ord = 1:nrow ( infosDf ) , escalaManhattan = -log10 ( valorP ) , chr = 6 ) %>% 
arrange ( -escalaManhattan )

infosDfExpPt2 %>% head ( 5 )
A data.frame: 5 × 7
snpNamebetavalorPtamOrdescalaManhattanchr
<chr><dbl><dbl><int><int><dbl><dbl>
1rs23951751.6698182.648721e-729157371.576966
2rs660895 1.6091076.920245e-708 42569.159886
3rs69100711.4264351.020792e-599280658.991066
4rs23951631.4096379.862716e-589157057.006006
5rs37633091.3464501.026304e-539224952.988726
In [43]:
bfLimit = -log10 ( 0.05 / nrow ( infosDfExpPt2 ) )
infosDfExpPt2 %>% ggplot ( ) + 
geom_point ( data = subset ( infosDfExpPt2 , escalaManhattan < bfLimit ) , aes ( x = Ord , y = escalaManhattan ) ) +
geom_hline ( yintercept = bfLimit , col = "red" ) +
geom_text( data = subset ( infosDfExpPt2 , escalaManhattan > bfLimit ) , aes ( Ord , escalaManhattan , label = snpName ) , col = "red") +
labs ( x = "Índice SNP" , y = "-log10p" , title = "Gráfico Manhattan" )
In [44]:
print ( paste0 ( "Temos que " , sum ( infosDfExpPt2$escalaManhattan > bfLimit ) , " em " , nrow(infosDfExpPt2) ,
               ", isto é, ", 100 * round ( sum ( infosDfExpPt2$escalaManhattan > bfLimit ) / nrow(infosDfExpPt2) , 4 ) ,
                "% dos snps possuem significância estatística considerando o critério selecionado"
               )  )
[1] "Temos que 483 em 4743, isto é, 10.18% dos snps possuem significância estatística considerando o critério selecionado"
In [45]:
bfLimit = -log10 ( 0.05 / nrow ( infosDfExpPt2 ) )
infosDfExpPt2 %>% ggplot ( ) + 
geom_point ( data = subset ( infosDfExpPt2 , escalaManhattan < bfLimit ) , aes ( x = beta , y = escalaManhattan ) ) +
geom_hline ( yintercept = bfLimit , col = "red" ) +
geom_text( data = subset ( infosDfExpPt2 , escalaManhattan > bfLimit ) , aes ( beta , escalaManhattan , label = snpName ) , col = "red") +
labs ( x = "Variação esperada no logOR para cada unidade do alelo alternativo" , y = "-log10p" , title = "Gráfico de Vulcão" )
In [46]:
print ( paste0 ( "Temos que " , sum ( infosDfExpPt2$escalaManhattan > bfLimit & infosDfExpPt2$beta > 0 ) ,
                " snp's possuem beta > 0 e que " , 
               sum ( infosDfExpPt2$escalaManhattan > bfLimit & infosDfExpPt2$beta < 0 ) ,
                " snp's possuem beta < 0"
               )  )
[1] "Temos que 210 snp's possuem beta > 0 e que 273 snp's possuem beta < 0"

Conclusão: A partir das análises feitas sobre modelos com apenas 1 grau de liberdade e levando-se em consideração a correção de Bonferroni, nota-se que há 483 SNP's com efeito estatisticamente siginificante, dos quais em 210 deles a quantidade de alelos alternativos aumenta a chance de se ter artrite reumatóide em relação ao genótipo de referência, enquanto que o efeito é o oposto para 273 snp's.

d) Compare os resultados dos modelos de regressão logística ajustados em a) e c).

In [47]:
mergeAll = merge ( infosDfExp , infosDfExpPt2 , by = "snpName" )
head ( mergeAll )
A data.frame: 6 × 13
snpNamebeta.xvalorP.xtam.xOrd.xescalaManhattan.xchr.xbeta.yvalorP.ytam.yOrd.yescalaManhattan.ychr.y
<chr><dbl><dbl><int><int><dbl><dbl><dbl><dbl><int><int><dbl><dbl>
1rs1000308 0.3669362781.009443e-029718 1.99591806-0.017210359.084247e-0197180.041711056
2rs1001310-0.0314345126.376290e-019719 0.19543196-0.005583559.356856e-0197190.028870066
3rs1002985-0.5922124603.312802e-049720 3.47980456-0.346237534.357181e-0297201.360794366
4rs1003581-0.2200902921.455909e-029721 1.83686566-0.158552958.615179e-0297211.064735716
5rs1003878-0.8252112558.562159e-19972218.06741676-0.648851578.254618e-1097229.083303026
6rs1003979-0.0036145879.551560e-019723 0.01992576 0.098513571.446064e-0197230.839812396
In [48]:
# Os mesmos snps se mantiveram estatisticamente significantes?
mergeAll = mergeAll %>% mutate ( signifSimples = ifelse ( escalaManhattan.x > bfLimit , "signifSimples" , "NSignifSimples" ) , signifCompleto = ifelse ( escalaManhattan.y > bfLimit , "signifCompleto" , "NSignifCompleto" ) )
table ( mergeAll$signifSimples , mergeAll$signifCompleto )
                
                 NSignifCompleto signifCompleto
  NSignifSimples            4058            182
  signifSimples              202            301
In [50]:
# Como se dão as relações entre os valores-p e os betas?
mergeAll = mergeAll %>% mutate ( signifConjunta = ifelse ( escalaManhattan.x > bfLimit & escalaManhattan.y > bfLimit , "Ambos",
                                                         ifelse ( escalaManhattan.x > bfLimit , "Simples" ,
                                                                 ifelse ( escalaManhattan.y > bfLimit , "Completo" , "Nenhum") ) ) )
mergeAll  %>% 
ggplot ( aes ( x = beta.x , y = beta.y , colour = signifConjunta ) ) +
geom_point ( ) +
labs ( x = "Beta - ajuste simples" , y = "Beta - ajuste completo" , title = "Comparação de ajustes dos efeitos estimados e signif. estatística (Bonferroni)" , colour = "Significância" )

mergeAll  %>% 
ggplot ( aes ( x = escalaManhattan.x , y = escalaManhattan.y ) ) +
geom_point ( ) +
labs ( x = "-log10(Valor-p) - ajuste simples" , y = "-log10(Valor-p) - ajuste completo" , title = "Comparação de valores descritivos" )

Conclusões: Temos que as conclusões a respeito da significância estatística dos snps é similar para 4359 dos mesmos (301 estatisticamente significantes e 4058 não). Porém no modelo simples (sem demais covariáveis) temos que 202 snps foram dados como significantes enquanto no modelo completo (covariáveis de sexo e primeiros dois CP's acrescentadas) foram dados como não significantes. O mesmo fenômeno ocorre com 182 snps, do modelo completo em relação ao modelo simples. Já a respeito da relação entre as estimativas dos efeitos para cada unidade alélica de cada snp sobre a chance de se ter a artrite reumatóide, e sobre seus valores descritivos, pode-se observar que:

  • existe uma tendência dos $\beta$'s estimados serem próximos e cuja significância estatística, levando-se em consideração o método de Bonferroni para comparações múltiplas, é similar (reta principal);
  • nas redondezas das estimativas de $\beta$ próximas de 0 do modelo simples, existe uma nuvem de pontos em que $\beta$'s do modelo completo são positivos e estatisticamente significantes (levando-se em conta a correção para múltiplos testes);
  • Existe uma tendência dos valores-p estimados serem próximos (reta principal no segundo gráfico).