R extract education degree with str_match_all

Viewed 54

I have an R string column containing education information (university + degree). I would like to extract the degree and creating two categorial variables to indicate undergraduate or graduate degree (undergrad.dummy and grad.dummy).

df = data.frame(educ = c("Angelo State University  (BBA, Finance; BBA, Economics;)", "University of Oxford  (MA, Philosophy; MA, Economics;", "Ross School of Business, University of Michigan  (MBA; BBA;)"))

My approach is to create a list of undergrad and graduate degree, like below

undergrad.list = c("BBA", "BA")
grad.list = c("MA", "MBA", "PhD")

What I attempted is to first extract the degree from educ

df$degree = str_match_all(df$educ, "BBA|MS|MBA|BA")

The problem is the result can be a vector, and I'm having difficult time to extract undergrad and grad degree from that for my large dataset. In the end, I'd like to have

df = data.frame(educ = c("Angelo State University  (BBA, Finance; BBA, Economics;)", "University of Oxford  (MA, Philosophy; MA, Economics;", "Ross School of Business, University of Michigan  (MBA; BBA;)"), undergrad.dummy = c(1,0,1), grad.dummy = c(0,1,1))

Hope to get some suggestions to deal with this problem.

2 Answers

Keep the pattern vectors in a list, loop over the list with map (from purrr), paste them into a single string by collapseing with | (OR) use that in pattern within str_detect, returns a logical vector, coerce it to binary (as.integer or +), rename the columns from map_dfc and bind those columns to original dataset

library(dplyr)
library(purrr)
library(stringr)
map_dfc(list(undergrad.list, grad.list), ~
       +(str_detect(df$educ, str_c("\\b(",str_c(.x, collapse="|"), ")\\b")))) %>%
   set_names(c("undergrad.dummy", 'grad.dummy')) %>%
  bind_cols(df, .)

-output

#                                                          educ undergrad.dummy grad.dummy
#1     Angelo State University  (BBA, Finance; BBA, Economics;)               1          0
#2        University of Oxford  (MA, Philosophy; MA, Economics;               0          1
#3 Ross School of Business, University of Michigan  (MBA; BBA;)               1          1
    for (i in 1:nrow(df)) {
      if (grepl("BA", df$educ[i]) == TRUE) {
        df$unddummy[i] <- 1
      } else {
        df$unddummy[i] <- 0
      }
      if (grepl("MBA|MA|Phd", df$educ[i]) == TRUE) {
        df$graddummy[i] <- 1
      } else {
        df$graddummy[i] <- 0
      }
    }

 df
                                                          educ unddummy graddummy
1     Angelo State University  (BBA, Finance; BBA, Economics;)        1         0
2        University of Oxford  (MA, Philosophy; MA, Economics;        0         1
3 Ross School of Business, University of Michigan  (MBA; BBA;)        1         1

This solution checks the content of a cell in df$edu and puts a corresponding value into unddummy and graddummy. Two things to notic: when checking the undergraduates, checking for "BA" is enough, because "BBA" contains "BA". This hints to an important problem and my regex skills are close to nonexistent. This code will also mark a university as "undergraduate" when the name contains BA, for example the "University of BAli". Ill edit once I find the corret way to do it with regex ...

Related