One-hot encoding a text string

Viewed 234

I have a column which contains a mixed string of characters, I've created columns to represent each one of the unique characters in the string. I need to encode the columns with a [1,0] if any of the characters in the string matches one of these columns.

library(data.table)
d = data.table(string = c("P_P_F_", "U_F_/", "-_P_B"),
               P = c(1,  0, 1),
               F = c(1, 1, 0),
               U = c(0, 1, 0),
               B = c(0, 0, 1))

In the example above string has the characters I need matching to the corresponding columns. The first string has a P and F so I have a 1 in those columns and a 0 in the rest. The characters within the string are always separated by an underscore and has a maximum length of 7.

The data set is quite large so I would prefer a data.table solution is possible.

3 Answers

We can use mtabulate after splitting the string

library(qdapTools)
cbind(d, mtabulate(strsplit(d$string, "[_/-]")))

data

d <- data.table(string = c("P_P_F_", "U_F_/", "-_P_B"))

Remove leading and lagging punctuations so the string is clean with only one separator between each character and then use cSplit_e which uses data.table internally.

library(data.table)
d = data.table(string = c("P_P_F_", "U_F_/", "-_P_B"))

d$string <- trimws(d$string, whitespace = '[[:punct:]]')
splitstackshape::cSplit_e(d, 'string', sep = '_', type = 'character', fill = 0)

#   string string_B string_F string_P string_U
#1:  P_P_F        0        1        1        0
#2:    U_F        0        1        0        1
#3:    P_B        1        0        1        0

A data.table option

d[
  ,
  cbind(
    string,
    as.data.table(
      +(t(
        table(
          stack(
            setNames(
              Map(Filter, list(nchar), strsplit(string, "[_/-]")),
              seq_along(string)
            )
          )
        )
      ) > 0)
    )
  )
]

gives

   string B F P U
1: P_P_F_ 0 1 1 0
2:  U_F_/ 0 1 0 1
3:  -_P_B 1 0 1 0
Related