Подготовка

Что сделал:

  • Импортировал данные о пробах участников;
  • Подключил нужные библиотеки;
  • Выгрузил ID’шники испытуемых.
# Бибилотеки
library(tidyverse)
library(plyr)

# Импорт данных
trials_data = dating = read.csv("trials final (updated).csv", sep = ";")

# Выгружаем айдишники
subjects_ids = unique(trials_data$subject_id)

Поиск проблематичных испытуемых

По времени, которое было потраченно на пробы

# Создаём переменую с суммой времени, потраченного на пробы
subjects_goodness = 
  trials_data %>% 
  group_by(subject_id) %>% 
  dplyr::summarise(duration_total = sum(state_duration))

# Создаём переменую с проверкой на отрицательную длительность
subjects_goodness$negative_duration = "-"

for (id in subjects_ids) {
  
  id_data = trials_data %>% 
    filter(subject_id == id)

  n_negative_values = sum(id_data$state_duration < 0)
  
  if (n_negative_values > 0) {
    subjects_goodness[subjects_goodness$subject_id == id, ]$negative_duration = "+"
  }
}

# Считаем Z-score суммарного времени
subjects_neg_dur = subjects_goodness %>% filter(negative_duration == "+")
subjects_goodness = subjects_goodness %>% filter(negative_duration == "-")

subjects_goodness$duration_z = 
  (subjects_goodness$duration_total - 
     mean(subjects_goodness$duration_total)) / sd(subjects_goodness$duration_total)

subjects_goodness = rbind.fill(subjects_neg_dur, subjects_goodness)

# Делаем вывод о подозиртельности по отношению ко времени прохождения проб
subjects_goodness = subjects_goodness %>% 
  mutate(sus_duration = 
           ifelse(
               duration_z < -2 |
               duration_total < 115000 | 
               negative_duration == "+", 
             "+", "-"))

По качеству и количеству вербализаций

# Считаем количество вербализаций (или контрольного задания) и количество скипов
subjects_goodness$verb_num = NA
subjects_goodness$verb_skip_num = NA
subjects_goodness$verb_bad_qual_num = NA

for (id in subjects_ids) {
  
  id_data = trials_data %>% 
    filter(subject_id == id)
  
  # Кол-во вербализаций
  if (id_data$exp_group == "control") {
    
    subjects_goodness[subjects_goodness$subject_id == id, ]$verb_num =
      sum(id_data$state_skipCities == F)
    
  } else {
    
    subjects_goodness[subjects_goodness$subject_id == id, ]$verb_num =
      sum(id_data$state_skipVerb == F)
  }
  
  # Кол-во скипов
  subjects_goodness[subjects_goodness$subject_id == id, ]$verb_skip_num =
    sum(id_data$skip_check == "TRUE" & id_data$state_verbtext %in% c("no verb", "no cities"))
  
  # Кол-во плохих вербализаций
  subjects_goodness[subjects_goodness$subject_id == id, ]$verb_bad_qual_num =
    sum(nchar(id_data$state_verbtext) < 12 &
          id_data$skip_check == "FALSE" &
          (id_data$state_skipCities == F | id_data$state_skipVerb == F))
}

# Считаем проблематичные вербализации: суммируем скипы и плохие вербализации
subjects_goodness = subjects_goodness %>% 
  mutate(verb_problematic_num = verb_bad_qual_num + verb_skip_num) %>% 
  mutate(verb_problematic_share = verb_problematic_num/verb_num)  

# Считаем Z-score количества проблематичных вербализаций
subjects_goodness$verb_problematic_z = 
  (subjects_goodness$verb_problematic_share - 
     mean(subjects_goodness$verb_problematic_share)) / sd(subjects_goodness$verb_problematic_share)

# Делаем вывод о подозиртельности по отношению ко времени прохождения проб
subjects_goodness = subjects_goodness %>% 
  mutate(sus_verb = 
           ifelse(
               verb_problematic_z > 2 |
               verb_problematic_share > 0.45, 
             "+", "-"))

По испольованным эмоциям-состояниям

subjects_goodness$emotions_num = NA
subjects_goodness$emotions_highest_z = NA

for (id in subjects_ids) {

  id_data = trials_data %>% 
    filter(subject_id == id)
  
  # Записываем использованные эмоции-состояния и количество их использований
  id_responses = t(as.data.frame(table(id_data$state_response))) %>% `colnames<-`(.[1, ])
  id_responses = t(as.data.frame(id_responses[-1, ])) %>% `rownames<-`("Frequency")
  
  emotions_frequencies = as.numeric(as.vector(id_responses[1, ]))
  
  # Считаем Z-score количества использваний для каждой эмоции-состояния 
  emotions_z = ((emotions_frequencies - 
     mean(emotions_frequencies)) / sd(emotions_frequencies))
  
  # Ищем наибольший Z-score для эмоций-состояний
  subjects_goodness[subjects_goodness$subject_id == id, ]$emotions_highest_z = max(emotions_z)
  
  # Считаем количество использованных эмоций-состояний
  subjects_goodness[subjects_goodness$subject_id == id, ]$emotions_num = ncol(id_responses)
}

# Считаем Z-score количества использованных эмоций-состояний
subjects_goodness$emotions_num_z = 
  (subjects_goodness$emotions_num - 
     mean(subjects_goodness$emotions_num)) / sd(subjects_goodness$emotions_num)

# Делаем вывод о подозиртельности по отношению к использованным эмоциям-состояниям
subjects_goodness = subjects_goodness %>% 
  mutate(sus_emotions = 
           ifelse(
               emotions_num_z > 2 |
               emotions_highest_z > 2.2 |
               emotions_num < 4,
             "+", "-"))

Суммирование результатов

# Складываем показтели подозрительности по 3 категориям: время прохождения, использованные эмоции-состояния, качество и пропуски вербализаций.
subjects_goodness = subjects_goodness %>% 
  mutate(sus_total_score = 
           ifelse(sus_duration == "+", 1, 0)  + 
           ifelse(sus_verb == "+", 1, 0) + 
           ifelse(sus_emotions == "+", 1, 0))

# Формируем вердикт о подозрительности испытуемого 
subjects_goodness$sus_verdict = 
  ifelse(subjects_goodness$sus_total_score > 0, "+", "-")

Фильтрация проблематичных испытуемых

# Записываем ID'шники проблематичных испытуемых 
ids_problematic = subjects_goodness %>% filter(sus_verdict == "+")
ids_problematic = ids_problematic$subject_id

# Выводим ID'шники проблематичных испытуемых 
paste0("Проблематичные испытуемые: ", paste(ids_problematic, collapse=", "))
## [1] "Проблематичные испытуемые: ikDOPYWoD5_1, ikDOPYWoD5_2, ikDOPYWoD5_3, LnavCGmm47, ymoET7orhO"
# Функция для удобства
'%!in%' <- function(x,y)!('%in%'(x,y))

# Удаляем проблематичных испытуемых из данных
trials_data_filtered = trials_data %>% 
  filter(subject_id %!in% ids_problematic)

# Записываем отфильтрованный файл
write.csv(trials_data_filtered, file = "trials_data_filtered.csv")

 

Итоги

Общий коментарий

По результатам анализа данных пилота стало ясно следующее:

  • Лучше всего проблематичные испытуемые определяются проверочной категорией качества и количества вербализаций — для каждого такого испытуемого (всего их 5) доля проблематичных ответов (скипнутые + некачественные) составила 100%, среди добросовестных испытуемых наивысшая доля составляет 43%;
  • Категория использованных эмоций-состояний тоже позволяет определить проблематичных испытуемых, но не всех: все 3 испытуемых, которые были помечены проблематичными в этой категории, также были помечены проблематичными в категории качества и количества вербализаций;
  • Категория суммарного времени работает аналогично категории эмоций-состояний: 3-ое тех, кто потратил невозможно маленькое количество времени (от 6 до 22 секунд), являются проблематичными и в других категориях. Тем не менее есть 2 других проблематичных испытуемых, которые потратили больше времени, чем один добросовестный испытуемый: 2 минуты 4 секунды и 2 минуты 32 секунды VS 2 минут. Возможно этот испытуемый — выброс, но по выборке пилота этого нельзя сказать наверняка.

Кандидаты на исключение

4 испытуемых:

  • ikDOPYWoD5_1: прошел все пробы за 22 секунды, есть пробы c отрицательной длительностью (возвращался в прошлое, чтобы всё досконально обдумать???), использовал только 1 эмоцию-состояние, отправил 8 пустых вербализаций;
  • ikDOPYWoD5_2: прошел все пробы за 17 секунд, использовал 2 эмоции-состояния (39 раз ‘Очень вежливое’ и 1 раз ‘Очень дружелюбное’), отправил 3 пустые вербализации;
  • ikDOPYWoD5_3: прошел все пробы за 6 секунд, использовал 2 эмоции-состояния (39 раз ‘Очень вежливое’ и 1 раз ‘Дружелюбное’), отправил 2 пустые вербализации;
  • LnavCGmm47: из 5 вербализаций 2 скипнул, 3 отправил пустыми.

Испытуемый, ошибочно помеченный проблематичным

ymoET7orhO: из-за рассинхрона state_verbtext и skip_check (данные по вербализации находятся на разных строчках, а должны на одной) все вербализации считались некачественными. Если убрать рассинхрон, то испытуемый перестанет быть проблематичным.

 

Codebook

Базовая информация

subject_id — ID’шник испытуемого.

Время прохождения проб

4 переменные:

  • duration_total — суммарное время, потраченное на все 40 проб;
  • negative_duration — содержат ли записи о пробах отрицательное значение длительности прохождения;
  • duration_z — Z-score суммарного времени проб; нужен для того, чтобы находить тех, кто потратил заметно меньше времени, чем все остальные испытуемые в выборке;
  • sus_duration — есть ли что-то подозрительное/проблематичное касательно времени проб испытуемого; есть 3 критерия подозрительности/проблематичности: наличие отрицательного времени, Z-score суммарного времени < -2, суммарное время < 1 минуты 55 секунд.

Качество & количество вербализаций

7 переменных:

  • verb_num — количество вербализаций (или аналагов), запрошенных у испытуемого;
  • verb_num_skip — количество вербализаций, которые были скипнуты испытуемым;
  • verb_bad_qual_num — количество вербализаций плохого качества, т.е. вербализаций меньше 12 знаков;
  • verb_problematic_num — количество проблематичных вербализаций (сумма кол-ва скипнутых вербализаций и кол-ва вербализаций плохого качества);
  • verb_problematic_share — доля проблематичных вербализаций от всех запрошенных вербализаций;
  • verb_problematic_z — Z-score суммарного времени проб; нужен для того, чтобы находить тех, чья доля проблематичных вербализаций заметно выше по сравнению со всеми остальными испытуемыми в выборке;
  • sus_verb — есть ли что-то подозрительное/проблематичное касательно вербализаций испытуемого; есть 2 критерия подозрительности/проблематичности: Z-score количества проблематичных вербализаций > 2, доля проблематичных вербализаций от всех запрошенных вербализаций > 0.45.

Использованные эмоции-состояния

4 переменных:

  • emotions_num — количество отличающихся эмоций-состояний, которые использовал испытуемый;
  • emotions_highest_z — наивысший Z-score количества использований какой-то одной эмоции-состояния (в контексте остальных эмоций-состояний); нужен для того, чтобы находить тех, испытуемых, которые использовали какую-то одну эмоции несравнимо чаще, чем все остальные эмоции;
  • emotions_num_z — Z-score количества отличающихся эмоций-состояний, использованных испытуемым; нужен для того, чтобы находить тех, кто использовал заметно меньше эмоций-состояний по сравнению со всеми остальными испытуемыми в выборке;
  • sus_emotions — есть ли что-то подозрительное/проблематичное касательно эмоций-состояний, которые использовались испытуемым; есть 3 критерия подозрительности/проблематичности: Z-score количества использований какой-то одной эмоции-состояния > 2.2, Z-score количества отличающихся эмоций-состояний, использованных испытуемым > 2, количество уникальных эмоций, использованных испытуемым < 4.

Общие индикаторы

2 переменные:

  • sus_verdict — проблематичен ли испытуемый хотя бы в одной проверочной категории из трех (время прохождения, использованные эмоции-состояния, качество и пропуски вербализаций); + значит проблематичен, - значит НЕ проблематичен;
  • sus_total_score — показывает в скольких проверочных категориях проблематичен испытуемый; 0 — НЕ проблематичен ни в одной категории, 3 — проблематичен во всех категориях.