Skip to Content
Course content

150: Building a Survey Data Analysis Tool

Click on the "Edit" button in the top corner of the screen to edit your slide content.

By the time you get to lesson 150, you've likely realized that real-world data is rarely clean. When you're building a tool to analyze survey data—like a customer satisfaction survey for a coffee chain—you aren't just running a few mean() functions. You're fighting with inconsistent strings, missing values, and the need to turn "Strongly Agree" into a number that R can actually calculate. I've built a dozen of these tools, and the secret is spending 80% of your time on the data transformation pipeline before you even touch a plot.

How do I turn text-based Likert scales into numbers without writing a hundred if-statements?

If you have columns like "Very Dissatisfied" through "Very Satisfied," don't use a massive case_when or a series of if blocks. It's tedious and prone to typos. The professional way to do this is with a named vector. It acts like a lookup table. I usually define the scale once at the top of my script so I can change the weighting later if the client decides "Neutral" should be a 0 instead of a 3.

# Our mapping vector
likert_map <- c("Very Dissatisfied" = 1, "Dissatisfied" = 2, 
                  "Neutral" = 3, "Satisfied" = 4, "Very Satisfied" = 5)

# Apply it across multiple columns using mutate and across
survey_data <- survey_data %>%
  mutate(across(c(coffee_quality, service_speed, store_cleanliness), 
                ~ likert_map[.x]))

The across() function is your best friend here. Instead of repeating the logic for every column, you just tell R: "Find these three columns and swap the text for the corresponding value in my map."

What's the best way to handle the "messy" open-ended comments?

Survey tools always have that one open-ended "Any other feedback?" box. You can't average a sentence, but you can flag keywords. I usually build a simple "sentiment flag" system. Rather than diving into complex Natural Language Processing (NLP) libraries immediately, start by searching for high-signal words using stringr. It's faster to implement and often just as effective for a first-pass analysis.

library(stringr)

survey_data <- survey_data %>%
  mutate(complaint_flag = str_detect(comments, regex("slow|cold|rude|expensive", ignore_case = TRUE)),
         praise_flag = str_detect(comments, regex("amazing|fast|friendly|love", ignore_case = TRUE)))

Now you have boolean columns. You can quickly see if there's a correlation between a low "service_speed" score and the "complaint_flag." If a customer gave a 2 but didn't mention "slow" in their comments, you know the issue was something else entirely.

How can I generate a summary table for all questions at once instead of one by one?

This is where most people get stuck. They write a separate summary block for every survey question. If your survey has 50 questions, your script becomes a nightmare. The trick is to pivot your data from "wide" to "long" format. Once the data is long, you can group by the question name and calculate everything in one shot.

library(tidyr)

summary_report <- survey_data %>%
  select(customer_id, coffee_quality, service_speed, store_cleanliness) %>%
  pivot_longer(cols = -customer_id, names_to = "question", values_to = "score") %>%
  group_by(question) %>%
  summarise(
    avg_score = mean(score, na.rm = TRUE),
    std_dev = sd(score, na.rm = TRUE),
    response_count = n()
  )

I love this approach because adding a new question to your survey doesn't require adding new code to your analysis; you just add the column name to the select() call, and the rest of the pipeline handles it automatically.




📋 Practical Task

Exercise: Building a Remote Work Satisfaction Aggregator

You have been handed a raw dataset from a company's "Remote Work Experience" survey. The data is messy and needs to be processed into a clean summary report.

The Dataset: Create a data frame called remote_survey with the following columns:

  • emp_id: 1 to 5
  • work_life_balance: (Values: "Poor", "Fair", "Good", "Excellent")
  • tech_support: (Values: "Poor", "Fair", "Good", "Excellent")
  • feedback: (Short strings like "I love my home office", "VPN is too slow", "Management is great", "Too many meetings", "Everything is fine")

Your Task:

  1. Create a named vector to map the quality levels ("Poor" through "Excellent") to numbers 1 through 4.
  2. Use mutate(across(...)) to convert both the work_life_balance and tech_support columns to numeric values.
  3. Create a new column called tech_issue that is TRUE if the feedback column contains the word "VPN" or "slow", and FALSE otherwise.
  4. Pivot the numeric columns into a long format and calculate the average score for each category.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.