knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE
)
knitr::opts_knit$set(root.dir = normalizePath(".."))
Esse é um notebook do R, escrito em R Markdown. Quando tu executas o código no notebook, os resultados aparecem embaixo do código. Eu acho uma forma legal de garantir a reprodutibilidade das análises e de mesclar comentário com resultados das análises.
Eu estou usando, com o consentimento da minha aluna, uma base de dados proveniente de um TCC que eu orientei sobre marcas humanizadas. Ela coletou 326 casos via Qualtrics, em um design de 2 fatores entre participantes: Marca “Controle” e Marca “Humanizada”.
A condição de controle apresenta o tweet stream de uma marca fictícia de celulares, lidando com um problema de uma cliente.
A condição experimental apresenta a mesma marca fictícia em um tom conversacional descontraído, com gifs, imagens e informalidade.
Existem problemas de design e confounds (e.g., reclamação só na condição controle, múltiplas dimensões da humanização manipuladas de uma só vez, etc.), mas para efeitos de análise ignoraremos essas limitações por ora.
O primeiro passo é importar os dados. Eu recomendo usar sempre os dados “mais brutos”, ou seja, sem qualquer forma de processamento. No Qualtrics, essas opções são texto (TXT) ou texto - valores separados por vírgula (CSV). Ao exportar, podemos escolher se queremos os dados como variáveis nominais (“choice text”) ou números. Eu recomendo baixar os dois e usa-los de acordo com a necessidade. Não esquecer de pedir para o Qualtrics exportar a ordem da randomização das variáveis. Isso adiciona muitas variáveis à base de dados, mas é informação que pode ser útil. Outro desafio diz respeito ao formato de exportação. O Qualtrics, por default, exporta três “cabeçalhos” na base de dados, contendo nome da variável, descrições e enunciados. Se nós importarmos os dados diretos, o R julgará que todas as variáveis são strings e as operações com os dados serão limitadas (além, claro, de estarem erradas). Por isso, eu importo os dados apenas e, depois, adiciono os nomes das variáveis às bases de dados. Eu poderia abrir os dados no Excel e apagar duas linhas, mas eu quero evitar “tocar” na base de dados para minimizar chances de erro.
#importando dados numéricos como dn
require(readr)
setwd("/home/lnicolao/Google Drive/Drive/UFRGS/Ensino/20211/ADP - Experimentos/Scripts Aulas/TCC_Karen/")
dn<-read_csv("TCC_Karen_Numeros.csv",
col_names = FALSE, skip = 3)
names(dn)<-read_csv("TCC_Karen_Numeros.csv",
col_names = FALSE)[1,]
#importando dados em texto como dt
dt<-read_csv("TCC_Karen_Strings.csv",
col_names = FALSE, skip = 3)
names(dt)<-read_csv("TCC_Karen_Strings.csv",
col_names = FALSE)[1,]
Uma inspeção inicial mostra que a base “em texto” já considera as escalas como números. Podemos usar apenas essa para a análise. A função “head” mostra as primeiras cinco linhas da base / objeto. Aliás, essa função é comum a muitas linguagens de programação, inclusive ao Python.
head(dn)
head(dt)
Porque minha aluna já tinha me dito que ela testou duas vezes o questionário, eu sei que precisamos nos livrar das primeiras duas linhas de dados. Mas vamos confirmar se esse é o caso.
names(dt)
## [1] "StartDate" "EndDate" "Status"
## [4] "IPAddress" "Progress" "Duration (in seconds)"
## [7] "Finished" "RecordedDate" "ResponseId"
## [10] "RecipientLastName" "RecipientFirstName" "RecipientEmail"
## [13] "ExternalReference" "LocationLatitude" "LocationLongitude"
## [16] "DistributionChannel" "UserLanguage" "Consentimento"
## [19] "Q01" "Q02" "Q03"
## [22] "Q04" "Q05" "Q06"
## [25] "Q07" "Q08" "Q09"
## [28] "Q10" "Q11" "Q01"
## [31] "Q02" "Q03" "Q04"
## [34] "Q05" "Q06" "Q07"
## [37] "Q08" "Q09" "Q01"
## [40] "Q01" "Q02" "Q03"
## [43] "Q04_1" "Q04_2" "Q04_3"
## [46] "Q05" "Q06" "Q01"
## [49] "FL_20_DO" "CondControle_DO" "CondHumana_DO"
## [52] "Atitude_DO" "ItensHumanização_DO"
Ops. Parece que a nomeação das variáveis tem um problema. O Qualtrics nos permite nomear variáveis. Eu recomendo que as nomes sejam sempre (1) diagnósticos: nos permitam saber exatamente do que se trata a variável sem precisar recorrer ao questionário ou dicionário de variáveis e (2) simples: o menor número de caracteres possível (precisaremos digitar o nome das variáveis pelo menos uma vez), sem letras maiusculas (o R diferencia capitalização), sem acentuação (pode dar problema), não começando em números (o R não permite que objetos e variáveis tenham nomes que começam em números). Eu vou concertar os nomes das duas bases aqui. Eu li o questionário e destilei as características principais de cada variável.
nomes_corrigidos<-c("StartDate", "EndDate", "Status", "IPAddress", "Progress",
"Duration", "Finished", "RecordedDate", "ResponseId",
"RecipientLastName", "RecipientFirstName", "RecipientEmail",
"ExternalReference", "LocationLatitude", "LocationLongitude",
"DistributionChannel", "UserLanguage", "Consentimento",
"a1_reputacao", "a2_cara", "a3_prestigio", "a4_qualidade",
"a5_gosto", "a6_melhor", "a7_admiro", "a8_simpatia",
"a9_compraria", "a10_recomendaria", "a11_prefiro",
"h1_homens", "h2_humanas", "h3_amigos", "h4_personalidade",
"h5_atraente", "h6_medo", "h7_emocional", "h8_aberta",
"h9_etica", "humanizada", "genero", "idade", "escolaridade",
"freq_twitter", "freq_instagram", "freq_facebook",
"sabia_humanizada", "comentário", "sorteio", "condicao",
"CondControle_DO", "CondHumana_DO", "Atitude_DO",
"ItensHumanização_DO")
#ver se o número de variáveis nas bases "match" o número de variáveis que eu digitei
length(names(dt))
## [1] 53
length(names(dn))
## [1] 53
length(nomes_corrigidos)
## [1] 53
#já que eles todos têm o mesmo número de elementos
names(dt)<-nomes_corrigidos
names(dn)<-nomes_corrigidos
Agora sim, limpando a base de dados. Como eu havia comentado, a minha aluna rodou o estudo duas vezes e deixou esses dados na base. Precisamos eliminar.
names(dt)
## [1] "StartDate" "EndDate" "Status"
## [4] "IPAddress" "Progress" "Duration"
## [7] "Finished" "RecordedDate" "ResponseId"
## [10] "RecipientLastName" "RecipientFirstName" "RecipientEmail"
## [13] "ExternalReference" "LocationLatitude" "LocationLongitude"
## [16] "DistributionChannel" "UserLanguage" "Consentimento"
## [19] "a1_reputacao" "a2_cara" "a3_prestigio"
## [22] "a4_qualidade" "a5_gosto" "a6_melhor"
## [25] "a7_admiro" "a8_simpatia" "a9_compraria"
## [28] "a10_recomendaria" "a11_prefiro" "h1_homens"
## [31] "h2_humanas" "h3_amigos" "h4_personalidade"
## [34] "h5_atraente" "h6_medo" "h7_emocional"
## [37] "h8_aberta" "h9_etica" "humanizada"
## [40] "genero" "idade" "escolaridade"
## [43] "freq_twitter" "freq_instagram" "freq_facebook"
## [46] "sabia_humanizada" "comentário" "sorteio"
## [49] "condicao" "CondControle_DO" "CondHumana_DO"
## [52] "Atitude_DO" "ItensHumanização_DO"
E a variável sorteio. Vamos ver onde esses casos estão
head(dt$sorteio)
## [1] "KAREN - DESCONSIDERAR" "KAREN 2 - DESCONSIDERAR"
## [3] "51991838706" "51998036343"
## [5] "51980424234" "51 997799888"
São os dois primeiros casos. Vamos elimina-los das duas bases de dados. Eu vou criar uma base nova, sem esses dois casos. Eu não vou manter o mesmo nome, do contrário a base pode ser corrompida múltiplas vezes. Existem várias formas de fazer isso. Eu posso pedir para o R eliminar os casos cujas respostas para a variável sorteio são “KAREN - DESCONSIDERAR” e “KAREN 2 - DESCONSIDERAR” respectivamente. Ou, nesse caso, posso pedir só para apagar os dois primeiros casos. Daqui em diante usarei só a base “dt” que tem números nas escalas e texto quando apropriado.
d<-dt[-c(1,2),]
head(d$sorteio)
## [1] "51991838706" "51998036343"
## [3] "51980424234" "51 997799888"
## [5] "brunalimalampert@hotmail.com" "sinhorellivictoria@gmail.com"
Eu quero verificar quem acabou o questionário. Para isso, eu farei uma tabela e a colocarei em um formato mais amigável usando uma função do markdown, Kable.
require(knitr)
require(questionr)
table(d$Finished)
##
## FALSE TRUE
## 125 199
d$Acabou<-factor(d$Finished, levels = c("FALSE","TRUE"), labels = c("Não","Sim"))
t.acabou<-freq(d$Acabou, digits = 2, exclude = NA, total = T)
kable(t.acabou, caption = "Quantos acabaram o questionário")
| n | % | |
|---|---|---|
| Não | 125 | 38.58 |
| Sim | 199 | 61.42 |
| Total | 324 | 100.00 |
Muita gente não acabou o questionário. Muitos respondentes não inseriram o email ou telefone para o sorteio, outros não enviaram o questionário. TODOS os testes que eu farei aqui eliminam missings do processo de análise, e as não respostas acabariam sendo eliminadas. Mesmo assim, eu eliminarei os que não acabaram o questionário da amostra.
d.finished<-subset(d, d$Acabou == "Sim")
Agora é uma boa oportunidade para darmos uma olhada nos outliers em tempo de resposta. A aluna não utilizou nenhuma “instructional manipulation checks”, então essa é a única medida de atenção que podemos utilizar. É importante que façamos isso no começo. Se determinarmos que o tempo de resposta é uma medida diagnóstica de atenção ou de falta de comprometimento, e esse for um critério de deleção, devemos fazer isso antes de ver os resultados e de forma consistente em todas as bases investigadas.
d.finished$log_duration<-log(d.finished$Duration)
tempo<-boxplot(d.finished$log_duration)
sort(tempo$out)
## [1] 7.049255 7.125283 7.282761 7.731053 7.780303 7.872455 8.074649 8.149313
## [9] 8.574329 8.617762 9.110410
do<-subset(d.finished, (d.finished$log_duration < 7.049))
Aqui eu criarei variáveis compostas (médias) para Atitude e Humanização da Marca e extrairei o Alfa de Cronbach.
do$atitude.df <- data.frame(do$a1_reputacao, do$a2_cara, do$a3_prestigio,
do$a4_qualidade, do$a5_gosto, do$a6_melhor,
do$a7_admiro, do$a8_simpatia, do$a9_compraria,
do$a10_recomendaria, do$a11_prefiro)
do$atitude<-rowMeans(do$atitude.df, na.rm = TRUE)
do$human.df <- data.frame(do$h1_homens, do$h2_humanas, do$h3_amigos, do$h4_personalidade,
do$h5_atraente, do$h6_medo, do$h7_emocional, do$h8_aberta,
do$h9_etica)
do$human <- rowMeans(do$human.df, na.rm = TRUE)
require(psych)
alpha(do$atitude.df)
##
## Reliability analysis
## Call: alpha(x = do$atitude.df)
##
## raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
## 0.96 0.96 0.96 0.66 21 0.0042 2.3 1 0.74
##
## lower alpha upper 95% confidence boundaries
## 0.95 0.96 0.97
##
## Reliability if an item is dropped:
## raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r
## do.a1_reputacao 0.95 0.95 0.96 0.65 18 0.0049 0.0495
## do.a2_cara 0.97 0.97 0.97 0.76 32 0.0033 0.0017
## do.a3_prestigio 0.95 0.95 0.96 0.65 19 0.0047 0.0518
## do.a4_qualidade 0.95 0.95 0.96 0.66 19 0.0046 0.0528
## do.a5_gosto 0.95 0.95 0.96 0.65 18 0.0049 0.0499
## do.a6_melhor 0.95 0.95 0.96 0.65 19 0.0047 0.0507
## do.a7_admiro 0.95 0.95 0.96 0.65 19 0.0048 0.0500
## do.a8_simpatia 0.95 0.95 0.96 0.65 18 0.0049 0.0480
## do.a9_compraria 0.95 0.95 0.96 0.65 19 0.0047 0.0514
## do.a10_recomendaria 0.95 0.95 0.96 0.65 19 0.0048 0.0498
## do.a11_prefiro 0.95 0.95 0.96 0.65 19 0.0047 0.0512
## med.r
## do.a1_reputacao 0.74
## do.a2_cara 0.76
## do.a3_prestigio 0.75
## do.a4_qualidade 0.76
## do.a5_gosto 0.74
## do.a6_melhor 0.74
## do.a7_admiro 0.74
## do.a8_simpatia 0.74
## do.a9_compraria 0.74
## do.a10_recomendaria 0.74
## do.a11_prefiro 0.74
##
## Item statistics
## n raw.r std.r r.cor r.drop mean sd
## do.a1_reputacao 188 0.90 0.90 0.89 0.87 2.4 1.4
## do.a2_cara 188 0.32 0.34 0.25 0.24 2.6 1.0
## do.a3_prestigio 188 0.87 0.87 0.86 0.84 2.2 1.2
## do.a4_qualidade 188 0.84 0.84 0.83 0.81 2.2 1.1
## do.a5_gosto 188 0.91 0.90 0.90 0.88 2.4 1.3
## do.a6_melhor 188 0.87 0.87 0.86 0.84 2.1 1.1
## do.a7_admiro 188 0.89 0.88 0.88 0.86 2.2 1.3
## do.a8_simpatia 188 0.91 0.90 0.90 0.88 2.5 1.4
## do.a9_compraria 188 0.88 0.88 0.87 0.85 2.3 1.3
## do.a10_recomendaria 188 0.89 0.89 0.88 0.87 2.2 1.3
## do.a11_prefiro 188 0.87 0.87 0.86 0.84 2.0 1.1
##
## Non missing response frequency for each item
## 1 2 3 4 5 miss
## do.a1_reputacao 0.36 0.19 0.19 0.17 0.09 0
## do.a2_cara 0.18 0.22 0.44 0.14 0.02 0
## do.a3_prestigio 0.37 0.23 0.22 0.16 0.02 0
## do.a4_qualidade 0.31 0.26 0.32 0.09 0.02 0
## do.a5_gosto 0.34 0.21 0.26 0.13 0.06 0
## do.a6_melhor 0.45 0.17 0.28 0.06 0.04 0
## do.a7_admiro 0.42 0.18 0.21 0.13 0.06 0
## do.a8_simpatia 0.38 0.16 0.17 0.18 0.11 0
## do.a9_compraria 0.40 0.17 0.24 0.13 0.05 0
## do.a10_recomendaria 0.43 0.20 0.21 0.11 0.06 0
## do.a11_prefiro 0.48 0.18 0.23 0.08 0.03 0
alpha(do$human.df)
##
## Reliability analysis
## Call: alpha(x = do$human.df)
##
## raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
## 0.96 0.95 0.96 0.7 21 0.0045 2.8 1.3 0.72
##
## lower alpha upper 95% confidence boundaries
## 0.95 0.96 0.96
##
## Reliability if an item is dropped:
## raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r
## do.h1_homens 0.96 0.96 0.96 0.74 23 0.0042 0.013
## do.h2_humanas 0.95 0.95 0.95 0.69 18 0.0054 0.018
## do.h3_amigos 0.95 0.94 0.95 0.68 17 0.0056 0.015
## do.h4_personalidade 0.95 0.95 0.96 0.71 19 0.0049 0.021
## do.h5_atraente 0.96 0.96 0.96 0.74 23 0.0043 0.015
## do.h6_medo 0.95 0.95 0.95 0.69 18 0.0054 0.015
## do.h7_emocional 0.95 0.95 0.95 0.69 18 0.0054 0.019
## do.h8_aberta 0.95 0.95 0.95 0.68 17 0.0056 0.015
## do.h9_etica 0.95 0.95 0.95 0.70 18 0.0052 0.019
## med.r
## do.h1_homens 0.77
## do.h2_humanas 0.67
## do.h3_amigos 0.67
## do.h4_personalidade 0.75
## do.h5_atraente 0.77
## do.h6_medo 0.69
## do.h7_emocional 0.67
## do.h8_aberta 0.67
## do.h9_etica 0.70
##
## Item statistics
## n raw.r std.r r.cor r.drop mean sd
## do.h1_homens 188 0.68 0.70 0.65 0.62 2.6 1.2
## do.h2_humanas 188 0.91 0.91 0.90 0.89 2.7 1.6
## do.h3_amigos 188 0.94 0.93 0.93 0.92 2.8 1.7
## do.h4_personalidade 188 0.84 0.84 0.81 0.79 2.8 1.4
## do.h5_atraente 188 0.71 0.72 0.67 0.65 2.7 1.3
## do.h6_medo 188 0.91 0.90 0.90 0.88 3.0 1.8
## do.h7_emocional 188 0.91 0.91 0.90 0.88 2.8 1.6
## do.h8_aberta 188 0.93 0.92 0.93 0.91 2.9 1.8
## do.h9_etica 188 0.88 0.88 0.86 0.85 2.6 1.4
##
## Non missing response frequency for each item
## 1 2 3 4 5 miss
## do.h1_homens 0.27 0.18 0.34 0.14 0.08 0
## do.h2_humanas 0.37 0.11 0.16 0.18 0.18 0
## do.h3_amigos 0.44 0.04 0.11 0.15 0.26 0
## do.h4_personalidade 0.27 0.19 0.19 0.21 0.14 0
## do.h5_atraente 0.28 0.16 0.28 0.18 0.10 0
## do.h6_medo 0.40 0.07 0.04 0.13 0.36 0
## do.h7_emocional 0.33 0.12 0.15 0.20 0.20 0
## do.h8_aberta 0.40 0.07 0.05 0.17 0.31 0
## do.h9_etica 0.34 0.12 0.27 0.16 0.11 0
Vamos inspecionar as médias de atitude e médias de “humanização” da marca por condição. Mas antes disso, quantos casos temos por condição mesmo?
table(do$condicao)
##
## CondControle CondHumana
## 91 97
#fazendo mais "bonito"
do$condicoes <- factor(do$condicao, levels = c("CondControle", "CondHumana"),
labels = c("Controle", "Humanizada"))
t.condicao <- freq(do$condicoes, digits = 2, exclude = NA, total = T)
kable(t.condicao, caption = "Respondentes por Condição")
| n | % | |
|---|---|---|
| Controle | 91 | 48.4 |
| Humanizada | 97 | 51.6 |
| Total | 188 | 100.0 |
Mais ou menos equilibradas as condições. Agora vamos ver como as variáveis de interesse se distribuem por condições. Para isso, eu vou usar a função “describeBy”, do pacote psych.
desc.atitude <- describeBy(do$atitude,do$condicoes, mat = T, digits = 2)
names(desc.atitude)[2] <- "Condições"
row.names(desc.atitude)<-NULL
desc.human <- describeBy(do$human,do$condicoes, mat = T, digits = 2)
names(desc.human)[2] <- "Condições"
row.names(desc.human)<-NULL
desc.atitude
desc.human
kable(desc.atitude[,c(2,4:6)], caption = "Médias de Atitude por Condição Experimental")
| Condições | n | mean | sd |
|---|---|---|---|
| Controle | 91 | 1.63 | 0.65 |
| Humanizada | 97 | 2.89 | 0.93 |
kable(desc.human[,c(2,4:6)], caption = "Médias de Humanização por Condição Experimental")
| Condições | n | mean | sd |
|---|---|---|---|
| Controle | 91 | 1.64 | 0.71 |
| Humanizada | 97 | 3.79 | 0.81 |
Podemos, também, fazer gráficos, mas as informações são redundantes.
require(ggplot2)
ggplot(desc.atitude, aes(x=`Condições`, y=mean))+
geom_bar(stat = "identity", width = 0.5, fill = "lightblue")+
geom_errorbar(aes(ymax = mean + (1.96*se), ymin=mean - (1.96*se)),
position=position_dodge(width=0.9), width=0.25)+
# coord_cartesian(ylim = c(1, 3))+
labs(title="Atitude em Relação à Marca por Condição Experimental",
y="Atitude Média", x="Condições")
ggplot(desc.human, aes(x=`Condições`, y=mean))+
geom_bar(stat = "identity", width = 0.5, fill = "pink")+
geom_errorbar(aes(ymax = mean + (1.96*se), ymin=mean - (1.96*se)),
position=position_dodge(width=0.9), width=0.25)+
# coord_cartesian(ylim = c(1, 3))+
labs(title="Humanização da Marca por Condição Experimental",
y="Humanização Média", x="Condições")
Agora finalmente entramos nos testes de hipóteses. Recapitulando: H1: A atitude em relação a marcas humanizadas é mais alta (mais positiva) quando comparada a marcas “tradicionais” (controle) H2: A intenção de compra de marcas humanizadas é mais alta do que a de marcas tradicionais (controle) H3: Marcas humanizadas são consideradas “mais humanas” do que marcas tradicionais (controle) H4: A influência das marcas humanizadas na atitude em relação à marca é moderada pela idade do respondente.
Para esse teste de hipóteses e para os a seguir, testaremos a mesma hipótese de diferentes formas: teste t, ANOVA e Regressão Linear. Para cada um dos testes, faremos os diagnósticos necessários.
Pressupostos. Como veremos, o teste t é, em suma, um modelo linear generalizado (GLM). Já trabalhamos com essa ideia em aula, mas a lógica das “distâncias” ou diferenças entre médias e a lógica da OLS, ordinary least squares, é a mesma. Dessa forma, os pressupostos são os mesmos. Normalidade dos resíduos e homogeneidade da variância. No teste t, a diferença entre os grupos deve seguir uma distribuição normal. Já homogeneidade da variância só é uma preocupação quando o tamanho (n) dos grupos é muito diferente. Nesses casos, o teste de Lavene, usado para isso, não é muito funcional. A ideia é usar um teste t de Welch que corrige para violações de homogeneidade da variância (Field et al., 2012). Para nossa sorte, esse é o teste t default do R. Vamos começar visualizando os grupos.
ggplot(do, aes(x=condicoes,y=atitude, fill=condicoes)) +
geom_violin(trim=FALSE) +
stat_summary(fun.data=mean_sdl, fun.args = list(mult = 1),
geom="pointrange", color="white") +
coord_cartesian(ylim = c(0,6)) +
labs(title = "Atitude por Condições", x = "Condições Experimentais",
y = "Atitude", fill = "Condições")
Faremos um teste de Shapiro Wilk para normalidade. Procuramos um p > .05.
require(pastecs)
shapiro.test(do$atitude[do$condicoes=="Humanizada"])
##
## Shapiro-Wilk normality test
##
## data: do$atitude[do$condicoes == "Humanizada"]
## W = 0.97149, p-value = 0.0329
shapiro.test(do$atitude[do$condicoes=="Controle"])
##
## Shapiro-Wilk normality test
##
## data: do$atitude[do$condicoes == "Controle"]
## W = 0.84404, p-value = 2.296e-08
by(do$atitude, do$condicoes, stat.desc, basic = FALSE, norm = TRUE)
## do$condicoes: Controle
## median mean SE.mean CI.mean.0.95 var std.dev
## 1.363636e+00 1.631369e+00 6.825467e-02 1.355998e-01 4.239417e-01 6.511081e-01
## coef.var skewness skew.2SE kurtosis kurt.2SE normtest.W
## 3.991177e-01 1.312945e+00 2.598075e+00 1.245823e+00 1.245069e+00 8.440358e-01
## normtest.p
## 2.295567e-08
## ------------------------------------------------------------
## do$condicoes: Humanizada
## median mean SE.mean CI.mean.0.95 var std.dev
## 3.09090909 2.88847235 0.09438175 0.18734629 0.86406769 0.92955241
## coef.var skewness skew.2SE kurtosis kurt.2SE normtest.W
## 0.32181454 -0.23122436 -0.47193406 -0.68528264 -0.70599696 0.97148818
## normtest.p
## 0.03289711
do$trans_atitude <- log(do$atitude) #sqrt(do$atitude) 1/(do$atitude)
qplot(sample = atitude, data = do, color=condicoes) +
labs(title = "QQPlot para Atitude e Condições")
Os dados para atitude são não-normais. Nos temos duas opções: ou nós tentamos transformar os dados ou rodamos análises não paramétricas. Muitos pesquisadores só ignoram isso e rodam o t-test da mesma forma. Faremos tudo aqui.
t.test(atitude ~ condicoes, data = do)
##
## Welch Two Sample t-test
##
## data: atitude by condicoes
## t = -10.793, df = 172.38, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group Controle and group Humanizada is not equal to 0
## 95 percent confidence interval:
## -1.487006 -1.027201
## sample estimates:
## mean in group Controle mean in group Humanizada
## 1.631369 2.888472
require(effsize)
effsize::cohen.d(do$atitude, do$condicoes)
##
## Cohen's d
##
## d estimate: -1.557923 (large)
## 95 percent confidence interval:
## lower upper
## -1.886579 -1.229268
kruskal.test(atitude ~ condicoes, data = do)
##
## Kruskal-Wallis rank sum test
##
## data: atitude by condicoes
## Kruskal-Wallis chi-squared = 71.175, df = 1, p-value < 2.2e-16
require(rstatix)
kruskal_effsize(atitude ~ condicoes, data = do)
As análises seguintes ficam redundantes, pois já encontramos a resposta, a atitude é mais positiva para a marca humanizada. Mas vamos ao exercício.
A ANOVA é um teste mais robusto. Existe muito debate sobre isso e sobre os efeitos da (não)normalidade. Quando os grupos são equivalentes, ANOVA é robusta para violações da homogeneidade da variância. O que é o caso, aliás - identificado por um teste de Levene, testando a diferença das variâncias. Queremos que as variâncias não sejam diferentes, ou seja, que p > 0.05.
require(car)
leveneTest(do$atitude, do$condicoes)
leveneTest(log(do$atitude), do$condicoes)
Todo caso, homogeneidade da variância responde bem a transformações das variáveis. Vamos usar o log da atitude também.
h1.anova <- aov(atitude ~ condicoes, data = do)
summary(h1.anova)
## Df Sum Sq Mean Sq F value Pr(>F)
## condicoes 1 74.2 74.20 114 <2e-16 ***
## Residuals 186 121.1 0.65
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
h1.anova.log <- aov(log(atitude) ~ condicoes, data = do)
summary(h1.anova.log)
## Df Sum Sq Mean Sq F value Pr(>F)
## condicoes 1 15.54 15.536 115.7 <2e-16 ***
## Residuals 186 24.97 0.134
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Em ambos os casos, a H1 foi confirmada.
A lógica da regressão é similar a da ANOVA. Mas é muito útil quando começamos a trabalhar com códigos de contraste, spotlights e outras relações mais complexas entre as variáveis. A primeira coisa que precisamos fazer para rodar uma regressão é codificar as nossas condições experimentais em códigos de contraste centrados em zero. Leremos mais adiante porque isso é importante (zero é mágico!).
do$condicoes.cc[do$condicoes=="Controle"] <- -1
do$condicoes.cc[do$condicoes=="Humanizada"] <- +1
table(do$condicoes,do$condicoes.cc) #funcionou
##
## -1 1
## Controle 91 0
## Humanizada 0 97
Como existem violações dos pressupostos da regressão, deveríamos rodar um teste não paramétrico (Kruskal-Wallis). Já o fizemos. Vamos rodar um modelo com atitude e com log(atitude). Primeiro a regressão com atitude original.
h1.reg <- lm(atitude ~ condicoes.cc, data = do)
plot(h1.reg, which = c(2))
summary(h1.reg)
##
## Call:
## lm(formula = atitude ~ condicoes.cc, data = do)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.88847 -0.54046 -0.03265 0.46345 2.09590
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.25992 0.05888 38.38 <2e-16 ***
## condicoes.cc 0.62855 0.05888 10.68 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.8069 on 186 degrees of freedom
## Multiple R-squared: 0.3799, Adjusted R-squared: 0.3766
## F-statistic: 114 on 1 and 186 DF, p-value: < 2.2e-16
E agora com atitude log.
h1.reg.log <- lm(log(atitude) ~ condicoes.cc, data = do)
plot(h1.reg.log, which = c(2))
summary(h1.reg.log)
##
## Call:
## lm(formula = log(atitude) ~ condicoes.cc, data = do)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.99808 -0.25580 0.05381 0.24161 0.89282
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.71047 0.02674 26.57 <2e-16 ***
## condicoes.cc 0.28761 0.02674 10.76 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.3664 on 186 degrees of freedom
## Multiple R-squared: 0.3835, Adjusted R-squared: 0.3802
## F-statistic: 115.7 on 1 and 186 DF, p-value: < 2.2e-16
Eu vou repetir todos os procedimentos para H1, mas investigando apenas a9_compraria. Aqui entra o bom e velho copia-cola. Mas cuidado ao mudar o nome das variáveis.
ggplot(do, aes(x=condicoes,y=a9_compraria, fill=condicoes)) +
geom_violin(trim=FALSE) +
stat_summary(fun.data=mean_sdl, fun.args = list(mult = 1),
geom="pointrange", color="white") +
coord_cartesian(ylim = c(0,6)) +
labs(title = "Intenção de Compra por Condições", x = "Condições Experimentais",
y = "Atitude", fill = "Condições")
Faremos um teste de Shapiro Wilk para normalidade. Procuramos um p > .05.
shapiro.test(do$a9_compraria[do$condicoes=="Humanizada"])
##
## Shapiro-Wilk normality test
##
## data: do$a9_compraria[do$condicoes == "Humanizada"]
## W = 0.89824, p-value = 1.599e-06
shapiro.test(do$a9_compraria[do$condicoes=="Controle"])
##
## Shapiro-Wilk normality test
##
## data: do$a9_compraria[do$condicoes == "Controle"]
## W = 0.66829, p-value = 4.952e-13
by(do$a9_compraria, do$condicoes, stat.desc, basic = FALSE, norm = TRUE)
## do$condicoes: Controle
## median mean SE.mean CI.mean.0.95 var std.dev
## 1.000000e+00 1.604396e+00 1.023284e-01 2.032931e-01 9.528694e-01 9.761503e-01
## coef.var skewness skew.2SE kurtosis kurt.2SE normtest.W
## 6.084224e-01 1.694328e+00 3.352762e+00 2.279098e+00 2.277719e+00 6.682928e-01
## normtest.p
## 4.952071e-13
## ------------------------------------------------------------
## do$condicoes: Humanizada
## median mean SE.mean CI.mean.0.95 var
## 3.000000e+00 2.896907e+00 1.194961e-01 2.371979e-01 1.385095e+00
## std.dev coef.var skewness skew.2SE kurtosis
## 1.176900e+00 4.062610e-01 -1.439986e-01 -2.939043e-01 -7.639143e-01
## kurt.2SE normtest.W normtest.p
## -7.870054e-01 8.982354e-01 1.599248e-06
do$trans_a9_compraria <- log(do$a9_compraria) #sqrt(do$a9_compraria) 1/(do$a9_compraria)
qplot(sample = a9_compraria, data = do, color=condicoes) +
labs(title = "QQPlot para Intenção de Compra e Condições")
Os dados para a9_compraria (Intenção de Compra) são não-normais. Nos temos duas opções: ou nós tentamos transformar os dados ou rodamos análises não paramétricas. Muitos pesquisadores só ignoram isso e rodam o t-test da mesma forma. Faremos tudo aqui.
t.test(a9_compraria ~ condicoes, data = do)
##
## Welch Two Sample t-test
##
## data: a9_compraria by condicoes
## t = -8.2157, df = 183.29, p-value = 3.713e-14
## alternative hypothesis: true difference in means between group Controle and group Humanizada is not equal to 0
## 95 percent confidence interval:
## -1.6029078 -0.9821154
## sample estimates:
## mean in group Controle mean in group Humanizada
## 1.604396 2.896907
require(effsize)
effsize::cohen.d(do$a9_compraria, do$condicoes)
##
## Cohen's d
##
## d estimate: -1.191899 (large)
## 95 percent confidence interval:
## lower upper
## -1.5043031 -0.8794947
kruskal.test(a9_compraria ~ condicoes, data = do)
##
## Kruskal-Wallis rank sum test
##
## data: a9_compraria by condicoes
## Kruskal-Wallis chi-squared = 52.439, df = 1, p-value = 4.437e-13
require(rstatix)
kruskal_effsize(a9_compraria ~ condicoes, data = do)
As análises seguintes ficam redundantes, pois já encontramos a resposta, a intenção de compra é maior. Mas vamos ao exercício.
leveneTest(do$a9_compraria, do$condicoes)
leveneTest(log(do$a9_compraria), do$condicoes)
Todo caso, homogeneidade da variância responde bem a transformações das variáveis. Vamos usar o log da a9_compraria também.
h2.anova <- aov(a9_compraria ~ condicoes, data = do)
summary(h2.anova)
## Df Sum Sq Mean Sq F value Pr(>F)
## condicoes 1 78.44 78.44 66.7 4.7e-14 ***
## Residuals 186 218.73 1.18
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
h2.anova.log <- aov(log(a9_compraria) ~ condicoes, data = do)
summary(h2.anova.log)
## Df Sum Sq Mean Sq F value Pr(>F)
## condicoes 1 17.96 17.963 72.96 4.67e-15 ***
## Residuals 186 45.79 0.246
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Em ambos os casos, a h2 foi confirmada.
Como existem violações dos pressupostos da regressão, deveríamos rodar um teste não paramétrico (Kruskal-Wallis). Já o fizemos. Vamos rodar um modelo com a9_compraria e com log(a9_compraria). Primeiro a regressão com a9_compraria original.
h2.reg <- lm(a9_compraria ~ condicoes.cc, data = do)
plot(h2.reg, which = c(2))
summary(h2.reg)
##
## Call:
## lm(formula = a9_compraria ~ condicoes.cc, data = do)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.8969 -0.6044 0.1031 0.3956 3.3956
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.25065 0.07913 28.443 < 2e-16 ***
## condicoes.cc 0.64626 0.07913 8.167 4.7e-14 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.084 on 186 degrees of freedom
## Multiple R-squared: 0.264, Adjusted R-squared: 0.26
## F-statistic: 66.7 on 1 and 186 DF, p-value: 4.697e-14
E agora com a9_compraria log.
h2.reg.log <- lm(log(a9_compraria) ~ condicoes.cc, data = do)
plot(h2.reg.log, which = c(2))
summary(h2.reg.log)
##
## Call:
## lm(formula = log(a9_compraria) ~ condicoes.cc, data = do)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.9561 -0.3376 0.1425 0.3555 1.2718
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.64688 0.03621 17.867 < 2e-16 ***
## condicoes.cc 0.30927 0.03621 8.542 4.67e-15 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.4962 on 186 degrees of freedom
## Multiple R-squared: 0.2818, Adjusted R-squared: 0.2779
## F-statistic: 72.96 on 1 and 186 DF, p-value: 4.672e-15
Testaremos a Hipótese H3
Eu vou repetir todos os procedimentos para H1, mas investigando apenas a humanização da marca. Aqui entra o bom e velho copia-cola. Mas cuidado ao mudar o nome das variáveis.
ggplot(do, aes(x=condicoes,y=human, fill=condicoes)) +
geom_violin(trim=FALSE) +
stat_summary(fun.data=mean_sdl, fun.args = list(mult = 1),
geom="pointrange", color="white") +
coord_cartesian(ylim = c(0,6)) +
labs(title = "Humanização por Condições", x = "Condições Experimentais",
y = "Atitude", fill = "Condições")
Faremos um teste de Shapiro Wilk para normalidade. Procuramos um p > .05.
shapiro.test(do$human[do$condicoes=="Humanizada"])
##
## Shapiro-Wilk normality test
##
## data: do$human[do$condicoes == "Humanizada"]
## W = 0.9528, p-value = 0.001557
shapiro.test(do$human[do$condicoes=="Controle"])
##
## Shapiro-Wilk normality test
##
## data: do$human[do$condicoes == "Controle"]
## W = 0.81614, p-value = 2.779e-09
by(do$human, do$condicoes, stat.desc, basic = FALSE, norm = TRUE)
## do$condicoes: Controle
## median mean SE.mean CI.mean.0.95 var std.dev
## 1.444444e+00 1.642247e+00 7.459730e-02 1.482006e-01 5.063929e-01 7.116129e-01
## coef.var skewness skew.2SE kurtosis kurt.2SE normtest.W
## 4.333167e-01 1.610958e+00 3.187789e+00 2.554508e+00 2.552962e+00 8.161443e-01
## normtest.p
## 2.778908e-09
## ------------------------------------------------------------
## do$condicoes: Humanizada
## median mean SE.mean CI.mean.0.95 var std.dev
## 3.888888889 3.790378007 0.082483838 0.163729125 0.659947605 0.812371593
## coef.var skewness skew.2SE kurtosis kurt.2SE normtest.W
## 0.214324690 -0.779170091 -1.590303480 0.616086759 0.634709463 0.952798929
## normtest.p
## 0.001557108
do$trans_human <- log(do$human) #sqrt(do$human) 1/(do$human)
qplot(sample = human, data = do, color=condicoes) +
labs(title = "QQPlot para Intenção de Compra e Condições")
Os dados para human (Intenção de Compra) são não-normais. Nos temos duas opções: ou nós tentamos transformar os dados ou rodamos análises não paramétricas. Muitos pesquisadores só ignoram isso e rodam o t-test da mesma forma. Faremos tudo aqui.
t.test(human ~ condicoes, data = do)
##
## Welch Two Sample t-test
##
## data: human by condicoes
## t = -19.315, df = 185.15, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group Controle and group Humanizada is not equal to 0
## 95 percent confidence interval:
## -2.367539 -1.928724
## sample estimates:
## mean in group Controle mean in group Humanizada
## 1.642247 3.790378
effsize::cohen.d(do$human, do$condicoes)
##
## Cohen's d
##
## d estimate: -2.807003 (large)
## 95 percent confidence interval:
## lower upper
## -3.212526 -2.401480
kruskal.test(human ~ condicoes, data = do)
##
## Kruskal-Wallis rank sum test
##
## data: human by condicoes
## Kruskal-Wallis chi-squared = 116.73, df = 1, p-value < 2.2e-16
kruskal_effsize(human ~ condicoes, data = do)
As análises seguintes ficam redundantes, pois já encontramos a resposta, a humanização é maior para marcas humanizadas. Mas vamos ao exercício.
leveneTest(do$human, do$condicoes)
O pressuposto da homogeneidade da variância não foi violado. Seguimos com a ANOVA.
h3.anova <- aov(human ~ condicoes, data = do)
summary(h3.anova)
## Df Sum Sq Mean Sq F value Pr(>F)
## condicoes 1 216.7 216.66 369.9 <2e-16 ***
## Residuals 186 108.9 0.59
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Em ambos os casos, a h3 foi confirmada.
h3.reg <- lm(human ~ condicoes.cc, data = do)
plot(h3.reg, which = c(2))
summary(h3.reg)
##
## Call:
## lm(formula = human ~ condicoes.cc, data = do)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.79038 -0.56816 -0.08669 0.44110 2.46886
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.71631 0.05584 48.64 <2e-16 ***
## condicoes.cc 1.07407 0.05584 19.23 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.7653 on 186 degrees of freedom
## Multiple R-squared: 0.6654, Adjusted R-squared: 0.6636
## F-statistic: 369.9 on 1 and 186 DF, p-value: < 2.2e-16
Como a H4 é uma hipótese de interação, não podemos fazer um teste T, mas podemos fazer uma ANOVA e uma regressão. O primeiro passo é centrar a idade na média, por razões que veremos na disciplina a seguir. Deveríamos fazer isso, mas como nossas condições estão equilibradas, o código de contraste usado naturalmente “centrou” na média.
do$idade.mc <- do$idade-mean(do$idade, na.rm = T)
mean(do$condicoes.cc)
## [1] 0.03191489
mean(do$idade.mc)
## [1] 1.499129e-16
Em seguida, podemos dar uma olhada na interação. É sempre mais fácil fazer o gráfico da variável contínua (de razão) no eixo dos X e a discreta (condição) como diferentes linhas. Isso é fácil no R.
ggplot(do) +
aes(x = idade, y = atitude, color = condicoes) +
geom_smooth(method = "lm")+
labs (title = "Relação entre Idade, Condições e Atitude", x = "Idade (em anos)",
y = "Atitude em Relação à Marca", color = "Condições")
h4.anova <- aov (atitude ~ condicoes*idade, data = do)
summary(h4.anova)
## Df Sum Sq Mean Sq F value Pr(>F)
## condicoes 1 74.20 74.20 115.486 <2e-16 ***
## idade 1 2.24 2.24 3.490 0.0633 .
## condicoes:idade 1 0.64 0.64 1.004 0.3177
## Residuals 184 118.22 0.64
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
h4.reg <- lm(atitude ~ condicoes*idade, data = do)
plot(h4.reg, which = c(2))
summary(h4.reg)
##
## Call:
## lm(formula = atitude ~ condicoes * idade, data = do)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.94428 -0.54037 -0.06266 0.46481 2.09212
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.743500 0.275680 6.324 1.88e-09 ***
## condicoesHumanizada 1.593056 0.359439 4.432 1.60e-05 ***
## idade -0.003870 0.009061 -0.427 0.670
## condicoesHumanizada:idade -0.011821 0.011799 -1.002 0.318
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.8016 on 184 degrees of freedom
## Multiple R-squared: 0.3947, Adjusted R-squared: 0.3848
## F-statistic: 39.99 on 3 and 184 DF, p-value: < 2.2e-16