В психологии для исследования когнитивного стиля диапазон эквивалентности применяются различные модификации методики «Свободная сортировка объектов» (Free Sorting Test) Гарднера. В методике обычно используется от 30 до 70 стимулов (понятий). В этой заметке я продеонмстрирую некоторые возможности обработки результатов проведения методики «Свободная сортировка объектов» в R.
Итак, для начала смоделируем результаты проведения методики. Предположим, у нас было 70 стимулов (как в оригинальном варианте, предложенном Гарднером), в исследовании приняли участие 100 человек. Зададим также максимальное число групп, которое могли выделить испытуемые (я взял 20 групп).
n <- 100 # количество испытуемых
k <- 70 # количество стимулов
l <- 3 # минимульное число групп
m <- 20 # максимальное число групп
dataset <- matrix(0, ncol = k, nrow = n)
for (i in 1:n) {
groups <- sample(l:m, size = 1) # число групп, которое выделил испытуемый
sorting <- sample(seq_len(groups), size = k, replace = TRUE) # симмулируем сортировку бъектов
sorting <- paste0("G", sorting) # формируем названия групп
dataset[i, ] <- sorting # заносим строку в сводную таблицу
}
# задаём имена столбцам
colnames(dataset) <- paste0("S", 1:k)
# преобразуем матрицу в таблицу данных
dataset <- as.data.frame(dataset, stringsAsFactors = FALSE)
Для наглядности приведём часть сгенерированных данных:
head(dataset[, 1:10])
#> S1 S2 S3 S4 S5 S6 S7 S8 S9 S10
#> 1 G7 G5 G8 G4 G1 G5 G2 G8 G8 G3
#> 2 G4 G11 G9 G5 G11 G9 G4 G2 G4 G7
#> 3 G6 G3 G8 G1 G2 G8 G2 G1 G8 G6
#> 4 G3 G1 G3 G1 G4 G4 G4 G5 G5 G5
#> 5 G2 G15 G5 G7 G16 G4 G14 G9 G13 G12
#> 6 G10 G9 G1 G13 G11 G11 G4 G6 G14 G6
Как мы видим, столбцы таблицы содержат данные по каждому из стимулов, а строки представляют собой результат группировки — в ячейках представлены условные имена групп (у каждого испытуемого они могут быть произвольные).
После проведения методики оценивают следующие показатели:
При анализе результатов также рассчитывается количество групп, сформированных по категориальным и тематическим основаниям, но я рассматривать их не буду, т.к. для их оценки нужно провести качественных анализ результатов сортировки.
Для расчёта количественных показателей методики для наших данных напишем функцию, которая будет рассчитывать нужные нам параметры:
free_sorting_summary <- function(x) {
if (is.list(x))
x <- unlist(x)
if (is.character(x))
x <- as.factor(x)
# рассчитываем показатели
freqs <- tabulate(x) # количество элементов в каждой группе
res <- c(n.groups = length(freqs), # общее число групп
max.elements = max(freqs), # число элементов в наибольшей группе
n1.groups = sum(freqs == 1)) # число групп с 1 элементом
return(res)
}
Чтобы расчитать показатели для каждого испытуемого, применим эту функцию к каждой строке нашей своодной таблицы данных при помощи функции apply():
summary_results <- as.data.frame(t(apply(dataset, 1, free_sorting_summary)))
Итогвую матрицу пришлось транспонировать, чтобы показатели соответствовали столбцам таблицы, а испытуемые строкам. Итоговая матрица с результатами выглядит следующим образом:
head(summary_results)
#> n.groups max.elements n1.groups
#> 1 11 10 0
#> 2 11 15 0
#> 3 8 15 0
#> 4 5 17 0
#> 5 16 8 0
#> 6 18 7 3
Далее мы можем проводить более детальный анализ полученных результатов: частотный анализ, описательные статистики. Например, построим гистограмму распределения частот количества выделенны групп:
hist(summary_results$n.groups,
main = "Histogram the number of groups",
xlab = "Number of groups")
Теперь рассчитаем описательные статистики по всем показателям методики, например, при помощи функции describe() из пакета psych:
library(psych)
describe(summary_results, skew = FALSE)
#> vars n mean sd median trimmed mad min max range se
#> n.groups 1 100 11.84 5.07 12 11.91 5.93 3 20 17 0.51
#> max.elements 2 100 12.16 5.36 10 11.25 2.97 5 28 23 0.54
#> n1.groups 3 100 0.59 0.95 0 0.40 0.00 0 4 4 0.10
Для того, чтобы определить какие стимулы были объединены в одну группу, построим матрицу, где столбцами и строками будут наши стимулы, а значения будут зависеть от того, были ли объединены стимулы в одну группу или нет. Для решения этой задачи можно использовать функцию outer(), которая применяет заданную функцию ко всем сочетаниям двух векторов или матриц. Чтобы определить принадлежность пары стимулов к одной группе, нам достаочно сравнить названия групп с помощью оператора ==. В итоге у меня получилась такая функция:
group_stimuli <- function(x) {
if (is.list(x))
x <- unlist(x)
m <- outer(x, x, "==") # сравниваем каждый элемент с каждым
mode(m) <- "integer" # преобразуем логичческие значения в числовые
return(m)
}
Теперь попробуем применить эту функцию к данным сортировки. Для этого возьмём данные одного из испытуемых. Ниже приведена только часть вывода, т.к. матрица слишком большая.
group_stimuli(dataset[1, ])[1:10, 1:10]
#> S1 S2 S3 S4 S5 S6 S7 S8 S9 S10
#> S1 1 0 0 0 0 0 0 0 0 0
#> S2 0 1 0 0 0 1 0 0 0 0
#> S3 0 0 1 0 0 0 0 1 1 0
#> S4 0 0 0 1 0 0 0 0 0 0
#> S5 0 0 0 0 1 0 0 0 0 0
#> S6 0 1 0 0 0 1 0 0 0 0
#> S7 0 0 0 0 0 0 1 0 0 0
#> S8 0 0 1 0 0 0 0 1 1 0
#> S9 0 0 1 0 0 0 0 1 1 0
#> S10 0 0 0 0 0 0 0 0 0 1
Как видим, если на пересечении столбца и строки стоит 1, то эти стимулы были объединениы в одну группу, если 0, соответственно, стимулы находились в разных группах.
На основе полученной матрицы, мы можем визуализировать результаты сортировки отдельного испытуемого. Для этого воспользуемся функцией qgraph() из одноимённого пакета.
library(qgraph)
qgraph(group_stimuli(dataset[1,]), layout = "spring")
Ещё один интересный момент, который можно представить с помощью графика — это соотношение категорий, выделенных исследователем и результатов группировки испытуемго. Предположим, что наши стимулы относиллись к 4 разным категориям и мы хотим узнать, как эти категории отразились в результатах испытуемого. Функция qgraph() может принимать именованный список групп, содежращих номера столбцов матрицы, которые относятся к данной группе.
qgraph(group_stimuli(dataset[1,]), layout = "spring",
groups = list(C1 = 1:20, C2 = 21:40, C3 = 41:60, C4 = 61:70),
color = heat.colors(4))
Итак, у нас есть всё, чтобы перейти к анализу групповых результатов. Чтобы получить обобщённые результаты по выборке испытуемых, просуммируем индивидуальные результаты группировки (матрицы совпадения групп стимулов):
# подготавливаем матрицу для заполнения в цикле
grouping_results <- matrix(0, ncol = ncol(dataset), nrow = ncol(dataset),
dimnames = list(colnames(dataset), colnames(dataset)))
for (i in 1:nrow(dataset))
grouping_results <- grouping_results + group_stimuli(dataset[i, ]) # суммируем результаты
diag(grouping_results) <- 0
Полученная матрица позволит увидеть наиболее часто объединяемые стимуллы в данной выборке. Мы можем визуализировать эту матрицу также как мы делали это с результатами одного испытуемого. При этом толщина линии будет отражать частоту объединения соответствующих стимулов в выборке.
qgraph(grouping_results, layout = "spring")
График, прямо скажем, не очень информативный. Для исправления ситуации нам нужно отфильтровать «случаные» связи стимулов. Для начала посмотрим какой диапазон частотк объединения стимулов у нас получился по выблорке:
table(grouping_results)
#> grouping_results
#> 0 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 24
#> 70 8 16 24 46 146 278 382 508 658 578 614 482 360 330 212 102 38 20 20 6 2
Выполнить фильтрацию при построении графика с помощью функции qgraph() можно, указав аргумент minimum.
qgraph(grouping_results, layout = "spring", minimum = 15)
Последним штрихом в нашем обзоре будет визуализация степени близости стимулов по сумманы выборочным данным. Для этого нам нужно инвертить матрицу группировки, которую мы получали при помощи функции group_stimuli(). Сделать это довольно просто: нам нужно просто заменить оператор ==, которую мы передавали в функцию outer(), на его противополжность, т.е. !=. Затем мы повторяем суммирование по всей выборке.
group_stimuli2 <- function(x) {
if (is.list(x))
x <- unlist(x)
m <- outer(x, x, "!=") # сравниваем каждый элемент с каждым
mode(m) <- "integer" # преобразуем логичческие значения в числовые
return(m)
}
grouping_results2 <- matrix(0, ncol = ncol(dataset), nrow = ncol(dataset),
dimnames = list(colnames(dataset), colnames(dataset)))
for (i in 1:nrow(dataset))
grouping_results2 <- grouping_results2 + group_stimuli2(dataset[i, ]) # суммируем результаты
Для визуализации близости стимулов применив метод многомерного шкалирования, чтобы получить координаты стимулов:
grouping_results2 <- cmdscale(grouping_results2)
Теперь нам осталось только построить график.
library(ggplot2)
#>
#> Attaching package: 'ggplot2'
#>
#> The following object is masked from 'package:psych':
#>
#> %+%
ggplot(as.data.frame(grouping_results2), aes(x = V1, y = V2, label = colnames(dataset))) +
geom_point(size = 3) +
geom_text(hjust = -1) +
theme(axis.title = element_blank(),
axis.text = element_blank())