Day 2 · 14:00 · 105 min

Qualitative visualisation

Voice of customer, without the word-cloud theatre

Day 2 · 14:00

Complaints, exit interviews and app-store reviews are data. They are just not rectangular yet. Tokenise them, remove the theatre, and you can put voice-of-customer on the same page as NPS.

You will leave able to

  • Tokenise free text to one-word-per-row (tidytext).
  • Remove stop-words and a custom confidential list.
  • Chart the content words a CHRO or CMO can act on — not a word cloud.

The original workshop used a corpus about a city. You will use 180 retail-bank complaint tickets — the sort of extract a CX team emails on a Friday. The temptation is a word cloud. Word clouds are decoration. EXCO needs ranked content words, split by channel, with the confidential tokens already gone.

Download voc-complaints.csv· ticket_id, channel, date, comment

One token per row

Julia Silge and David Robinson’s tidy text format is the same contract as yesterday: each observation (here, a word) is a row. unnest_tokens() splits a comment, drops punctuation, and lowercases in one step.

R
library(tidyverse)
library(tidytext)
voc <- read_csv("voc-complaints.csv")
tokens <- voc %>%
unnest_tokens(word, comment) %>%
count(word, sort = TRUE)
head(tokens, 10)

The top of that list will be *the, a, to, my*. That is not insight. It is English.

Stop-words — and your own

R
data("stop_words")
confidential <- tibble(word = c(
"northridge", "bvn", "account", "nuban"
))
numbers <- tokens %>%
filter(str_detect(word, "^[0-9]+$"))
clean <- tokens %>%
anti_join(stop_words, by = "word") %>%
anti_join(confidential, by = "word") %>%
anti_join(numbers, by = "word") %>%
filter(nchar(word) > 2)
clean %>% slice_head(n = 10)
Most frequent content words in 180 retail-bank complaint tickets after stop-word removal. 'Resolved' is the only unambiguously positive token in the top ten.

After cleaning, the list starts to look like an operating agenda: app, branch, transfer, charges, agent, queue. ‘Resolved’ appearing at all is the only unambiguously positive token in the top ten — and it is a process word, not a brand word.

Split by channel, or you will mislead

R
voc %>%
unnest_tokens(word, comment) %>%
anti_join(stop_words, by = "word") %>%
filter(nchar(word) > 2) %>%
count(channel, word, sort = TRUE) %>%
group_by(channel) %>%
slice_head(n = 5)

A national cloud would have mixed ‘queue’ (branch) with ‘ussd’ (feature phone) and ‘app’ (mobile). Those are three different owners in the operating model. The chart has to respect the org chart.

Exercise 2.2

A CHRO version

Imagine these comments are exit-interview notes instead of bank tickets. Which stop-words would you add? Draft a 6-line pipeline that produces the top 8 content words excluding the name of the firm.

  • Add the employer name, ‘manager’, and any product code-names to confidential.
  • CHRO audiences prefer a bar of counts to a cloud. Always.