清理likert scale数据:除了一些不相关的字符串,如何测试数据是否连续?

问题描述

我需要清理使用李克特量表收集的数据。这意味着我的数据中的观察来自那些从序数表中选择一个选项的人,例如“在 1-5 的范围内,其中 1 表示糟糕,5 表示很棒,您如何评价您对茄子的喜欢程度?"

因此,典型的数据集看起来像

library(tibble)

set.seed(123)
df_a <- 
  tibble(name = c("clara","john","michelle","dan",'timothy',"cindy","george","monica","david","rebecca"),response = sample(1:5,10,replace = TRUE))

   name     response
   <chr>       <int>
 1 clara           3
 2 john            3
 3 michelle        2
 4 dan             2
 5 timothy         3
 6 cindy           5
 7 george          4
 8 monica          1
 9 david           2
10 rebecca         3

我的任务是测试数据是否确实是likert scale,这意味着(1)值是整数,以及(2)如果我们总结了唯一值,它们是连续的。

  1. 测试是否都是整数可以通过
all((df_a$response - round(df_a$response)) == 0) ## https://stackoverflow.com/a/10114038/6105259

[1] TRUE
  1. 测试唯一值是否连续 [实际上我不知道该怎么做,但我的问题还不止于此]。

我真正的问题是李克特量表可能有不同的变化,并且其他字符串可能会显示在数据中,从而增加噪音。

  • 有效的李克特量表可以跨越不同的范围,例如 1-5、0-3 或 1-10 等。

  • 很多时候会出现附加字符串,例如“不相关”、“我不知道”、“我不这么认为”、“不适用于我”、等等。我无法预测数据中会出现哪些额外的字符串(如果有的话)。

在这种情况下,我需要检测我的数据是否本质上可能来自“李克特量表”。

决定数据的标准李克特量表:

  1. 数值是整数。
  2. 当我们取唯一值时,它们是连续的(从某种意义上说,sort(unique(df_a$response)) 返回 1 2 3 4 5。如果它返回了 1 3 4 5,那么它将不符合“连续性”标准)
  3. 范围内的最小值是 01
  4. 最大值是 10
  5. 不是数字的噪声字符串(例如“我不知道”、“abcd34”、“不相关”)占数据的不到 50%

以下是 4 个示例,用于演示可能的数据类型以及我在测试它们是否“likert”时应该发生的情况
在示例中,我使用 stringi::stri_rand_strings 来模拟“噪音”字符串(例如,“我不知道”、“不相关”以及我上面给出的其他示例)


示例 1 -- 对“is Likert 量表”的测试应返回 TRUE

library(stringi)

set.seed(19)
val_begin <- sample(0:1,1)
val_end <- sample(3:10,1)
my_seq <- seq(from = val_begin,to = val_end)
additional_strings <- stri_rand_strings(n = 2,length = 5,pattern = "[A-Za-z0-9]")

vec_example_1 <- sample(c(my_seq,additional_strings),size = 100,replace = TRUE) 
barplot(prop.table(table(vec_example_1)),main = "vec example 1)

vec_example_1

示例 2 -- 测试“is Likert 量表”应返回 FALSE

以下数据中,数字不连续

set.seed(19)
my_seq_2 <- sort(c(seq(0,4),seq(7,9)))
additional_strings_2 <- stri_rand_strings(n = 2,pattern = "[A-Za-z0-9]")
vec_example_2 <- sample(c(my_seq_2,additional_strings_2),replace = TRUE) 
barplot(prop.table(table(vec_example_2)),main = "vec example 2)

vec_example_2

示例 3 -- 对“is Likert 量表”的测试应返回 FALSE

以下数据中,“附加字符串”占数据的50%以上,数据的核心不太可能是likert scale

set.seed(19)
vec_example_3 <- sample(c(rep(additional_strings,70),sample(my_seq,30,replace = T))) 
barplot(prop.table(table(vec_example_3)),main = "vec example 3")

vec_example_3

示例 4 -- 测试“is Likert 量表”应返回 FALSE

只是随机数字和字符串,没有理由相信这是一个likert量表,即使它恰好是唯一且连续的,但1-> 30根本不可能是likert。

set.seed(19)
vec_example_4 <- sample(c(1:30,1000,replace = T) 
barplot(prop.table(table(vec_example_4)),main = "vec example 4")

vec_example_4


我在问什么

我认为一个完整的解决方案会很长,所以也许这里的人要求太多了。因此,即使只是提示、一般方法或如何解决此问题的想法,我也会很高兴。

解决方法

您可以编写一个函数来确定向量是否符合我们正在寻找的规则。

is_likert <- function(x) {
  only_numbers <- sort(as.numeric(unique(grep('^\\d+$',x,value = TRUE))))
  all_integers <- all(only_numbers %% 1 == 0)
  are_consecutive <- all(diff(only_numbers) == 1)
  ratio_of_numbers <- mean(grepl('^\\d+$',x))
  max_num <- max(only_numbers)
  min_num <- min(only_numbers)

  all_integers && are_consecutive && ratio_of_numbers > 0.5 && 
  max_num <= 10 && min_num <= 1
}

is_likert(vec_example_1)
#[1] TRUE
is_likert(vec_example_2)
#[1] FALSE
is_likert(vec_example_3)
#[1] FALSE
is_likert(vec_example_4)
#[1] FALSE

我希望变量名足够清楚,以展示它们在做什么。