清理李克特量表数据:除了一些不相关的字符串外,如何测试数据是否连续?

Cleaning up likert scale data: How to test whether data is consecutive in addition to some unrelated strings?

我需要清理用李克特量表收集的数据。这意味着我的数据中的观察来自那些从有序量表中选择一个选项的人,例如“在 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

我的任务是测试数据是否确实是李克特量表,这意味着 (1) 值是整数,并且 (2) 如果我们总结唯一值,它们是连续。

  1. 测试是否都是整数可以通过
  2. 来完成
all((df_a$response - round(df_a$response)) == 0) ## 

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

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

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

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

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

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


示例 1 -- 测试“李克特量表”应该 return 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)

示例 2 -- 测试“李克特量表”应该 return FALSE

以下数据中,数字不连续

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

示例 3 -- 测试“李克特量表”应该 return FALSE

以下数据中,“附加字符串”占数据的50%以上,数据核心不太可能是李克特量表

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")

示例 4 -- 测试“李克特量表”应该 return FALSE

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

set.seed(19)
vec_example_4 <- sample(c(1:30, additional_strings), 1000, replace = T) 
barplot(prop.table(table(vec_example_4)), main = "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

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