# Replace "path/to/your/directory" with the full path to your working folder
setwd("path/to/your/directory")Lab 4: Contingency Tables and Chi-Square Tests
An NCRM Case Study in Pedagogy
1. Introduction
Moving on from Lab 3
In previous weeks, we built up our understanding of statistical analysis. In Lab 1, we focused on univariate (one-variable) analysis, using descriptive statistics such as means, medians, standard deviations, and frequency distributions. In Lab 2, we covered the Central Limit Theorem (CLT), explaining how sampling distributions work and why they are central to inference.
Last week, we introduced bivariate (two-variable) statistics, where we examined relationships between variables. Bivariate statistics allows us to assess whether and how two variables are associated. In these analyses, we often distinguish between independent variables (also called explanatory variables or predictors) and dependent variables (also called outcome or response variables). The independent variable is the one we believe influences or explains changes in the dependent variable. For example, if we are studying the effect of education level on political participation, education would be the independent variable, while political participation would be the dependent variable.
A key component of bivariate analysis is hypothesis testing, which allows us to determine whether observed patterns in the data are likely due to chance or represent meaningful relationships. Depending on the levels of measurement of our independent and dependent variables, we need to apply different statistical tests to test our hypotheses appropriately. Choosing the correct test ensures valid statistical inferences
In Lab 3, we introduced the first of these types of tests: t-tests to compare differences in means. This test allows us to formally test a hypothesis about whether the difference in means between the two groups is statistically significant. T-tests are used when the independent variable is binary (a categorical variable with only two outcomes, e.g., gender, voted or not, civil war or not) and the dependent variable is numeric.
Now, in Lab 4, we introduce a new statistical approach—chi-square tests, which allow us to analyze relationships between two categorical variables.Like t-tests, chi-square tests are used to evaluate hypotheses, helping us determine whether the observed relationship between categorical variables is statistically significant.
A quick recap of hypothesis testing
Hypothesis testing helps us determine whether patterns in data are meaningful or due to chance. It involves two competing hypotheses:
Null Hypothesis (H₀): Assumes no effect, difference, or association (e.g., no difference in test scores between two teaching methods).
Alternative Hypothesis (H₁ or Ha): Suggests an effect, difference, or association exists (e.g., one teaching method leads to higher scores).
Steps in Hypothesis Testing:
Formulate Hypotheses: Define H₀ and H₁ based on the research question.
Set Significance Level (α): Usually 0.05, the threshold for rejecting H₀.
Choose a Test Statistic: Depends on data type (e.g., t-test for means, chi-square for categorical relationships).
Calculate Test Statistic & p-value: p-value measures the probability of observing the result if H₀ is true.
Make a Decision: If p < α, reject H₀ (suggesting a significant effect). Otherwise, fail to reject H₀.
In Lab 4, we apply these steps using chi-square tests to analyze relationships between categorical variables.
2. Understanding Crosstabs and Chi-Square Tests
What Are Crosstabs?
Crosstabulations (or contingency tables) are a way to summarize relationships between categorical variables by showing the frequency of observations across combinations of two variables. A crosstab displays counts for each combination of categories, allowing us to identify patterns or associations.
For example, consider a study examining trust in politicians by political party affiliation:
| Party ID | Trust | Do Not Trust | Total |
|---|---|---|---|
| Party A | 45 | 105 | 150 |
| Party B | 65 | 55 | 120 |
| Party C | 30 | 70 | 100 |
| Total | 140 | 230 | 370 |
- The rows represent categories of the independent variable.
- The columns represent categories of the dependent variable.
- The values inside represent the number of observations in each combination.
- The totals at the bottom and right allow us to see the overall distribution of responses.
Why Do We Standardize the Table Using Percentages?
While raw counts provide useful information, they make comparisons difficult because the total number of respondents in each category may differ. For instance, Party C has fewer respondents overall, making it hard to compare its numbers to Parties A and B.
To standardize the table, we convert the frequencies into percentages within each row. This allows us to make fair comparisons across groups. ALWAYS show percentages (%) within the independent variable (here, Party ID explains trust, so percentages should be by row).
| Party ID | Trust (%) | Do Not Trust (%) |
|---|---|---|
| Party A | 30.0% | 70.0% |
| Party B | 54.2% | 45.8% |
| Party C | 30.0% | 70.0% |
Interpreting the Standardized Table
Now that we have percentages, we can compare trends across groups: - Party B supporters are the most trusting of politicians (54.2%). - Party A and Party C supporters show similar levels of trust (30.0%).
This percentage-based analysis provides clearer insights than the raw frequency table.
Crosstabs provide an initial summary representation of potential relationships, but we need a statistical test to determine whether these relationships are meaningful or due to chance—this is where the chi-square test comes in.
What Is a Chi-Square Test?
A chi-square test is a statistical test used to determine whether there is an association between two categorical variables. Unlike a t-test, which compares means, a chi-square test examines whether the frequency distributions of two variables are independent of each other.
The test works by comparing what we actually observe in a cross-tabulation (the observed values) with what we would expect to see if the null hypothesis were true (the expected values). If the two variables were unrelated, the observed and expected values would be similar.
In simple terms, the larger the difference between observed and expected values, the stronger the evidence that the two variables are associated rather than randomly related. For more details on how this is calculated, see the appendix.
When Do We Use a Chi-Square Test?
Chi-square tests are used when we have two categorical variables and we want to test whether they are independent or associated.
For example, we might ask: - Is there an association between political party affiliation and trust in politicians? - Does gender influence attitudes toward democracy? - Are educational background and voting behavior related?
Types of Chi-Square Tests
There are two types of chi-square tests: 1. Chi-Square Goodness-of-Fit Test: Used when we have one categorical variable and we want to see if its distribution fits an expected pattern. 2. Chi-Square Test of Independence: Used when we have two categorical variables and we want to see if they are related.
In this lab, we will focus on the Chi-Square Test of Independence.
Assumptions of the Chi-Square Test
- Independence of observations: Each participant or data point should belong to only one category.
- Minimum expected frequency rule: Chi-squared calculations are sensitive to low cell counts; if you have lots of cell counts that are less than 5 within a crosstab, you need to consider recoding the variable to address this. One or two low cell counts in a large table probably don’t matter, but lots will have a real effect on the statistical analysis.
Interpreting the Chi-Square Test
R calculates the chi-square statistic for us. For example, suppose we analyze the relationship between Party ID and Trust and get the following result:
- X2 = 12.34
- df = 2
- p-value = 0.0021
A larger chi-square value generally indicates a stronger association, but the p-value is the key to interpretation. Here, the p-value (0.0021) is lower than the critical threshold of 0.05, meaning the likelihood that this relationship occurred by chance is less than 1%.
Since the test is statistically significant, we reject the null hypothesis and conclude that Party ID and Trust are not independent; there is evidence of an association between them.
3. Crosstabs and Chi-Square Tests in R
In this lab session, we’ll focus on factor variables and introduce the Chi-square test using the Arab Barometer dataset. This dataset, compiled by Princeton University, covers a wide range of Arab countries and is based on survey research. It consists of random samples of citizens from each country, asking them about politics and daily life. Because it includes data from multiple nations, it is classified as cross-national data. This means it can be used to analyze differences both between countries and within countries.
What to Expect in This Lab
In the first half of the session, we’ll explore crosstabs and Chi-square tests, discussing their practical applications and learning how to use the relevant R code. The Exercises section will then allow you to apply these skills by working through guided questions.
Commands Covered Today
%>%- this is a pipe and feeds data from one command to another (makes our code much shorter and easier to understand)contTables- (this is from the jamovi package and allows us to understand relationships between categorical variables)recode- (A command from tidyverse that allows us to recode our data)mutate- (a command from tidyverse that allows us to recode our data)drop_na- (a command that tells R not to include data that we think is unhelpful (e.g. people that say ‘don’t know’))
Reminder of key accessible commands
Opening a code chunk:
- Keyboard shortcut:
Ctrl + Alt + I(Windows/Linux) orCmd + Option + I(Mac)
- Keyboard shortcut:
Running a code chunk:
Ctrl + Shift + Enter(Windows/Linux) orCmd + Shift + Enter(Mac) while inside the chunkClick the green play button at the top right of the chunk
Executing a single line of code:
Ctrl + Enter(Windows/Linux) orCmd + Enter(Mac) with the cursor on the line
Rendering a Quarto document:
Ctrl + Shift + K(Windows/Linux) orCmd + Shift + K(Mac)Click the “Render” button in the toolbar
Setting up R for Analysis
Remember, like every week, we will take the same steps to get ready to use RStudio:
- load R Studio
- load a quarto script and save it
- set our working directory
- setting up an output file to sink the results (not necessary but recommended)
- load our packages
- load our data
- Set as factor (we have lots of categorical data today!)
- Off we go!
First, we need to open a quarto script and open a code chunk to place our working directory. Remember we need to run this before we proceed with the lab.
Next, I would again recommend setting up an output_filelab4 to sink the results so that we can check analysis and any error messages as we go.
Remember, you need to include in the brackets at the beginning of the chunk:
r setup, include=TRUE, eval=FALSE
This code will make sure that your output file updates as you run chunks but that you can also render the document as a whole.
# Open a file connection
output_file <- file("output_filelab4.txt", open = "wt")
# Redirect both standard output and error messages to the same file
sink(output_file, split = TRUE) # Capture normal output
sink(output_file, type = "message") # Capture errors and warningsWe also need to load the necessary packages and import our data.
library(tidyverse)
library(jmv)
library(haven)
library(BrailleR)
AB <- read_spss("data/ArabBarometer.sav")This week, we’re working with a .sav file again, just as we did in Lab 1. Remember: .sav files contain labels for factor variables, but when loaded into R using the read_sav function, all data is initially read as numeric. To properly classify categorical variables, we use the as_factor function, creating a new data object where numeric and factor variables are correctly identified.
Dropping Unused Levels in Categorical Variables
Now, let’s see how we can instruct R to drop unused levels in our categorical variables.
The syntax for as_factor remains the same as in Lab 1. The only difference here is that we are piping the Arab Barometer (AB) dataset through the droplevels function to remove unused factor levels.
The code should look like this:
ABfac <- as_factor(AB) %>% droplevels(.)The full stop indicates what you are piping in (a placeholder argument for the factor version of ABfac). We are just passing that data into drop levels.
Essentially, we are telling R:
“Take the dataset
AB, convert it into a new objectABfacusingas_factor, and then drop any unused levels inABfac.”
To give a sense of how this would look without a pipe, consider the following two lines of code:
In this first line of code we create our as_factor dataset – exactly the same as in lab 1.
ABfac <- as_factor(AB)
However, we also have this second line of code where we droplevels from our new dataset.
droplevels(ABfac)
By structuring the code this way, we streamline the process—asking R to perform an additional step within a single line of code, rather than executing it in separate commands, saving us time and make things slightly easier! This will become more intuitive as we see how it works later in the session.
Once you have run the packages and loaded the data remember to run the chunk. You can then also check your output text file to check they have loaded correctly.
Research Question 1: Do Arabic Nations Treat Women The Same?
Let’s start of with a research question. We are interested in learning something about how Women are perceived and treated in Arabic nations. There are numerous theories that we could examine that might tell us something about why treatment of Women within a society might differ, such as the cultural norms that exist within a society, the nature of the economy (e.g. regimes that have lots of oil may have less reason to liberalise and allow Women to become economically active) but to begin with we are just going to focus on whether differences actually exist.
Let’s start off by setting some expectations for what we might find; our null and alternative hypotheses.
The null hypothesis for each of these is the prediction that there is no association between our variables. We can specify alternative hypothesis to indicate what we think the relationship might be, but as a reminder we always test the null. We will either:
- Reject the null (when we find evidence to support our alternative hypothesis) or
- Fail to reject the null (where we find no evidence to support our alternative hypothesis)
Setting our hypotheses out
H0 There is no relationship between Country and Views of Women
Ha There is a relationship between Country and Views of Women
Getting to Know our Data: Cleaning and Management
Our Variables
For this Research Question we are going to look at these variables:
- COUNTRY (Which country did the survey take place in?)
- Q601_18 (Agree of Disagree: Men should have the final say on matters)
How did i find out about these variables? I used a codebook! We can have a look at the codebook for this data by looking at the file that is on Blackboard with the main data file, or we can go to the ArabBarometer Study website and download it ourselves.
Checking our Dependent Variable (independent variable): Men Final Opinion?
Now that we have got our data and packages loaded, we need to turn our attention to the variables we are going to use.
Lets start off by looking at our dependent variable which tells us whether or not individuals agree that Men should have the final say on all matters.
We can have a look at this using the attributes command:
attributes(ABfac$Q601_18)$levels
[1] "Strongly agree" "Agree" "Disagree"
[4] "Strongly disagree" "Don’t know" "Refused to answer"
$class
[1] "factor"
We can see here that there is a lot of useful information such as useful levels like strongly agree, Agree, Disagree and Strongly Disagree but there are also other levels that are not helpful like Refused to answer and Don’t know – these bits of data do not help us understand what made people vote leave or remain so we want to get rid of them. Remember what we talked about, in a Chi-Square test any pieces of data will be used to estimate inference. If there are any bits of data in there that we do not expect a relationship with or are separate to our key issue they may affect our significance tests.
In order to do this we are going to use piping, mutate and recode commands. We will essentially modify our dataset (ABfac) by adding a new variable called MenFinal, which is a recoded version of the original variable Q601_18.
To do this, we use two new functions:
mutate(): This function is used to create a new variable or modify an existing one. Here, we are creatingMenFinalinsidemutate().recode(): This function is used to change specific values of a variable. In this case, we are telling R to replace certain responses inQ601_18withNA(missing values).
One thing to consider when recoding is that we need to be very careful to not make errors in an original variable. If we do this and we make a mistake we may have to re-download our data. Because of this, we always recode into a new variable. in essence, we make a duplicate of the original variable and recode the duplicate. This means that if we make a mistake we will have our original variable preserved to redo our coding.
Let’s see how this works:
ABfac <- ABfac %>%
mutate (MenFinal = recode(Q601_18,
"Refused to answer" = NA_character_,
"The respondent does not wish to continue" = NA_character_,
"Don't know" = NA_character_))
levels(ABfac$MenFinal)[1] "Strongly agree" "Agree" "Disagree"
[4] "Strongly disagree" "Don’t know"
In the first line of code, ABfac <- ABfac %>%, we are writing over our original dataset and adding a new variable. The we use the mutate() function to add a new variable (MenFinal) to ABfac. The recode() function modifies the values of Q601_18 by changing:
"Refused to answer"toNA"The respondent does not wish to continue"toNA, and"Don’t know"toNA
Finally, we check our work with the levels command. In this example, we can see that it has done most of what we want, but “Don’t know” hasn’t disappeared. The problem is that the apostrophe in “Don’t” is not the same as the one we used in our code.
There are two types of apostrophes:
A curly apostrophe (’), which is often used in word processors and appears more curved or slanted.
A straight apostrophe (’), which is a simpler, vertical mark and is the default in R. This straight apostrophe is the one we type using the key under the @ symbol on a standard keyboard.
R treats these as different characters, so if we used a straight apostrophe in our code but the dataset contains a curly apostrophe, R won’t recognize them as the same. To fix this, we need to ensure we are matching exactly what is in the dataset.
There are two ways to ensure "Don’t know" matches correctly:
Copy and paste the value directly from
levels(ABfac$Q601_18), so the curly apostrophe is preserved.Manually type it by using the correct key combination for a curly apostrophe:
Windows: Hold Alt, type
0146on the numeric keypad, then release Alt.Mac: Press Option + Shift + ].
Now, let’s update our command to ensure "Don’t know" is recoded correctly:
ABfac <- ABfac %>%
mutate (MenFinal = recode(Q601_18,
"Refused to answer" = NA_character_,
"The respondent does not wish to continue" = NA_character_,
"Don’t know" = NA_character_))
levels(ABfac$MenFinal)[1] "Strongly agree" "Agree" "Disagree"
[4] "Strongly disagree"
This has worked! There is one last thing that we could do to make our data easier to interpret. Rather than having four categories, we could reduce it to a binary variable where people either ‘agree’ or ‘disagree’. We can do this really easily be combining the values "Strongly agree" = "Agree" and "Strongly disagree" = "Disagree". We add this at the end of our existing command:
ABfac <- ABfac %>%
mutate (MenFinal = recode(Q601_18,
"Refused to answer" = NA_character_,
"The respondent does not wish to continue" = NA_character_,
"Don’t know" = NA_character_,
"Strongly agree" = "Agree",
"Agree" = "Agree",
"Disagree" = "Disagree",
"Strongly disagree" = "Disagree"))We can now re-check our variable one last time to make sure it has worked:
levels(ABfac$MenFinal)[1] "Agree" "Disagree"
It has worked! This approach helps simplify analysis and makes patterns easier to spot.
A Note on Recoding Factor Variables and Why it Helps Interpretation
Large datasets can be difficult to interpret, especially when variables have many categories. This is even more challenging for screen reader users, who must navigate long lists of values. As a general rule, recoding factor variables into fewer levels improves readability and analysis. For example, a Likert scale with five categories (Strongly Agree, Agree, Neutral, Disagree, Strongly Disagree) could be collapsed into three (Agree, Neutral, Disagree) or even two (Agree, Disagree). Similarly, a 0–10 scale could be grouped into Low (0–3), Moderate (4–6), and High (7–10) to simplify interpretation.
When deciding how to recode, consider interpretability (does the grouping make sense?), meaning preservation (are important distinctions lost?), and statistical justification (are some categories too small?). If a category has very few observations, merging it with a similar one can make results more reliable. Keeping variables streamlined also improves accessibility, making data easier to navigate for all users.
Checking our Independent Variable: Country
Our Independent variable for this Research Question is going to be COUNTRY. As before, we can use the attributes command to inspect it.
attributes(ABfac$COUNTRY)$levels
[1] "Algeria" "Egypt" "Iraq" "Jordan" "Kuwait"
[6] "Lebanon" "Libya" "Mauritania" "Morocco" "Palestine"
[11] "Sudan" "Tunisia"
$class
[1] "factor"
Our dataset includes Arabic-speaking nations from both North Africa and the Middle East. However, since there are too many countries to analyze comprehensively, we will adjust our focus to North African Arabic nations. This means we will limit our case selection to Algeria, Egypt, Libya, Mauritania, Morocco, Sudan, and Tunisia.
There are several reasons for narrowing our focus. When conducting crosstabulations and chi-square analysis, especially when using a screen reader, having too many categories can make interpretation more difficult. Large contingency tables with many categories can be harder to navigate, making it more challenging to identify patterns or significant differences. Additionally, reducing the number of categories helps in two ways:
Easier Interpretation – Crosstabs become clearer, making it easier to see relationships between variables.
Higher Statistical Power – When categories are too fragmented, we may have small counts in some cells, making statistical significance harder to achieve. Fewer, well-defined categories improve the likelihood of detecting meaningful differences.
To address this issue, we have two possible strategies:
Recoding Variables – This involves grouping similar response categories together. For example, if a survey question includes “Strongly Agree” and “Agree”, we might combine them into a single category called “Agree”. Similarly, numeric scales (e.g., responses from 1 to 4) can be recoded into broader groupings (e.g., 1-2 and 3-4).
Narrowing the Case Selection – Instead of analyzing all Arabic-speaking countries, we focus on a smaller, more coherent subset. In this case, we refine our analysis to North African nations, ensuring that our comparisons remain meaningful and manageable.
To create the subset of North African countries, we use the filter command:
AB_nafrica <- ABfac %>%
filter(COUNTRY %in% c("Algeria", "Egypt", "Libya", "Mauritania",
"Morocco", "Sudan", "Tunisia")) %>%
mutate(COUNTRY = droplevels(COUNTRY))This command selects only the rows where the COUNTRY variable is Algeria, Egypt, Libya, Mauritania, Morocco, Sudan, or Tunisia, creating a new dataset called AB_nafrica.
However, in some cases, even after filtering, R still retains unused factor levels from the original dataset. This means that when we create a frequency or contingency table, the table may still include all original countries as empty categories, making it harder to interpret.
To avoid this, we added mutate(COUNTRY = droplevels(COUNTRY)). This ensures that COUNTRY is updated to only contain the levels present in AB_nafrica, removing any unused country categories. This step is important because it guarantees that only our North African countries appear in our tables and graphs, making the results clearer and more relevant.
Describing our Data
The next step in our analysis is to explore our data. We can use the descriptives command to generate frequency tables and examine the distribution of our variables. Since we are working with factor variables, we need to specifically request frequency tables, as measures like the mean or standard deviation are not meaningful for categorical data. We do this by setting freq = TRUE in our command:
descriptives(AB_nafrica, c(MenFinal, COUNTRY),
freq = TRUE)
DESCRIPTIVES
Descriptives
─────────────────────────────────────────────
MenFinal COUNTRY
─────────────────────────────────────────────
N 7697 15868
Missing 8171 0
Mean
Median
Standard deviation
Minimum
Maximum
─────────────────────────────────────────────
FREQUENCIES
Frequencies of MenFinal
────────────────────────────────────────────────────
MenFinal Counts % of Total Cumulative %
────────────────────────────────────────────────────
Agree 4486 58.28245 58.28245
Disagree 3211 41.71755 100.00000
────────────────────────────────────────────────────
Frequencies of COUNTRY
──────────────────────────────────────────────────────
COUNTRY Counts % of Total Cumulative %
──────────────────────────────────────────────────────
Algeria 2162 13.62491 13.62491
Egypt 2044 12.88127 26.50618
Libya 2505 15.78649 42.29266
Mauritania 2000 12.60398 54.89665
Morocco 2404 15.14999 70.04663
Sudan 2353 14.82859 84.87522
Tunisia 2400 15.12478 100.00000
──────────────────────────────────────────────────────
By default, the first descriptives table also prints summary statistics such as the mean, median, standard deviation, minimum, and maximum. However, since both of our variables are categorical (factors), these values are not calculated and appear empty. We can simply ignore them, or, if we prefer a cleaner output, we can disable them by explicitly setting each to FALSE in the descriptives command.
We begin our analysis by examining the frequencies of MenFinal, which represents respondents’ agreement or disagreement with the statement that men should have final say on all matters. The results show that 4486 respondents, or 58.3%, selected “Agree,” while 3211 respondents, or 41.7%, selected “Disagree.” This means that opinions are fairly evenly split, with a slight majority in agreement.
Next, we look at the distribution of responses across countries. The data includes respondents from 7 countries, with some variation in representation. The highest number of responses comes from Libya, Morocco, and Tunisia each contributing around 15% of the total sample, whilst the country with the fewest respondents is Mauritania, making up about 12.6% of the dataset. Overall, the difference between countries is relatively small. As you navigate the frequency table, you’ll see that cumulative percentages increasing as each country’s responses are added up. This tells us how much of the total dataset has been accounted for at each step.
The contTables command
As we discussed previously, contingency tables (sometimes called crosstabs) are a type of frequency table that compares two variables. They work by putting one variable into row and another into columns. They are really useful for seeing whether there are patterns between two categorical variables.
The jamovi package uses a command contTables to allow us to view contingency tables easily. The structure is nice and easy to use.
The basic command is: contTables(data, rows=variable1, cols=variable2). Note that contTables is spelled with an uppercase T in Tables.
In this case we want to use our MenFinal variable and COUNTRY variable.
contTables(AB_nafrica, cols=MenFinal, rows = COUNTRY)
CONTINGENCY TABLES
Contingency Tables
────────────────────────────────────────────
COUNTRY Agree Disagree Total
────────────────────────────────────────────
Algeria 690 341 1031
Egypt 605 370 975
Libya 739 468 1207
Mauritania 644 361 1005
Morocco 606 559 1165
Sudan 688 441 1129
Tunisia 514 671 1185
Total 4486 3211 7697
────────────────────────────────────────────
χ² Tests
──────────────────────────────────────
Value df p
──────────────────────────────────────
χ² 185.9512 6 < .0000001
N 7697
──────────────────────────────────────
How useful is this? Well, it shows the breakdown of Agree/Disagree by country, but notice how all of the different row totals are different? This makes comparison really difficult! We need to use percentages to standardise the data so that we can understand whether different generations indeed voted differently. We can do this by using the pcCol=TRUE option; this asks jamovi to report percentages in columns. We also add obs = FALSEto get rid of observation numbers and make the table easier to read.
Important!! Note that we ALWAYS choose percentage in the direction of the independent variable. If our independent variable is in Row we choose pcRow = TRUE and if our independent variable is in Column we choose pcCol = TRUE
If we get this wrong, our interpretation WILL be wrong! If we had columns percentages here, we would mistakenly interpret opinions on women’s issues as influencing the country someone lives in - when in reality, we know this isn’t possible.
contTables(AB_nafrica, cols=MenFinal, rows = COUNTRY, pcRow = TRUE, obs = FALSE)
CONTINGENCY TABLES
Contingency Tables
─────────────────────────────────────────────────────────────────────
COUNTRY Agree Disagree Total
─────────────────────────────────────────────────────────────────────
Algeria % within row 66.92532 33.07468 100.00000
Egypt % within row 62.05128 37.94872 100.00000
Libya % within row 61.22618 38.77382 100.00000
Mauritania % within row 64.07960 35.92040 100.00000
Morocco % within row 52.01717 47.98283 100.00000
Sudan % within row 60.93888 39.06112 100.00000
Tunisia % within row 43.37553 56.62447 100.00000
Total % within row 58.28245 41.71755 100.00000
─────────────────────────────────────────────────────────────────────
χ² Tests
──────────────────────────────────────
Value df p
──────────────────────────────────────
χ² 185.9512 6 < .0000001
N 7697
──────────────────────────────────────
This is better! we can now look at the relationships. Is there a pattern? Yes! it does appear to be the case that different countries are more likely to view Women more positively or negatively. But, how do we know if this is a statistically significant difference or if it has occurred by chance? This is where the Chi-Square test comes in.
Chi-Square Test: Testing our Hypothesis
The Chi-Square test allows us to evaluate our hypothesis. Let’s restate it:
H0 There is no relationship between country and attitudes towards Women.
Ha There is an association between country and attitudes towards Women.
Remember, when testing hypotheses we focus on the null and determine whether to: (1) Reject the null or (2) fail to reject the null.
In order to evaluate this, we need to compare our p-value with our critical value, which is 0.05.
if p>0.05 we fail to reject the null
if p<0.05 we reject the null
In essence, the p-value tells us how certain we are that the relationship did not occur by chance.
In this case, P < .0000001 which is much smaller than 0.05. Thus, we reject the null hypothesis. It appears likely that there is an association between country and attitudes towards Women. It is incredibly unlikely that the relationship we see would exist if the two variables are independent of each other.
Graphing the Relationship
We can also produce nice graphs to illustrate these relationships and make them easier to interpret. You will be familiar with the type of graph as we looked at them in Lab 1. We will create a ‘stacked bar chart’ using ggplot and geom_bar.
Lets give this a go! The code we need to use is the following:
bar = AB_nafrica %>%
drop_na(COUNTRY, MenFinal) %>%
ggplot(aes(x=COUNTRY))+
geom_bar(position = "fill", aes(fill=MenFinal))
VI(bar)This is an untitled chart with no subtitle or caption.
It has x-axis '' with labels Algeria, Egypt, Libya, Mauritania, Morocco, Sudan and Tunisia.
It has y-axis '' with labels 0.00, 0.25, 0.50, 0.75 and 1.00.
The chart is a bar chart with 7 vertical bars.
What does this mean? Let’s take it step by step:
We need to give the graph a name to save it. Here, I called it
barand then we use the=sign to assign the plot to this name. This allows us to refer tobarlater when we want it described with theVIfunction (see below).We specify our dataset, which in this case is
AB_nafrica. We then use the pipe operator%>%to move to the next line.We use the
drop_na(COUNTRY, MenFinal)function to remove any rows that contain missing values (NA) in theCOUNTRYorMenFinalcolumns. This is important because missing values can cause issues when generating the graph. By explicitly dropping these NAs, we ensure that only complete data (i.e. only theAgreeandDisagreecategories) are used in the visualization. Again, we use the pipe operator%>%to move to the next line.Next, we create the plot using
ggplot(). Since we have already piped in our dataset, we don’t need to specify it again insideggplot(). Instead, we go straight to defining the aesthetics usingaes(x=COUNTRY). This tells R that the x-axis of our plot should represent theCOUNTRYvariable, which is our independent variable.We then add
geom_bar(position = "fill", aes(fill=MenFinal))to create a bar chart. Thegeom_bar()function generates bars for each category in theCOUNTRYvariable. Theposition = "fill"argument makes the bars proportional, meaning instead of showing raw counts, they show relative frequencies (percentages) of each category within a country. Thefill = MenFinalaesthetic ensures that the bars are divided into segments based on the dependent variable, in this caseMenFinal. This allows us to compare its distribution across different countries - just like we did in the contingency tables!Finally, we use
VI(bar), which generates a text-based summary of the graph. This function describes the key features of the visualization, including the variables used, the overall distribution of data, and any notable patterns. While the description does not provide the exact proportions of each stack (i.e., the distribution of Agree/Disagree categories within each country), we can determine these values from the contingency table we created earlier!
Note: In a bar chart like this, the x-axis should represent the independent variable (the category we are comparing), while the fill aesthetic should represent the dependent variable (the outcome we are measuring within each category). This ensures that we are visualizing how the dependent variable is distributed across different levels of the independent variable.
Lastly, we can enhance the presentation of our graph by making some aesthetic adjustments. First, we add a title and axis labels using the ‘labs()’ function: ‘labs(title = “Views on women by Country”, x = “Country”, y = “Proportions”)’.
Next, to improve readability, we need to adjust the angle of the x-axis labels so they don’t overlap. We do this with the following line: theme(axis.text.x=element_text(angle=20, hjust=1)). This simply tells R that we want to change the angle of the x axis text to 20 degrees and adjust the height by 1.
Here is the final code:
bar = AB_nafrica %>%
drop_na(COUNTRY, MenFinal) %>%
ggplot(aes(x=COUNTRY))+
geom_bar(position = "fill", aes(fill=MenFinal))+
labs(title = "Views on Women by Country", x = "Country", y = "Proportions")+
theme(axis.text.x=element_text(angle=20, hjust=1))
VI(bar)This chart has title 'Views on Women by Country'.
It has x-axis 'Country' with labels Algeria, Egypt, Libya, Mauritania, Morocco, Sudan and Tunisia.
It has y-axis 'Proportions' with labels 0.00, 0.25, 0.50, 0.75 and 1.00.
The chart is a bar chart with 7 vertical bars.
Controlling for a third variable
When we examine bivariate relationships, we can gain valuable insights into political issues. However, political and social phenomena are rarely driven by a single factor; there are often multiple causes and interactions between variables. For instance, if we wanted to understand what influences political participation, we might consider age, which tends to increase participation, and income, which also has a positive effect. Yet, age and income are themselves related - older individuals generally have higher incomes. This raises an important question: how can we distinguish between these effects and determine which factor is truly driving participation?
This is where statistical control comes in. By controlling for a variable, we can assess whether the relationship we are interested in remains significant even after accounting for other factors. In doing so, we refine our understanding of the data and enhance the credibility of our findings. If a relationship remains statistically significant after controlling for multiple factors, it increases our confidence that the effect is meaningful rather than a byproduct of another variable.
Adding a Third Variable to a Crosstab
We can introduce a third variable into a contingency table using the layers argument in the contTables function. This allows us to examine whether the relationship between our independent and dependent variables still holds when we account for an additional factor.
For example, we might want to investigate whether the relationship between North African Arabic countries and views on women persists when we control for gender. This means we are testing whether attitudes toward gender roles vary between countries because of national differences or because of differences in the gender composition of respondents.
To do this, we simply add layers = Gender to our contTables function.
Our control variable is Q1002, which indicates the gender of respondents. Before incorporating it into our contingency tables, we first need to examine its structure and determine whether any recoding is necessary. We begin by using the levels command to check the existing categories of this variable:
levels(AB_nafrica$Q1002)[1] "Male" "Female"
The output shows that Q1002 has only two levels: “Male” and “Female”, meaning no recoding is required. However, since Q1002 is not an intuitive variable name, we will create a duplicate and name it Gender for better clarity, using the mutate function:
AB_nafrica <- AB_nafrica %>%
mutate(Gender = Q1002)To verify that the renaming was successful, we use the levels command again on our newly named variable:
levels(AB_nafrica$Gender)[1] "Male" "Female"
Since the output confirms that the variable still contains the levels “Male” and “Female”, we now have a clearer, more user-friendly variable name, making our analysis more readable and intuitive.
Before we proceed, let’s do one more adjustment: we need to ensure our contingency table remains interpretable. Since our dataset includes 7 countries, displaying all of them in a single table twice (for men and women) could make it overwhelming, particularly for someone using a screen reader. Instead, we will focus on a new subset of countries with similar cultural and historical backgrounds.
For this example, we will examine Algeria, Morocco, and Tunisia — three North African countries with shared colonial histories, similar legal systems regarding gender rights, and comparable levels of urbanization. This selection allows us to explore how gender influences attitudes toward women within a similar cultural and political context, ensuring that any observed differences are more likely to be driven by gender rather than broader national distinctions.
To create this subset, we use the filter command with droplevels once again:
ABfac_subset <- AB_nafrica %>%
filter(COUNTRY %in% c("Algeria", "Morocco", "Tunisia")) %>%
mutate(COUNTRY = droplevels(COUNTRY))We will now use this cleaned dataset to create our contingency table while controlling for gender:
contTables(ABfac_subset, cols=MenFinal, rows = COUNTRY, layers = Gender, obs=FALSE, pcRow = TRUE)
CONTINGENCY TABLES
Contingency Tables
────────────────────────────────────────────────────────────────────────────
Gender COUNTRY Agree Disagree Total
────────────────────────────────────────────────────────────────────────────
Male Algeria % within row 81.66667 18.33333 100.00000
Morocco % within row 67.93388 32.06612 100.00000
Tunisia % within row 57.16724 42.83276 100.00000
Total % within row 68.57308 31.42692 100.00000
Female Algeria % within row 50.71283 49.28717 100.00000
Morocco % within row 34.82143 65.17857 100.00000
Tunisia % within row 29.88314 70.11686 100.00000
Total % within row 37.75758 62.24242 100.00000
Total Algeria % within row 66.92532 33.07468 100.00000
Morocco % within row 52.01717 47.98283 100.00000
Tunisia % within row 43.37553 56.62447 100.00000
Total % within row 53.53446 46.46554 100.00000
────────────────────────────────────────────────────────────────────────────
χ² Tests
─────────────────────────────────────────────────
Gender Value df p
─────────────────────────────────────────────────
Male χ² 78.44888 2 < .0000001
N 1731
Female χ² 52.92428 2 < .0000001
N 1650
Total χ² 124.56341 2 < .0000001
N 3381
─────────────────────────────────────────────────
How do we interpret this?
We get partial tables - one for male and one for female respondents. Within these partial tables we get a break down in the relationship between country and views on Women split by gender. In order to analyse them, we treat each partial table separately. Each table also has their own Chi-Square test.
We start by examining the percentages within the table, examine the patterns that we see. Then we can move onto comparing the two tables in terms of percentages - do they appear the same or different?
Finally, we can examine the Chi-Square statistcs:
If both Chi-Square tests have P < 0.05 the relationship holds.
If one was insignificant (e.g. p> 0.05) and the other was significant, we have partial significance - the relationship does not hold overall (e.g. it is clearly affected by third variable) but it does still seem to matter within some groups.
If neither Chi-Square is significant, the relationship does not hold. When we control for a third variable, the relationship we see has disappeared.
What do our results show us? The first thing we can see is that among Men, there seems to be a big difference among countries about their agreement with the statement that men should have final say in all matters. In Algeria, men seem to agree much more with the statement (82%), as opposed to Morroccan (68%) and Tunisian (57%) men.
Among Women, we see that the differences between countries are still significant. We see the percentage that agree with the statement are 51% in Algeria, but only 35% in Morocco and 30% in Tunisia.
What does this mean for our hypothesis? Remember, we are still testing the association between Country and views on Women - we are simply ‘controlling’ for gender.
Well, when we look at the results, we see that the p-value for both Male and Female is very small (less than 0.0000001), so much smaller than our critical value of 0.005, in both cases.
This means that we can reject our null hypothesis. Even when we control for Gender, we see that the association bteween countries (in this case a small subset of North African countries) and views on Women is significant.
Graphing Three-Way Crosstabs
Visualizing three-way crosstabs is straightforward: we simply use the facet_wrap() function with ggplot. This function allows us to split our graph into multiple panels based on the levels of a categorical variable. In this case, we use facet_wrap(~Gender), which means ggplot will create separate bar charts for each gender, making it easier to compare how views on women (MenFinal) vary between males and females across different countries.
We use the same code we used previously to create the bar graphs of the contingency tables, we just have to remember to update the dataset, changing from ABfac to ABfac_subset, and adding the facet_wrap. Here’s how it works in practice:
bar = ABfac_subset %>%
drop_na(COUNTRY, MenFinal) %>%
ggplot(aes(x=COUNTRY))+
geom_bar(position = "fill", aes(fill=MenFinal))+
labs(title = "Views on Women by Country and Gender", x = "Country", y = "Proportions")+
theme(axis.text.x=element_text(angle=20, hjust=1))+
facet_wrap(~Gender)
VI(bar)This chart has title 'Views on Women by Country and Gender'.
The chart is comprised of 2 panels containing sub-charts, arranged horizontally.
The panels represent different values of Gender.
Each sub-chart has x-axis 'Country' with labels Algeria, Morocco and Tunisia.
Each sub-chart has y-axis 'Proportions' with labels 0.00, 0.25, 0.50, 0.75 and 1.00.
Panel 1 represents data for Gender = Male COORD = 1.
Panel 1 is a bar chart with 3 vertical bars.
Bar 1 is centered at 1, and length is from 0.18 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 2 is centered at 2, and length is from 0.32 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 3 is centered at 3, and length is from 0.43 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 4 is centered at 1, and length is from 0 to 0.18 with fill colour brilliant bluish green which maps to = Disagree.
Bar 5 is centered at 2, and length is from 0 to 0.32 with fill colour brilliant bluish green which maps to = Disagree.
Bar 6 is centered at 3, and length is from 0 to 0.43 with fill colour brilliant bluish green which maps to = Disagree.
Panel 2 represents data for Gender = Female COORD = 1.
Panel 2 is a bar chart with 3 vertical bars.
Bar 1 is centered at 1, and length is from 0.49 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 2 is centered at 2, and length is from 0.65 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 3 is centered at 3, and length is from 0.7 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 4 is centered at 1, and length is from 0 to 0.49 with fill colour brilliant bluish green which maps to = Disagree.
Bar 5 is centered at 2, and length is from 0 to 0.65 with fill colour brilliant bluish green which maps to = Disagree.
Bar 6 is centered at 3, and length is from 0 to 0.7 with fill colour brilliant bluish green which maps to = Disagree.
Conclusion
In this session, we have explored how to construct and interpret contingency tables in R, allowing us to examine relationships between categorical variables. We also introduced three-way crosstabs by adding a control variable, demonstrating how to refine our analysis and better understand patterns in the data. Finally, we applied the chi-square test, a fundamental statistical tool for assessing whether observed differences in categorical data are statistically significant.
These techniques are essential for making sense of political and social data, helping us move beyond simple comparisons to test whether associations between variables hold up under statistical scrutiny.
Next, we move on to the homework exercises. You can continue working in the same Quarto file or open a new one. If you choose to stay in the same file, you do not need to reload the packages, set the working directory, or reload the dataset — you can proceed directly to Question 1a.
4. Homework Exercises
Introduction
For this homework, we are going to go continue our examination of the ArabBarometer dataset. We will examine the the nature of interpersonal trust in the Middle East and whether it varies across countries. We will also have a closer look at Palestine. We will look at measures of liberal thought by examining attitudes towards religious governmental leadership.
Questions to Answer:
- Are there differences in Interpersonal trust across the Middle East?
- What factors are associated with positive views of religious leaders in government?
Variables
COUNTRY: Which country is the survey respondent based in?Q103: Most people can be trustedQ609: How strong is your religious commitment?Q606_2: Religious leaders should be central to Government.Q1002: What is your gender?
Opening or Creating Script
You can either continue to use your Lab 4 quarto script or load a new one.
Loading Packages
Remember to start by loading the packages. We need these to run commands. Think about what packages do you need to run and what do they do?
library(jmv) #Runs descriptive statistics and contingency tables
library(haven) #Allows us to open SPSS(SAV) files.
library(tidyverse) #Allows us to create graphs and recode variables
library(BrailleR) # Enhances accessibility by providing text descriptions of graphs for blind usersLoading and Setting Data as Factor
Remember if you are starting a fresh script, we need to load in the data and also use the pipe to convert the data to as_factor and drop the levels within it.
AB <- read_spss("data/ArabBarometer.sav")
ABfac <-as_factor(AB) %>% droplevels(.)Research Question 1. What is the Association between Country and Interpersonal Trust?
Sorting our Dependent Variable (Q103)
The first thing I want you to do is to determine which variable should be the independent variable.
Question 1a. Why do we need to recode our variables?
# We need to recode variables to get rid of information that is not
#informative and may affect the relationship that we are interested in. If we
#don't, our statistical analysis will be impacted and we may incorrectly
#reject or fail to reject the null hypothesis.
#Recoding is an ESSENTIAL part of data analysis. Question 1b. Are there any missing values? If so, what values should be removed? Once you have determined this, please use the mutate and recode commands to remove them and name the new variable IPTrust.
levels(ABfac$Q103)[1] "Most can be trusted" "Must be careful" "Don’t know"
[4] "Refused to answer"
# When we look at the levels command, we can see that there are a number of values that would not be informative for our Research Question. "Don't know" and "Refused to answer" tell us nothing about our data, therefore, we need to remove them.
ABfac <- ABfac %>%
mutate(IPTrust = recode(Q103,
"Don’t know" = NA_character_,
"Refused to answer" = NA_character_))
levels(ABfac$IPTrust)[1] "Most can be trusted" "Must be careful"
Remember to check your new variable using attributes and levels to check it has coded it appropriately!
Checking our Independent Variable (COUNTRY)
Before we can consider examining any statistical tests we need to examine our independent variable, which in this case is COUNTRY.
Question 1c. What tests should you run? Are there any missing values that should be removed?
# There are many commands we could use - str, attributes, levels or summary. For this I will use levels.
levels(ABfac$COUNTRY) [1] "Algeria" "Egypt" "Iraq" "Jordan" "Kuwait"
[6] "Lebanon" "Libya" "Mauritania" "Morocco" "Palestine"
[11] "Sudan" "Tunisia"
#As we can see, there are no obvious bits of data that are 'missing' and we have no theoretical reason to remove any of these countries from the data set. On this basis, there is no recoding to do. Question 1d. Subset the dataset to include only Arabic countries from the Middle East: Iraq, Jordan, Kuwait, Lebanon, and Palestine. Save the new dataset as AB_meast.
AB_meast <- ABfac %>%
filter(COUNTRY %in% c("Iraq", "Jordan", "Kuwait", "Lebanon", "Palestine")) %>%
mutate(COUNTRY = droplevels(COUNTRY))Analysing our Data
Once our variables are sorted, we can start our analysis. Start off by thinking about what the hypotheses may be. In this case, we are interested in the relationship between country and trust. So the corresponding hypotheses will be:
- H0 (null): There is no association between country and level of interpersonal trust.
- Ha: There is an association between country and level of interpersonal trust.
Now that we’ve sorted our hypotheses, start by producing some descriptive statistics of the variable IPTrust.
Question 1e. What is the modal category?
descriptives(AB_meast, IPTrust, freq=TRUE)
DESCRIPTIVES
Descriptives
─────────────────────────────────
IPTrust
─────────────────────────────────
N 5124
Missing 5162
Mean
Median
Standard deviation
Minimum
Maximum
─────────────────────────────────
FREQUENCIES
Frequencies of IPTrust
───────────────────────────────────────────────────────────────
IPTrust Counts % of Total Cumulative %
───────────────────────────────────────────────────────────────
Most can be trusted 433 8.45043 8.45043
Must be careful 4691 91.54957 100.00000
───────────────────────────────────────────────────────────────
#The modal category is "Must be Careful".Question 1f. What percentage of individuals chose “Most can be trusted”?
# 8.45% chose "most can be trusted".Question 1g. Write one sentence on what this data tells you.
#The data shows a heavy skew towards individuals being mistrustful, with 91.5% stating that one must be careful. This is significantly higher than the number of individuals who believe they can trust most people. However, what we cannot tell with this data is whether there are patterns within countries. Perhaps some are more trusting than others?Next, we need to move onto think about an inferential test. We will use the Chi-square test as we have two factor (categorical) variables. Before we get started, answer the following questions:
Question 1h. What is a Chi-square test?
# A Chi-square test is an inferential test that allows us to ascertain whether a relationship between two variables may just occur because of chance.Question 1i. Why do we need to use percentages to analyse?
# In order to compare different columns, we need to use percentages as they may have different numbers of cases within them. Therefore, count data may be misleading.Question 1j. What direction should our percentages run in?
# Our Percentages ALWAYS run in the direction of the independent variable, If it is in the column, we choose column percentages. What is the association between Country and Interpersonal Trust?
Question 1k. Use the contTables function to produce a crosstab.
REMEMBER - we must think carefully about the direction of the percentages. Select them in the same place you have the independent variable. If your independent variable is in row, choose row percentages; if it is in a column, choose column percentages.
contTables(AB_meast, cols=IPTrust, rows = COUNTRY , pcRow = TRUE, obs = FALSE)
CONTINGENCY TABLES
Contingency Tables
────────────────────────────────────────────────────────────────────────────────────
COUNTRY Most can be trusted Must be careful Total
────────────────────────────────────────────────────────────────────────────────────
Iraq % within row 8.55162 91.44838 100.00000
Jordan % within row 9.47826 90.52174 100.00000
Kuwait % within row 13.87960 86.12040 100.00000
Lebanon % within row 3.96694 96.03306 100.00000
Palestine % within row 9.44700 90.55300 100.00000
Total % within row 8.45043 91.54957 100.00000
────────────────────────────────────────────────────────────────────────────────────
χ² Tests
──────────────────────────────────────
Value df p
──────────────────────────────────────
χ² 56.92600 4 < .0000001
N 5124
──────────────────────────────────────
What do the results show?
Question 1l. Write a couple of sentences on the relationship: are there clear patterns in the data? What does it show?
# The results show that though in general all countries seem to be distrustful, there are significant differences between the level of interpersonal trust in countries. If we take a look at extreme values, 14% of individuals in Kuwait believe you can trust most people. This compares to Lebanon where only 4% of individuals believe you can trust most people. These differences appear to be big, but in order to test our hypotheses, we must turn our attention to the p-value.Question 1m. Interpret the p-value: do you reject or fail to reject the null?
# When we look at the p-value, we can see that p < 0.0000001. This is significantly lower than our critical value of 0.05. On the basis of this, we can reject the null hypothesis. It does appear that there is a statistically significant association between Country and trust.Graphing the relationship
Finally for the first Research Question, I want you to create a graph of the relationship. I want you to also add titles and axes titles.
Top tip 1 - remember we need use a pipe to drop_na (missing values) from our graph.
Top tip 2 - in order to view all of our axis labels we need to angle them slightly so that they don’t all cover over each other. We do this by applying the line theme(axis.text.x=element_text(angle=20, hjust=1)). This simply tells R that we want to change the angle of the x axis text to 20 degrees and adjust the height by 1.
Question 1n. What variable should go in fill?
# We should put our dependent variable in fill so that we can see the
#differences within each category of our independent variable.
bar1 = AB_meast %>%
drop_na(COUNTRY, IPTrust) %>%
ggplot(aes(x=COUNTRY))+
geom_bar(position = "fill", aes(fill=IPTrust))+
labs(title = "Interpersonal Trust by Country", x = "Country", y = "Proportions")+
theme(axis.text.x=element_text(angle=20, hjust=1))
VI(bar1)This chart has title 'Interpersonal Trust by Country'.
It has x-axis 'Country' with labels Iraq, Jordan, Kuwait, Lebanon and Palestine.
It has y-axis 'Proportions' with labels 0.00, 0.25, 0.50, 0.75 and 1.00.
The chart is a bar chart with 5 vertical bars.
Bar 1 is centered at 1, and length is from 0.91 to 1 with fill colour strong reddish orange which maps to = Most can be trusted.
Bar 2 is centered at 2, and length is from 0.91 to 1 with fill colour strong reddish orange which maps to = Most can be trusted.
Bar 3 is centered at 3, and length is from 0.86 to 1 with fill colour strong reddish orange which maps to = Most can be trusted.
Bar 4 is centered at 4, and length is from 0.96 to 1 with fill colour strong reddish orange which maps to = Most can be trusted.
Bar 5 is centered at 5, and length is from 0.91 to 1 with fill colour strong reddish orange which maps to = Most can be trusted.
Bar 6 is centered at 1, and length is from 0 to 0.91 with fill colour brilliant bluish green which maps to = Must be careful.
Bar 7 is centered at 2, and length is from 0 to 0.91 with fill colour brilliant bluish green which maps to = Must be careful.
Bar 8 is centered at 3, and length is from 0 to 0.86 with fill colour brilliant bluish green which maps to = Must be careful.
Bar 9 is centered at 4, and length is from 0 to 0.96 with fill colour brilliant bluish green which maps to = Must be careful.
Bar 10 is centered at 5, and length is from 0 to 0.91 with fill colour brilliant bluish green which maps to = Must be careful.
Research Question 2. What is associated with positive views of religious leadership in government?
We will examine the factors associated with positive views of religious leadership in government in Palestine. One potential influence on these views is an individual’s level of religious identification. Those who strongly identify as religious may be more supportive of religious leadership in government, whereas those with weaker religious identification may be more inclined toward secular governance.
To explore this relationship, we propose the following hypotheses:
H0 There is no association between between an individual’s religious strength and their views on religious officials in government. Ha There is an association between between an individual’s religious strength and their views on religious officials in government.
Before analyzing the data, take a moment to consider what you expect the relationship to be. Do you anticipate a strong association? What social, political, or cultural factors might help explain any patterns we observe?
For the next part of the exercise, we are going to focus on just data from Palestine. This means that we are going to have to filter out data from our ABfac dataset and create a new dataset called ABfacPalestine.
Remember, that for this we need to use the filter command.
Question 2a. Create a new data object that contains just data from Palestine.
#We create a new data object called ABfacPalestine, filtering data from ABfac where COUNTRY is equal to Palestine.
ABfacPalestine <- filter(ABfac, COUNTRY == "Palestine")Next, we are going to look at two variables: Q606_2 (Religious Government) and whether it is related to an individual’s own religious strength (Q609). If any recoding is required please call the new version of Q606_2 ReligiousGov and the new version of Q609 ReligiousStrength.
Question 2b. Which variable should we treat as the dependent variable?
#In this instance, the dependent variable should be ReligiousGov as we are interested in whether an individual's religion strength is associated with it. Question 2c. Are there any values in Q609 that need to be removed?
Top Tip: Pay attention to the curly apostrophe in the "Don’t know" response option! If this causes issues, you can either copy and paste it directly from the levels output or manually type it using the following shortcuts:
Windows: Hold Alt, type
0146on the numeric keypad, then release Alt.Mac: Press Option + Shift + ].
levels(ABfacPalestine$Q609)[1] "Religious" "Somewhat religious" "Not religious"
[4] "Don’t know" "Refused to answer"
#We can see that we have values of "Don't know" and "Refused to answer" that we need to get rid of. Therefore we do need to create a new variable called ReligiousStrength:
ABfacPalestine <- ABfacPalestine %>%
mutate(ReligiousStrength = recode(Q609,
"Don’t know" = NA_character_,
"Refused to answer" = NA_character_))
levels(ABfacPalestine$ReligiousStrength)[1] "Religious" "Somewhat religious" "Not religious"
Question 2d. Are there any values in Q606_2 that need to be removed?
For the purposes of this I would like you to combine Strongly Agree with Agree and Strongly Disagree with Disagree as well as removing any missing values.
levels(ABfacPalestine$Q606_2)[1] "Strongly agree" "Agree" "Disagree"
[4] "Strongly disagree" "Don’t know" "Refused to answer"
#We can see the usual responses that we need to remove include "don't know" and "refused to answer". We also need to combine the values to make it just 'Agree' or 'Disagree'
ABfacPalestine <- ABfacPalestine %>%
mutate(ReligiousGov = recode(Q606_2,
"Don’t know" = NA_character_,
"Refused to answer" = NA_character_,
"Strongly agree" = "Agree",
"Agree" = "Agree",
"Strongly disagree" = "Disagree",
"Disagree" = "Disagree"))
levels(ABfacPalestine$ReligiousGov)[1] "Agree" "Disagree"
Once we have recoded our variables, we can again turn our attention to descriptive analyses followed by contingency tables with Chi-square tests.
Question 2e. Start by producing descriptive frequencies of both variables.
descriptives(ABfacPalestine, vars=c(ReligiousStrength, ReligiousGov),
freq=TRUE)
DESCRIPTIVES
Descriptives
───────────────────────────────────────────────────────────
ReligiousStrength ReligiousGov
───────────────────────────────────────────────────────────
N 1796 844
Missing 4 956
Mean
Median
Standard deviation
Minimum
Maximum
───────────────────────────────────────────────────────────
FREQUENCIES
Frequencies of ReligiousStrength
──────────────────────────────────────────────────────────────
ReligiousStrength Counts % of Total Cumulative %
──────────────────────────────────────────────────────────────
Religious 778 43.31849 43.31849
Somewhat religious 948 52.78396 96.10245
Not religious 70 3.89755 100.00000
──────────────────────────────────────────────────────────────
Frequencies of ReligiousGov
────────────────────────────────────────────────────────
ReligiousGov Counts % of Total Cumulative %
────────────────────────────────────────────────────────
Agree 372 44.07583 44.07583
Disagree 472 55.92417 100.00000
────────────────────────────────────────────────────────
Question 2f. What percentage of respondents are somewhat religious?
# 52.78% feel somewhat religious. This is also the modal category.Question 2g. What percentage of respondents Agree that religious leaders in government are good?
# 44.08% feel that religious leaders in government are good. Once you have looked at the descriptives, it is time to produce a contingency table and perform a Chi-square test. Answer the following questions:
Question 2h. Is there a pattern? What does the data show?
contTables(ABfacPalestine, cols=ReligiousGov, rows = ReligiousStrength , pcRow = TRUE, obs = FALSE)
CONTINGENCY TABLES
Contingency Tables
─────────────────────────────────────────────────────────────────────────────
ReligiousStrength Agree Disagree Total
─────────────────────────────────────────────────────────────────────────────
Religious % within row 56.98630 43.01370 100.00000
Somewhat religious % within row 35.87444 64.12556 100.00000
Not religious % within row 12.90323 87.09677 100.00000
Total % within row 44.18052 55.81948 100.00000
─────────────────────────────────────────────────────────────────────────────
χ² Tests
──────────────────────────────────────
Value df p
──────────────────────────────────────
χ² 49.04517 2 < .0000001
N 842
──────────────────────────────────────
#We can see that within the data there does appear to be a pattern. Those who are not religious are far more likely to disagree that Religious officials should be central to government. Conversely, those that identify as religious are more likely to agree than not that religious leaders should be central to government. While the pattern seems very strong, we still need to use a Chi-square test to address our null hypothesis. Question 2i. Do we reject or fail to reject our null hypothesis?
#When we examine the p-value, we can see that it is less than 0.0000001. This is less than our critical value of 0.05. On this basis we can reject our null hypothesis. It does appear that there is an association between strength of religion and views of religious leaders in government. Question 2j. Finally, please produce a graph of the relationship.
bar2 = ABfacPalestine %>%
drop_na(ReligiousGov, ReligiousStrength) %>%
ggplot(aes(x=ReligiousStrength))+
geom_bar(position = "fill", aes(fill=ReligiousGov))+
labs(title = "Views on Religious Government by Religious Stregth",
x = "Religious Strength",
y = "Proportions")+
theme(axis.text.x= element_text(angle=20, hjust=1))
VI(bar2)This chart has title 'Views on Religious Government by Religious Stregth'.
It has x-axis 'Religious Strength' with labels Religious, Somewhat religious and Not religious.
It has y-axis 'Proportions' with labels 0.00, 0.25, 0.50, 0.75 and 1.00.
The chart is a bar chart with 3 vertical bars.
Bar 1 is centered at 1, and length is from 0.43 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 2 is centered at 2, and length is from 0.64 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 3 is centered at 3, and length is from 0.87 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 4 is centered at 1, and length is from 0 to 0.43 with fill colour brilliant bluish green which maps to = Disagree.
Bar 5 is centered at 2, and length is from 0 to 0.64 with fill colour brilliant bluish green which maps to = Disagree.
Bar 6 is centered at 3, and length is from 0 to 0.87 with fill colour brilliant bluish green which maps to = Disagree.
While we can see clear differences and have addressed our research question, there is one final step I’d like you to take in this section: I want you to create create a three-way crosstabulation, controlling for Gender in layers. Additionally, generate a graph to visualize this three-way relationship.
Question 2k. First, check variable Q1002 and create a new variable, Gender, ensuring that any missing values are removed.
levels(ABfacPalestine$Q1002)[1] "Male" "Female"
# We can see that we only have the categories 'Male' and 'Female', so we don't need to get rid of anything. However, let's still create a duplicate of the variable and call it Gender, which is a more descriptive name.
ABfacPalestine <- ABfacPalestine %>%
mutate(Gender = Q1002)
levels(ABfacPalestine$Gender)[1] "Male" "Female"
Question 2l. Before proceeding, let’s ensure that the three-way contingency table remains clear and interpretable. To simplify the analysis, recode the variable ReligiousStrength into two categories: “Religious” and “Not Religious”. Name the new variable ReligiousStrength2.
levels(ABfacPalestine$ReligiousStrength)[1] "Religious" "Somewhat religious" "Not religious"
ABfacPalestine <- ABfacPalestine %>%
mutate(ReligiousStrength2 = recode(ReligiousStrength,
"Religious" = "Religious",
"Somewhat religious" = "Religious",
"Not religious" = "Not religious"))
levels(ABfacPalestine$ReligiousStrength2)[1] "Religious" "Not religious"
Now we can run a three-way crosstabulation with our control variable Gender.
Question 2m. Which variable should go in layers?
# We should put Gender in layers as this is our control variable. Question 2n. How do we interpret a three-way crosstab?
contTables(ABfacPalestine, cols=ReligiousGov, rows = ReligiousStrength2, pcRow = TRUE, layers = Gender, obs = FALSE)
CONTINGENCY TABLES
Contingency Tables
───────────────────────────────────────────────────────────────────────────────────────
Gender ReligiousStrength2 Agree Disagree Total
───────────────────────────────────────────────────────────────────────────────────────
Male Religious % within row 42.14660 57.85340 100.00000
Not religious % within row 16.66667 83.33333 100.00000
Total % within row 41.00000 59.00000 100.00000
Female Religious % within row 48.25175 51.74825 100.00000
Not religious % within row 7.69231 92.30769 100.00000
Total % within row 47.05882 52.94118 100.00000
Total Religious % within row 45.37608 54.62392 100.00000
Not religious % within row 12.90323 87.09677 100.00000
Total % within row 44.18052 55.81948 100.00000
───────────────────────────────────────────────────────────────────────────────────────
χ² Tests
────────────────────────────────────────────────
Gender Value df p
────────────────────────────────────────────────
Male χ² 4.613563 1 0.0317201
N 400
Female χ² 8.331585 1 0.0038962
N 442
Total χ² 12.767173 1 0.0003528
N 842
────────────────────────────────────────────────
# We interpret a three-way crosstab by still focusing on our original hypothesis. We are simply asking: can we still reject the null when we control for a third variable? We need to examine each crosstab individually looking at Male and Female. Question 2o. What is the association between ReligiousStrength2 and ReligiousGov for Men and Women?
#Examining the contingency table, we can see distinct patterns in attitudes toward religious leaders in government based on gender and religious strength.
#Among religious individuals, men and women hold relatively similar views. 42.1% of religious men and 48.3% of religious women agree that religious leaders should be involved in government. While women in this group are slightly more likely to agree, the difference is modest.
#In contrast, among non-religious individuals, the difference is more pronounced. 16.7% of non-religious men agree that religious leaders should have a role in government, compared to only 7.7% of non-religious women. This suggests that non-religious men are more open to the idea of religious leadership in government than non-religious women.
#Overall, the trend remains consistent: as individuals identify as more religious, they are more likely to support the role of religious leaders in government, regardless of gender. However, the gender gap is wider among non-religious individuals, where men show greater support for religious leadership compared to women.Question 2p. Do we reject or fail to reject the null hypothesis that there is no association between ReligiousGov and ReligiousStrength, now that we control for Gender?
Top Tip: As a reminder, if all Chi-square tests are below 0.05, we still reject the null hypothesis. If only some are below 0.05 we partially reject the null. If all are above 0.05 we fail to reject the null.
#In this instance, we see all p-values are well below 0.05. Therefore, we can reject the null hypothesis. Even when we control for gender, strength of religion is still related to views of religious leaders in government. Question 2q. Finally, please create a graph that illustrates this 3 way relationship.
bar3 = ABfacPalestine %>%
drop_na(ReligiousGov, ReligiousStrength2, Gender) %>%
ggplot(aes(x=ReligiousStrength2))+
geom_bar(position = "fill", aes(fill=ReligiousGov))+
labs(title = "Views on Religious Government by Religious Stregth",
x = "Religious Strength",
y = "Proportions")+
theme(axis.text.x= element_text(angle=20, hjust=1))+
facet_wrap(~Gender)
VI(bar3)This chart has title 'Views on Religious Government by Religious Stregth'.
The chart is comprised of 2 panels containing sub-charts, arranged horizontally.
The panels represent different values of Gender.
Each sub-chart has x-axis 'Religious Strength' with labels Religious and Not religious.
Each sub-chart has y-axis 'Proportions' with labels 0.00, 0.25, 0.50, 0.75 and 1.00.
Panel 1 represents data for Gender = Male COORD = 1.
Panel 1 is a bar chart with 2 vertical bars.
Bar 1 is centered at 1, and length is from 0.58 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 2 is centered at 2, and length is from 0.83 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 3 is centered at 1, and length is from 0 to 0.58 with fill colour brilliant bluish green which maps to = Disagree.
Bar 4 is centered at 2, and length is from 0 to 0.83 with fill colour brilliant bluish green which maps to = Disagree.
Panel 2 represents data for Gender = Female COORD = 1.
Panel 2 is a bar chart with 2 vertical bars.
Bar 1 is centered at 1, and length is from 0.52 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 2 is centered at 2, and length is from 0.92 to 1 with fill colour strong reddish orange which maps to = Agree.
Bar 3 is centered at 1, and length is from 0 to 0.52 with fill colour brilliant bluish green which maps to = Disagree.
Bar 4 is centered at 2, and length is from 0 to 0.92 with fill colour brilliant bluish green which maps to = Disagree.
We have covered a lot of ground in this workbook. Well done!
Appendix: Calculating the Chi-Square Test – Expected vs. Observed Values
As discussed, the Chi-Square test helps determine whether two categorical variables are independent of each other. In other words, it tests whether there is a relationship (or association) between them. The test does this by comparing observed values (actual data) with expected values (theoretical data assuming no relationship).
Expected values are calculated under the assumption that the two variables are independent—meaning there is no systematic association between them. Specifically, the expected values reflect what we would anticipate in each cell of a contingency table if the distribution were purely random. If no relationship exists between the two variables, we expect each cell to contain values proportional to the overall distribution. However, if a relationship does exist, some cells will have higher or lower counts than expected.
Simply put:
The bigger the difference between observed and expected values, the less likely it is that the relationship occurred by chance.
A larger Chi-Square statistic suggests a stronger deviation from the null hypothesis, meaning the observed pattern is unlikely to be random.
Example: Observed vs. Expected Values
To illustrate, let’s revisit our first Research Question: Do All Arabic Nations Treat Women The Same?
Recall our hypotheses:
H0 There is no relationship between Country and Views of Women
Ha There is a relationship between Country and Views of Women
If the null hypothesis is correct, the same proportion of people in each country should hold similar views on women. That is, the distribution of responses should be uniform across all countries.
To calculate the expected counts (E) for each cell in our contingency table, we use the formula:
E=(Row Total×Column Total)÷Grand Total.
In other words: the Expected value equals row total multiplied by column total, then divided by the grand total.
We can compute this in R using the following code:
contTables(AB_nafrica, cols=MenFinal, rows = COUNTRY , exp = TRUE)
CONTINGENCY TABLES
Contingency Tables
─────────────────────────────────────────────────────────────────
COUNTRY Agree Disagree Total
─────────────────────────────────────────────────────────────────
Algeria Observed 690 341 1031
Expected 600.8920 430.1080 1031.0000
Egypt Observed 605 370 975
Expected 568.2539 406.7461 975.0000
Libya Observed 739 468 1207
Expected 703.4691 503.5309 1207.0000
Mauritania Observed 644 361 1005
Expected 585.7386 419.2614 1005.0000
Morocco Observed 606 559 1165
Expected 678.9905 486.0095 1165.0000
Sudan Observed 688 441 1129
Expected 658.0088 470.9912 1129.0000
Tunisia Observed 514 671 1185
Expected 690.6470 494.3530 1185.0000
Total Observed 4486 3211 7697
Expected 4486.0000 3211.0000 7697.0000
─────────────────────────────────────────────────────────────────
χ² Tests
──────────────────────────────────────
Value df p
──────────────────────────────────────
χ² 185.9512 6 < .0000001
N 7697
──────────────────────────────────────
What does it show? Well if there was no difference between country and views on women, we would expect observed and expected values to be very similar. Are they? In general, no! We see big gaps between observed and expected values. For example, in the case of Mauritania, the observed value for Agree/Disagreee are 644 and 361, whilst the expected values are 585.7386 and 419.2614. This means that it is quite likely there is some sort of relationship between country and views of women.
We can confirm this by calculating the Chi-Square statistic (𝜒²) using the formula:
χ2=∑(Observed−Expected)2÷Expected
Here, Chi-Square equals the sum of the squared differences between observed and expected values, divided by the expected value for each cell. In essence, the formula does the following:
Subtract the expected value from the observed value.
Square the result.
Divide by the expected value.
Repeat this for all cells in the table and sum the results.
Again, R has already calculated this for us. In this case, the Chi-Square has a very large value (185.9512) and a very small p-value (less than 0.0000001). Therefore, we reject our null hypothesis: it seems that attitudes toward women differ significantly across North African Arabic nations.