Reputation: 449
I am working with survey data that has a question about race. Each race category is its own variable. Here is what I want to do:
p.race
.p.race
the value of one of the eight variables for race/ethnicity (below).p.race
the value "Two or more races" in such cases.p.race
the value "Hispanic or Latino" when they indicated this ethnicity.p.poc
, to indicate if they are a person of color (i.e., not white, including Hispanic/Latino). This shall be 0 or 1.The eight race categories are white*, black*, Asian*, AIAN*, NHPI*, some other race*, two or more races*, and Hispanic; where * denotes not Hispanic or Latino ethnicity.
Here is what I tried so far for parsing out "Two or more races":
p['p.race'] <- NA # create new variable for race
# list of variable names that store a string indicating the race
## e.g., `race_white` would be either blank or contain "White, European, Middle Eastern, or Caucasian"
race.list <- c('p.race_white', 'p.race_black', 'p.race_asian', 'p.race_aian', 'p.race_nhpi', 'p.race_other')
# iterate through each record
for ( n in 1:length(p) ) {
multiflag = 0
# iterate through the race list
for ( i in race.list ) {
# if it is not blank, +1 to multiflag
if ( p$i[n] != '' ) {
multiflag <- multiflag + 1
}
}
# if multiflag was flagged more than once, assign "Two or more races" to `race`
if ( multiflag > 1 ) {
p$p.race[n] <- 'Two or more races'
}
}
When executed, it returns this error:
> Error in if (p$i[n] != "") { : argument is of length zero
And here is my poc
variable coding with error below:
p['p.poc'] <- 0 # create a new variable for whether they are a person of color
for ( n in 1:length(p) ) {
if ( p$p.race_black[n] == 'Black, African-American, or African'
| p$p.race_asian[n] == 'Asian or Asian-American'
| p$p.race_aian[n] == 'American Indian or Alaskan Native'
| p$p.race_nhpi[n] == 'Native Hawaiian or other Pacific Islander'
| p$p.race_other[n] == 'Other (please specify)'
| p$p.hispanic[n] == 'Yes') {
p$p.poc[n] <- 1
}
}
> Error in if (p$p.race_black[n] == "Black, African-American, or African" | :
missing value where TRUE/FALSE needed
I don't really know where to start for assigning the new race
variable one of the eight race categories without making it a very long code.
If it helps, below are the survey questions:
Q1. Do you consider yourself of Hispanic, Latino, or Spanish origin?
Q2. Which race do you identify with (check all that apply)?
And here is the sample output (text truncated):
> p[264:271]
#
# p.hispanic p.race_white p.race_black p.race_asian p.race_aian p.race_nhpi p.race_other
# 1 Yes White
# 2 No White
# 3 No Black
# 4 No White Asian
# 5 Yes Some other race
And here is a dput
output:
> dput(p[264:270])
structure(list(p.hispanic = structure(c(2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 2L,
2L, 2L, 2L, 2L, 3L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 3L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("", "No", "Yes"
), class = "factor"), p.race_white = structure(c(2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 1L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 2L, 2L, 2L,
1L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 2L, 2L,
2L, 1L, 2L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 2L, 2L), .Label = c("",
"White, European, Middle Eastern, or Caucasian"), class = "factor"),
p.race_black = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L,
1L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("",
"Black, African-American, or African"), class = "factor"),
p.race_asian = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 2L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L), .Label = c("",
"Asian or Asian-American"), class = "factor"), p.race_aian = structure(c(1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L,
1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L), .Label = c("", "American Indian or Alaskan Native"
), class = "factor"), p.race_nhpi = c(NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
p.race_other = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L,
1L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("",
"Other (please specify)"), class = "factor")), .Names = c("p.hispanic",
"p.race_white", "p.race_black", "p.race_asian", "p.race_aian",
"p.race_nhpi", "p.race_other"), class = "data.frame", row.names = c(NA,
-79L))
Upvotes: 2
Views: 1366
Reputation: 36076
The way my bring work, this sort of task always seems easier if the data are in a long format instead of a wide format. However, this means a unique ID per response is needed - in a case like this you can just assign an integer to each row.
library(tidyr)
library(dplyr)
# Add individual ID to each row
p = mutate(p, id = 1:n())
Once that is done, I would do a little work to make the p.hispanic
column look more like the other race columns, put the dataset in a long format, remove all NA
/blanks, then make the two new variables. Once the new variables are made, they can be joined to the original. I use package tidyr for reshaping and dplyr for manipulation.
p %>%
mutate(p.hispanic = ifelse(p.hispanic == "No", NA, "Hispanic or Latino")) %>% # change p.hispanic column
gather(category, answer, p.hispanic:p.race_other, na.rm = TRUE) %>%
filter(answer != "") %>% # get rid of blanks (if were NA would have removed in "gather")
group_by(id) %>%
# Create new variable p.race and p.pop based on rules
mutate(p.race = ifelse(n_distinct(answer) > 1, "Two or more races", answer),
p.poc = as.integer(p.race == "White, European, Middle Eastern, or Caucasian")) %>%
slice(1) %>% # take only 1 record for the duplicate id's
select(-category, - answer) %>% # remove columns that aren't needed
left_join(p, ., by = "id") %>% # join new columns with original dataset
select(-id) # remove ID column if not wanted
Once you have this dataset, you could reset the levels of p.race
with factor
if you want the levels to look a certain way.
Upvotes: 1
Reputation: 20811
This is not very elegant, but I think it works. Using loops, especially nested loops, is not very "R" since they are slow but also have side effects like cluttering your workspace.
and you might want to change how this treats p.poc
if race is unspecified because it defaults to 1 which may not be what you want.
So here is one way:
tmp <- lapply(1:nrow(p), function(ii) {
## this checks for columns that aren't blank or NA, takes the colname
## and strips off the prefix
tmp <- gsub('p.race_', '', names(p)[which(p[ii, -1] != '' & !is.na(p[ii, -1])) + 1])
## some special cases for > 1 race and blanks and p.poc
tmp <- ifelse(length(tmp) > 1, 'Two or more', tmp)
tmp[is.na(tmp)] <- 'Not specified'
tmp <- ifelse(p[ii, 1] %in% 'Yes', 'Hispanic or Latino', tmp)
p.poc <- (!grepl('white', tmp)) * 1
return(list(p.race = tmp, p.poc = p.poc))
})
head(do.call(rbind, tmp), 20)
# p.race p.poc
# [1,] "white" 0
# [2,] "white" 0
# [3,] "white" 0
# [4,] "white" 0
# [5,] "white" 0
# [6,] "white" 0
# [7,] "white" 0
# [8,] "white" 0
# [9,] "asian" 1
# [10,] "white" 0
# [11,] "other" 1
# [12,] "white" 0
# [13,] "white" 0
# [14,] "white" 0
# [15,] "Hispanic or Latino" 1
# [16,] "white" 0
# [17,] "white" 0
# [18,] "white" 0
# [19,] "white" 0
# [20,] "white" 0
## and combine back to the data frame
p <- cbind(p, do.call(rbind, tmp))
data:
p <- structure(list(p.hispanic = structure(c(2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 2L,
2L, 2L, 2L, 2L, 3L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 3L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("", "No", "Yes"
), class = "factor"), p.race_white = structure(c(2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 1L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 2L, 2L, 2L,
1L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 2L, 2L,
2L, 1L, 2L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 2L, 2L), .Label = c("",
"White, European, Middle Eastern, or Caucasian"), class = "factor"),
p.race_black = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L,
1L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("",
"Black, African-American, or African"), class = "factor"),
p.race_asian = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 2L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L), .Label = c("",
"Asian or Asian-American"), class = "factor"), p.race_aian = structure(c(1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L,
1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L), .Label = c("", "American Indian or Alaskan Native"
), class = "factor"), p.race_nhpi = c(NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
p.race_other = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L,
1L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("",
"Other (please specify)"), class = "factor")), .Names = c("p.hispanic",
"p.race_white", "p.race_black", "p.race_asian", "p.race_aian",
"p.race_nhpi", "p.race_other"), class = "data.frame", row.names = c(NA,
-79L))
Upvotes: 2