5 Satisfaction Within Multiracial Neighborhoods
5.1 Distribution of respondents across neighborhoods
5.1.1 Median satisfaction level in tracts
To prevent large values on intercepts, I changed the reference value of the sample_tract variable to the tract with the median level of satisfaction among neighborhoods. When calculating the median, include only those tracts with at least two respondents.
mutrtall <- dcas16 %>%
filter(neighborhood=="Global Neighborhood") %>%
group_by(sample_tract) %>%
summarize(
N = n(),
tractsat = mean(satisfied)
) %>%
ungroup()
mutrt <- mutrtall %>%
filter(N>1) %>%
arrange(tractsat)
medtrt <- mutrt$sample_tract[round(nrow(mutrt)/2)] %>% as.character()
medtrtval <- mutrt$tractsat[mutrt$sample_tract==medtrt]*100
dcas16svy <- update(
dcas16svy, sample_tract = relevel(sample_tract, ref=medtrt)
)
## Add following to allow MIpredict to predict values at intercept
dcas16$sample_tract <- relevel(dcas16$sample_tract, ref=medtrt)
onlyone <- nrow(mutrtall) - nrow(mutrt)
onlyonelist <- mutrtall$sample_tract[mutrtall$N==1]
dcas16svy <- subset(dcas16svy, !(sample_tract %in% onlyonelist))
dcas16svy <- update(
dcas16svy, sample_tract = relevel(factor(sample_tract), ref=medtrt))The reference level for sample_tract was set to tract 24031700817, in which 75% of residents reported being satisfied.
5.1.2 Count of respondents across neighborhoods
Plot the distribution of respondents per tract. There are 9 tracts in the sample with a single respondent. There are 6.5 respondents per tract on average (median=5) with a maximum of 20 respondents per tract. The sample size for the multiracial neighborhood resident sample used for analysis is 632.

5.1.3 Distribution of respondents by race
The analyses below consider the distribution of respondents by race across neighborhoods. Since the data include respondents, I do not need imputed values. I pull the data from the first imputed dataset. From that dataset, I calculate the percentage and sum of respondents for each race across neighborhoods.
## Summarize respondents across neighborhoods
wndta <- dcas16svy$designs[[1]]$variables
wncnt <- wndta %>%
group_by(sample_tract, raceeth) %>%
count() %>%
group_by(sample_tract) %>%
mutate(
pct = n / sum(n),
N = sum(n)
) %>%
ungroup() %>%
pivot_wider(
id_cols = c(sample_tract, N), names_from = raceeth, values_from = pct
) %>%
mutate(across(-1, ~replace_na(., 0))) %>%
select(sample_tract, N, asian, black, latino, white) %>%
filter(N > 1)
## Count number of neighborhoods with respondents of all four racial groups
all_pres <- wncnt %>%
mutate(allpres = if_all(-1:-2, ~ . > 0)) %>%
summarise(allpres = sum(allpres)) %>%
pull()There of the 103 neighborhoods with two or more respondents, 26 neighborhoods (25.2 percent) contain respondents who identify across all four racial groups. Table 5.1 contains descriptive statistics of the distribution of the racial identities of respondents across neighborhoods and Table 5.2 contains the number of respondents who live in neighborhoods where all other respondents share the same racial identity.
## Respondent distribution across neighborhoods
bind_cols(
tibble(Statistic =
c("Minimum", "First Quart.", "Median", "Mean", "Third Quart.",
"Maximum",
"All of race",
"None of race")
),
bind_rows(
sapply(wncnt[, -1:-2], summary) %>% as_tibble() %>% setNames(racelabs),
## Number of neighborhoods with all of each race
sapply(wncnt[, -1:-2], function(x) sum(x == 1)) %>% setNames(racelabs),
## Number of neighborhoods with none of each race
sapply(wncnt[, -1:-2], function(x) sum(x == 0)) %>% setNames(racelabs)
)
) %>%
as_huxtable() %>%
set_bold(1, everywhere, TRUE) %>%
set_number_format(2:7, -1, "%.2f") %>%
set_align(everywhere, -1, "right") %>%
set_caption(paste("Descriptive statistics of distribution of respondents",
"across neighborhoods by race")) %>%
set_label("tab:nhood-desc")| Statistic | Asian | Black | Latino | White |
|---|---|---|---|---|
| Minimum | 0.00 | 0.00 | 0.00 | 0.00 |
| First Quart. | 0.05 | 0.00 | 0.00 | 0.25 |
| Median | 0.29 | 0.00 | 0.10 | 0.39 |
| Mean | 0.29 | 0.14 | 0.16 | 0.41 |
| Third Quart. | 0.46 | 0.25 | 0.25 | 0.56 |
| Maximum | 1.00 | 0.75 | 0.75 | 1.00 |
| All of race | 3 | 0 | 0 | 5 |
| None of race | 26 | 52 | 42 | 14 |
## Count of respondents living in neighborhood with only same-race neighbors
wndta %>%
left_join(wncnt, by = "sample_tract") %>%
filter(if_any(c(asian, black, latino, white), ~ . == 1)) %>%
summarize(across(c(asian, black, latino, white), sum)) %>%
rename_with(~sub("^(\\w)", "\\U\\1", ., perl = TRUE)) %>%
as_huxtable() %>%
set_caption(paste(
"Number of respondents living in neighborhood with same-race",
"neighbors, by race"
)) %>%
set_label("tab:nhood-only")| Asian | Black | Latino | White |
|---|---|---|---|
| 8 | 0 | 0 | 16 |
5.2 Descriptive analysis of neighborhood satisfaction
Calculate the unconditional percentage of respondents who are satisfied in their neighborhood by race.
racedfs <- list(
dcas16svy,
subset(dcas16svy, raceeth=="asian"),
subset(dcas16svy, raceeth=="black"),
subset(dcas16svy, raceeth=="latino"),
subset(dcas16svy, raceeth=="white")
)
descwn <- lapply(racedfs, function(df){
res <- with(df, svymean(~satisfied)) %>% MIcombine()
n <- nrow(df$designs$imp1)
list(mean16=coef(res)*100, se16=sqrt(vcov(res)[1,1])*100, n16 = n)
}) %>%
bind_rows() %>%
mutate(race = racelevs)Create a 4x4 matrix where each cell represents the difference in satisfaction percentages between the racial group listed in the column and the racial group listed in the row. No values are entered for the bottom triangle or the diagonal.
## Create matrix of differences
diffmat <- matrix(rep(NA_real_, 16), nrow=4)
musat <- descwn$mean16[1]
muraces <- descwn$mean16[-1]
for(i in 1:3) {
start <- i+1
for(j in start:4) {
diffmat[i, j] <- muraces[j] - muraces[i]
}
}
colnames(diffmat) <- racelevs[-1]Add an additional row to the top of the matrix that contains the percent of each group that reports being satisfied in their neighborhoods. Add an additional column to the left that contains a) the overall percent of residents who are satisfied living in multiracial neighborhoods and b) the difference between the percent of the racial group listed in the row and the overall mean. This table is saved to tables/within_descriptives.tex.
descwn_tbl <- bind_rows(
descwn$mean16[-1] %>% set_names(racelevs[-1]), ## Percent satisfied in group
as_tibble(diffmat) ## Diff. matrix
) %>%
add_column(all = c(musat, muraces - musat), .before = 1)
names(descwn_tbl) <- c("All", "Asian", "Black", "Latino", "White")
descwn_tbl<- descwn_tbl %>%
mutate_all(round, 1) %>%
huxtable() %>%
# insert_row(c("All", "Asian", "Black", "Latino", "White")) %>%
insert_row(rep(NA, 5), after=2) %>%
insert_column(c("Group", "Percent satisfied", "Difference",
"Asian", "Black", "Latino", "White")) %>%
set_number_format(everywhere, everywhere, "%5.1f")
descwn_tbl| Group | All | Asian | Black | Latino | White |
|---|---|---|---|---|---|
| Percent satisfied | 71.3 | 71.7 | 68.8 | 75.0 | 70.0 |
| Difference | |||||
| Asian | 0.4 | -3.0 | 3.2 | -1.8 | |
| Black | -2.5 | 6.2 | 1.2 | ||
| Latino | 3.7 | -5.0 | |||
| White | -1.3 |
5.3 Regression anaysis of neighborhood satisfaction
Follow a similar process of model development as in the separate multiracial neighborhood and complete DC-area datasets. Add a fourth model that removes race from the model to examine whether removing the race variables improves the model fit. Include a neighborhood fixed effect in all models so that the coefficients represent the difference for residents living in the same neighborhood.
- Race and neighborhood fixed effects
- Race, individual demographic characteristics (age, foreign-born, gender, children present, marital status, and education), and neighborhood fixed effects
- Race, individual demographic characteristics, neighborhood experience (home ownership, years in the neighborhood, and perceived neighborhood size), and neighborhood fixed effects
- No race, only individual demographic characteristics, neighborhood experience, and neighborhood fixed effects
m1 <- "raceeth + sample_tract"
m2 <- paste(m1, "+ agec + forbornc + manc + kidsc + marriedc",
" + educ1c + educ3c + educ4c + educ5c")
m3 <- paste(m2, "+ ownc + nhdyrsc + nhdsize2c + nhdsize3c")
m4 <- sub("raceeth \\+ ", "", m3)Estimate model parameters for each of the four models. Record the parameter estimates and standard errors in a table stored in file tables/within.tex.
## Note: "non-integer #successes" warnings suppressed
m1wn <- with(dcas16svy, svyglm(
as.formula(paste('satisfied ~', m1)), family=binomial)
)
m2wn <- with(dcas16svy, svyglm(
as.formula(paste('satisfied ~', m2)), family=binomial)
)
m3wn <- with(dcas16svy, svyglm(
as.formula(paste('satisfied ~', m3)), family=binomial)
)
m4wn <- with(dcas16svy, svyglm(
as.formula(paste('satisfied ~', m4)), family=binomial)
)
wn_tbl <- report_models(
MIcombine_aic(m1wn), MIcombine_aic(m3wn), MIcombine_aic(m4wn),
caption = paste(
"Logistic regression coefficients and standard errors predicted",
"from models estimating neighborhood satisfaction among residents",
"of mulitracial neighborhoods"
),
label = "tab:within",
reglabels = regression_labels,
use.headers = TRUE
)
statrow <- nrow(wn_tbl)-3
wn_tbl <- insert_row(
wn_tbl, c("Tract fixed effects", rep("X", 3)),after=statrow) %>%
set_top_border(statrow+1, everywhere, TRUE) %>%
set_top_border(statrow+2, everywhere, FALSE) %>%
set_top_padding(0) %>%
set_bottom_padding(0)
cat(
sub("\\(\\\\#(tab:.+?)\\)", "\\\\label{\\1\\}", to_latex(wn_tbl)),
file="tables/within.tex"
)
wn_tbl| (1) | (2) | (3) | |
|---|---|---|---|
| (Intercept) | 0.533 | 0.512 | 0.838 |
| (1.051) | (1.089) | (1.144) | |
| Race | |||
| Asian | -0.050 | 0.041 | |
| (0.384) | (0.487) | ||
| Black | 0.364 | 0.450 | |
| (0.400) | (0.450) | ||
| Latinx | 0.207 | 0.507 | |
| (0.424) | (0.539) | ||
| Demographics | |||
| Age | 0.003 | 0.003 | |
| (0.012) | (0.012) | ||
| Foreign Born | -0.106 | -0.057 | |
| (0.446) | (0.348) | ||
| Male | 0.219 | 0.190 | |
| (0.297) | (0.298) | ||
| Children Present | -0.659 | -0.568 | |
| (0.376) | (0.370) | ||
| Married | 0.415 | 0.326 | |
| (0.315) | (0.308) | ||
| Socioeconomic | |||
| <H.S. | -1.824 * | -1.802 * | |
| (0.863) | (0.881) | ||
| Some college, no B.A. | -1.031 | -1.030 | |
| (0.635) | (0.632) | ||
| B.A. | -0.976 | -1.050 | |
| (0.608) | (0.603) | ||
| M.A.+ | -1.362 * | -1.434 * | |
| (0.587) | (0.578) | ||
| Neighborhood perceptions | |||
| Home owner | 0.734 | 0.719 | |
| (0.396) | (0.398) | ||
| Years in neighborhood | -0.019 | -0.020 | |
| (0.017) | (0.017) | ||
| 10-50 blocks | 1.030 ** | 1.070 ** | |
| (0.377) | (0.358) | ||
| >50 blocks | 0.320 | 0.457 | |
| (0.603) | (0.580) | ||
| Tract fixed effects | X | X | X |
| N | 632 | 632 | 632 |
| AIC | 663.145 | 647.778 | 642.032 |
| *** p < 0.001; ** p < 0.01; * p < 0.05. | |||
5.4 Marginal Effect of Race on Neighborhood Satisfaction
Calculate the marginal effect of race on neighborhood satisfaction using white residents as the reference group. The function MImargins() is defined in the file marginal_effects.R. The function combines the standard errors of marginal effects from the multiply imputed datasets using Rubin’s rules (following this algorithm).
## Calculate partial effects of race
m1wn_mfx <- MImargins(m1wn, param="margins")
m3wn_mfx <- MImargins(m3wn, param="margins")
## Record marginal effects and standard errors in table and report
mfxwn <- inner_join(m1wn_mfx, m3wn_mfx, by="raceeth",
suffix=c(".Unadjusted", ".Adjusted"))
mfxwn_tbl <- mfxwn %>%
mutate_at(vars(starts_with("val")), ~paste0(" ", round(.,3), " ")) %>%
mutate_at(vars(starts_with("SE")), ~paste0("(", round(.,3), ")"))
kable(mfxwn_tbl, digits=3)| raceeth | val.Unadjusted | SE.Unadjusted | val.Adjusted | SE.Adjusted |
|---|---|---|---|---|
| asian | -0.008 | (0.059) | 0.006 | (0.068) |
| black | 0.053 | (0.058) | 0.06 | (0.059) |
| latino | 0.031 | (0.063) | 0.067 | (0.069) |
## Plot marginal effects and standard errors
mfxwn_long <- bind_rows(m1wn_mfx, m3wn_mfx) %>%
mutate(
model=relevel(factor(rep(c("Unadjusted", "Adjusted"), each=3)),
ref="Unadjusted"),
raceeth = sub("^(\\w)", "\\U\\1", raceeth, perl = TRUE)
)
dodge_wd <- 0.25
wn_mfx_plt <- ggplot(mfxwn_long,
aes(x=raceeth, y=val, ymin=val-1.96*SE, ymax=val+1.96*SE,
group=model, color=model, shape=model)) +
geom_point(position=position_dodge(width=dodge_wd), size=2.15) +
geom_linerange(size=.5, position=position_dodge(dodge_wd)) +
geom_hline(yintercept=0, color="#666666") +
scale_color_manual(values = c("#888888", "#222222")) +
scale_x_discrete(
labels=gsub("^(\\w)", "\\U\\1", mfxwn_long$raceeth, perl=TRUE)
) +
scale_y_continuous(limits=c(-.21, .21)) +
# scale_shape_discrete(labels=c("No controls", "With controls")) +
labs(
x = NULL,
y = "Marginal effect",
shape = NULL, color = NULL
) +
theme_minimal() +
theme(
legend.position = "bottom",
panel.grid.major.x = element_blank()
)
wn_mfx_plt_cap <- paste(
"Marginal effects of race on being satisfied in multiracial",
"neighborhoods compared to white residents of multiracial neighborhoods"
)
Figure 5.1: Marginal effects of race on being satisfied in multiracial neighborhoods compared to white residents of multiracial neighborhoods
5.5 Partial Predicted Probabilities
m3wn_prd <- MImargins(m3wn, param="predicted")
kable(m3wn_prd)| raceeth | val | SE |
|---|---|---|
| white | 0.6832765 | 0.0365181 |
| asian | 0.6889261 | 0.0477260 |
| black | 0.7434700 | 0.0424701 |
| latino | 0.7505796 | 0.0509451 |
5.6 Wald Statistics of Model Fit
Report the value of Wald tests measuring the change in model fit for the full model (Model 3) compared to a model without race covariates (Model 4).
racewn_wald <- lapply(m3wn, regTermTest, test.terms=~raceeth, df=NULL)
racewn_wald_tbl <- tibble(
val = c(
sapply(racewn_wald, function(x) x$Ftest),
sapply(racewn_wald, function(x) x$p)
),
stat = rep(c("F test", "p"), each=5),
i = rep(1:5,2)
) %>%
pivot_wider(id_cols = "stat", values_from="val", names_from="i",
names_prefix="imp")
racewn_wald_tbl$mean <- apply(racewn_wald_tbl[, 2:6], 1, mean)
racewn_wald_tbl$min <- apply(racewn_wald_tbl[, 2:6], 1, min)
racewn_wald_tbl$max <- apply(racewn_wald_tbl[, 2:6], 1, max)
kable(racewn_wald_tbl, digits=3)| stat | imp1 | imp2 | imp3 | imp4 | imp5 | mean | min | max |
|---|---|---|---|---|---|---|---|---|
| F test | 0.633 | 0.622 | 0.563 | 0.631 | 0.588 | 0.607 | 0.563 | 0.633 |
| p | 0.594 | 0.601 | 0.640 | 0.595 | 0.623 | 0.611 | 0.594 | 0.640 |