Splitting values in different columns in R

Viewed 77

One of the column in my dataset contains values like

utm_source=google&utm_medium=cpc&utm_campaign=1234567&utm_term=brand%20&utm_content=Brand&gclid=ERtyuiipotf_YTj

How should I split this in different columns with its values in R?

utm_source utm_medium  utm_campaign utm_brand  utm_content
  google      cpc          1234567   brand%20     Brand

dput(column) gives below output

structure(list("null", "gclid=ertyyhglkdl-kjkY", 
    "utm_source=google&utm_medium=cpc&utm_campaign=1234556&utm_term=brand%20shirts&utm_content=Brand&gclid=jhajsgjdgd_ajs", 
    "utm_source=google&utm_medium=cpc&utm_campaign=1674814043&utm_term=brand%20shirts&utm_content=Brand&gclid=KvgMsEAAYASAAEgLq6vD_BwE", 
    "null", "null", "null", "null", "null", "null", "null", "null", 
    "null", "null", "utm_source=fb&utm_medium=ctw&utm_campaign=Shirt_rem&utm_content=CasciaShirt"), class = c("extracted", 
"list"))
2 Answers

With the OP's updated example as a list, we loop over the list, if the elements are not "null", then create a tibble, split the column at & with separate_rows and then split that column into multiple columns (separate), create a tibble from the named vector (deframe) with as_tibble_row)

library(dplyr)
library(tidyr)
library(tibble)
library(purrr)
map_dfr(lst1, ~ if(.x != "null") tibble(col1 = .x) %>% 
             separate_rows(col1, sep="&") %>% 
             separate(col1, into = c('col1', 'col2'), sep="\\=") %>%
             deframe %>% 
             as_tibble_row())

-output

# A tibble: 4 x 6
#  gclid                    utm_source utm_medium utm_campaign utm_term       utm_content
#  <chr>                    <chr>      <chr>      <chr>        <chr>          <chr>      
#1 ertyyhglkdl-kjkY         <NA>       <NA>       <NA>         <NA>           <NA>       
#2 jhajsgjdgd_ajs           google     cpc        1234556      brand%20shirts Brand      
#3 KvgMsEAAYASAAEgLq6vD_BwE google     cpc        1674814043   brand%20shirts Brand      
#4 <NA>                     fb         ctw        Shirt_rem    <NA>           CasciaShirt

Or instead of doing this in a loop, we can convert the list to a column in data.frame, do this once and pivot to wide format

library(data.table)
keep(lst1, ~ .x != "null") %>%
     flatten_chr %>% 
     tibble(col1 = .) %>%
     mutate(rn = row_number()) %>% 
     separate_rows(col1, sep='&') %>% 
     separate(col1, into = c('col1', 'col2'), sep="\\=") %>%
     pivot_wider(names_from = col1, values_from = col2) %>% 
     select(-rn)
# A tibble: 4 x 6
#  gclid                    utm_source utm_medium utm_campaign utm_term       utm_content
#  <chr>                    <chr>      <chr>      <chr>        <chr>          <chr>      
#1 ertyyhglkdl-kjkY         <NA>       <NA>       <NA>         <NA>           <NA>       
#2 jhajsgjdgd_ajs           google     cpc        1234556      brand%20shirts Brand      
#3 KvgMsEAAYASAAEgLq6vD_BwE google     cpc        1674814043   brand%20shirts Brand      
#4 <NA>                     fb         ctw        Shirt_rem    <NA>           CasciaShirt

data

lst1 <- structure(list("null", "gclid=ertyyhglkdl-kjkY", "utm_source=google&utm_medium=cpc&utm_campaign=1234556&utm_term=brand%20shirts&utm_content=Brand&gclid=jhajsgjdgd_ajs", 
    "utm_source=google&utm_medium=cpc&utm_campaign=1674814043&utm_term=brand%20shirts&utm_content=Brand&gclid=KvgMsEAAYASAAEgLq6vD_BwE", 
    "null", "null", "null", "null", "null", "null", "null", "null", 
    "null", "null", "utm_source=fb&utm_medium=ctw&utm_campaign=Shirt_rem&utm_content=CasciaShirt"), class = c("extracted", 
"list"))

I am not sure if this is the expected output. Below might be a base R option for your goal

Reduce(
  function(...) merge(..., all = TRUE),
  lapply(
    column,
    function(x) {
      u <- unlist(strsplit(x, "&"))
      setNames(data.frame(as.list(gsub(".*=", "", u))), gsub("=.*", "", u))
    }
  )
)

which gives

  utm_source utm_medium utm_campaign utm_content null                    gclid
1         fb        ctw    Shirt_rem CasciaShirt <NA>                     <NA>
2     google        cpc      1234556       Brand <NA>           jhajsgjdgd_ajs
3     google        cpc   1674814043       Brand <NA> KvgMsEAAYASAAEgLq6vD_BwE
4       <NA>       <NA>         <NA>        <NA> null         ertyyhglkdl-kjkY
        utm_term
1           <NA>
2 brand%20shirts
3 brand%20shirts
4           <NA>

Update

If you want to preserve all the data even if it is null, you can try the code below

Reduce(
  function(x, y) {
    if (all(is.na(x)) | all(is.na(y))) {
      return(rbind(x, y))
    }
    dplyr::full_join(x, y)
  },
  lapply(
    column,
    function(x) {
      if (x == "null") {
        return(NA)
      }
      u <- unlist(strsplit(x, "&"))
      setNames(data.frame(as.list(gsub(".*=", "", u))), gsub("=.*", "", u))
    }
  )
)

which gives

                      gclid utm_source utm_medium utm_campaign       utm_term
1                      <NA>       <NA>       <NA>         <NA>           <NA>
2          ertyyhglkdl-kjkY       <NA>       <NA>         <NA>           <NA>
3            jhajsgjdgd_ajs     google        cpc      1234556 brand%20shirts
4  KvgMsEAAYASAAEgLq6vD_BwE     google        cpc   1674814043 brand%20shirts
5                      <NA>       <NA>       <NA>         <NA>           <NA>
6                      <NA>       <NA>       <NA>         <NA>           <NA>
7                      <NA>       <NA>       <NA>         <NA>           <NA>
8                      <NA>       <NA>       <NA>         <NA>           <NA>
9                      <NA>       <NA>       <NA>         <NA>           <NA>
10                     <NA>       <NA>       <NA>         <NA>           <NA>
11                     <NA>       <NA>       <NA>         <NA>           <NA>
12                     <NA>       <NA>       <NA>         <NA>           <NA>
13                     <NA>       <NA>       <NA>         <NA>           <NA>
14                     <NA>       <NA>       <NA>         <NA>           <NA>
15                     <NA>         fb        ctw    Shirt_rem           <NA>
   utm_content
1         <NA>
2         <NA>
3        Brand
4        Brand
5         <NA>
6         <NA>
7         <NA>
8         <NA>
9         <NA>
10        <NA>
11        <NA>
12        <NA>
13        <NA>
14        <NA>
15 CasciaShirt
Related