В этой главе мы познакомимся со вторым «атлетом» нашей метафоры – характеристиками студента. Мы помним, что чем сильнее студент, тем выше его шансы на верное решение. Но как отследить и оценить эту силу? Давайте разбираться.
По традиции начнем с самого простого случая: студент выполняет задания, и у него только одна попытка на задание. В таком случае можно считать, что у него есть некое свойство – сила, определяющая успех в решении. Здесь я намеренно избегаю использования слов «знание», «умение», «навык», знакомых нам по советской педагогической традиции; слова «компетенция», вошедшего в обиход в первую декаду 2000-х; слова «скилл», ставшего модным уже в современной индустрии EdTech, или слов «способность» и «подготовленность» из словаря психометриков. Мне хочется, чтобы приводимые в книге метрики остались в равной степени удаленными и приближенными к любой педагогической школе и традиции; кроме того, я стремлюсь воздерживаться от терминологических дебатов и сфокусироваться на метриках и их практической пользе. Под словом «сила» я понимаю не новое определение, а исключительно свойство студента, которое обусловливает его успех в выполнении заданий, в соответствии с нашей метафорой про борцов.
Итак, как выразить эту силу? Элементарным способом будет расчет доли верных ответов. Обратите внимание: доля верных ответов может выразить как характеристику задания (в чем мы убедились в предыдущей главе), так и свойство студента. Принцип подсчета доли верных ответов для студента аналогичен. Сначала распределяем результаты минимальных учебных действий по корзинкам, каждая из которых соответствует одному студенту. Затем в каждой корзинке считаем долю верных ответов (другими словами, делим количество верных ответов на сумму верных и неверных ответов, или, иначе, на общее число заданий, с которыми студент взаимодействовал). Таким образом, сила студента выражается через долю верных ответов: чем она больше, тем более сильным можно считать студента.
Для иллюстрации вернемся к простейшему датасету (book_dataset_1.tsv), в котором содержатся необходимые нам переменные student_id, task_id, is_correct, отражающие результат выполнения (is_correct) студентами (student_id) заданий (task_id). Напомню, что сначала следует подгрузить данные с помощью команды df <– read.table("book_dataset_1.tsv", header = TRUE, quote = "", sep = "\t"). Кроме того, с помощью команды library(dplyr) обратимся к уже установленному ранее пакету dplyr.
Для расчета доли верных ответов по студентам воспользуемся следующим кодом:
Он вам уже знаком по вычислению доли верных ответов к заданиям. Сначала с помощью команды group_by(student_id) распределяем ответы по корзинкам, каждая из которых соответствует студенту. Затем в каждой корзинке подсчитываем количество верных и неверных ответов, используя команды n_Correct = sum(is_correct == 1) и n_Incorrect = sum(is_correct == 0) соответственно. И наконец, подсчитываем долю верных ответов, применив команду p_j = round(n_Correct / (n_Correct + n_Incorrect), 2). Результирующая таблица с интересующей нас переменной доли верных ответов называется p_j (индексом j в психометрике принято обозначать студента). Она содержит два столбца: идентификатор студента и соответствующее этому студенту значение доли верных ответов.
Теперь рассмотрим иллюстрирующую таблицу (табл. 13).
Таблица 13. Доли верных ответов для четырех студентов
Мы видим, что первый студент с идентификатором s001 справился с 97 % заданий; второй – с 80 % заданий; третий и четвертый – с 56 и 23 % заданий соответственно. Но какими будут референсные значения?
Границы референсных значений студента совпадают с границами референсных значений заданий (см. главу 4). Это стало важным открытием в моей практике. Другими словами, для студентов оптимальными результатами считаются те, при которых доля верных решений находится в диапазоне 75–95 %. Такие студенты достигают лучших учебных результатов: лучше сдают проектные работы и с наибольшей вероятностью завершают обучение. Студенты с долей верных решений в интервале 50–75 % находятся в субоптимальной категории. Тех, у кого доля верных решений ниже 50 %, мы считаем испытывающими фрустрирующий учебный опыт, а студентов с долей верных решений выше 95 % – скорее, скучающими.
Таким образом, студент s001 относится к категории скучающих, студент s002 – к категории студентов с оптимальными результатами; студенты s003 и s004 – к субоптимальной и категории фрустрированных студентов соответственно.
Мини-практикум. В какой категории с точки зрения доли верных ответов оказался студент
1299da27aedcad06fa1c923f1ec584c7?
Правильный ответ: в субоптимальной со значением доли верных ответов 0,62[21].
Однако эта метрика показывает нам общую характеристику студента на основе всех накопленных данных. В практических целях может быть интересно узнать, есть ли различия, например, между уроками или темами, которые студент изучал. В таком случае следует использовать модифицированный подход.
В этом случае мы собираем корзинки не по отдельным студентам, а по студентам и урокам: в одну корзинку попадают результаты выполнения конкретным студентом заданий из конкретного урока. Рассмотрим этот подход подробнее и с вычислениями.
Для расчета нам понадобятся переменные с идентификаторами уроков, тем и курсов. Напомню, в нашем текущем датасете они есть, в чем можно убедиться с помощью команды head(as.data.frame(df)). После воспользуемся следующим кодом для вычислений:
Команда group_by(student_id, lesson_id) формирует нужные нам корзинки в разрезе студент – урок. Дальнейшие вычисления вам уже знакомы. В результате получим таблицу под названием p_jl, где l – урок. Она состоит из трех столбцов: идентификатор студента, идентификатор урока и соответствующая этой паре доля верных решений (переменная p_jl). Таким образом, мы сможем сравнивать значения p_jl от урока к уроку (или от темы к теме, или любой другой агрегирующей сущности, которая нас интересует).
Интерпретация значений переменной p_jl аналогична описанной. Студентов в каждом уроке можно соотнести с категорией: оптимальные, фрустрированные, субоптимальные или скучающие. Интерпретируя эти значения, важно понимать и помнить, что высокие (или низкие) значения доли верных ответов могут говорить не только о том, что студент более (или менее) сильный, но и о том, что задания были менее (или более) трудными.
Мини-практикум. Какой урок оказался для студента
1299da27aedcad06fa1c923f1ec584c7наиболее трудным?
Правильный ответ: урок с идентификатором
87486730, доля верных ответов студента в этом уроке составила 0,17[22].
Теперь по традиции расширим контекст и предположим, что студентам при решении заданий доступны несколько попыток. Как и в ситуации с контентом, можем рассчитать характеристику студента, его силу, самым простым способом – через долю верных ответов по первой попытке. Давайте сделаем это. Вновь обратимся к датасету (book_dataset_2a.tsv из главы 4), в котором взаимодействие студентов с заданиями размечено меткой времени[23]. По уже знакомой нам схеме рассчитаем переменную попытки для этого датасета с помощью команды df <– df %>% group_by(student_id, task_id) %>% arrange(timestamp) %>% mutate(attempt = row_number()). Далее воспользуемся следующим кодом, чтобы рассчитать долю верных ответов по первой попытке для каждого студента нашего учебного продукта:
Логика этого кода вам должна быть известна, но давайте еще раз пройдемся по основным командам. Сначала отбираем только первые попытки filter(attempt == 1), так как нас интересует доля верных ответов студента по первой попытке. Далее формируем корзинки по студентам group_by(student_id) и в каждой считаем число верных n_Correct = sum(is_correct == 1) и неверных ответов n_Incorrect = sum(is_correct == 0) соответственно, чтобы затем применить эти значения в формуле для расчета доли верных ответов в каждой корзинке: p_j1 = round(n_Correct / (n_Correct + n_Incorrect), 2).
Мини-практикум. Какова доля верных ответов по первой попытке студентов с идентификаторами
2c49eb91a8cca06f3842cb76ef17048fи2f5834cdaaacf9e21661b8a9bb87c557? К каким категориям относятся эти студенты?
Правильный ответ: 0,89 (оптимальный) и 0,33 (фрустрированный) соответственно[24].
Выразить силу студента можно также через квартили попыток. Для этого, как мы помним, нужно определить эффективную попытку, затем сформировать корзинки по студентам и упорядоченно расположить все задания, которые решал этот студент, по количеству эффективных попыток от наименьшего к наибольшему. Далее необходимо разделить эти задания на четыре равные группы – квартили и взять пять значений. Первое и последнее значения покажут наименьшее и наибольшее число попыток, затраченное студентом на решение заданий; второе, третье и четвертое – границы по количеству попыток для 25, 50 и 75 % заданий, решенных студентом.
В вычислительном коде этот подход выглядит таким образом. На данных из предыдущего пункта, где уже рассчитана переменная попыток (attempt), отберем эффективные попытки (это вам знакомо)[25] и далее применим следующий код:
В нем группируем данные по корзинкам, относящимся к отдельным студентам. Затем для каждой корзинки вычисляем квартили, как указано ранее.
В результате получим таблицу с названием qa_j, где qa – квартиль (quartile) попыток (attempts); j – общепринятый индекс для обозначения студентов. Таблица содержит идентификатор студента (student_id); минимальное количество попыток, которые потребовались студенту на решение заданий (Min); границы первого, второго и третьего квартилей (Q1, Q2, Q3 соответственно) и максимальное количество попыток, потребовавшихся студенту на решение заданий (Max).
Код вычисляет квартили попыток как накопительную метрику по состоянию «сейчас».
Мини-практикум. Каковы значения квартилей попыток для студента
5214c659eeee27501cf51d0cf2eb6443? Как можно интерпретировать полученные значения?
Правильный ответ: границы квартилей попыток этого студента равны 1, 1, 1, 2 и 34. Над некоторыми задачами ему пришлось потрудиться: максимальное значение использованных попыток – 34. Но число таких задач не превышает четверти от общего числа задач, которые решал студент (так как нижняя граница четвертого квартиля составляет 2 попытки, что нормально)[26].
Эту метрику можно представить и в разрезе отдельных тем. В этом случае код будет выглядеть следующим образом:
Мы видим, что теперь корзинки собираются по студенту и по теме (group_by(student_id, topic_id)). При этом остальная часть этого кода с вычислением собственно квартилей вам уже хорошо знакома.
Кроме того, мы можем рассчитывать оперативное значение, например, для «последних х решенных заданий». Такой подход позволит отслеживать динамику студента без привязки к контентным сущностям типа темы или урока. Попробуем сделать такой расчет:
Обратите внимание: в этом коде появились две новые команды. Первая arrange(desc(timestamp)) упорядочивает эффективные попытки студента по убыванию метки времени. А вторая slice_head(n = 20) отбирает желаемое количество решенных заданий (в данном случае 20). В результате получаем 20 последних решений студента (или меньше, если он еще не решил 20 заданий). Для этих данных рассчитываются квартили попыток. Структура результирующей таблицы останется прежней и уже знакомой вам.
Мини-практикум. Задачи в каких темах вызывали у студента
5214c659eeee27501cf51d0cf2eb6443существенные трудности?
Правильный ответ: отдельные задачи в темах
b56d111eиa87ff039, о чем свидетельствуют максимальные значения используемых студентом попыток при взаимодействии с задачами этих тем – 9 и 34 соответственно[27].
Силу студента в отношении попыток можно выразить и средним значением. Здесь расчет аналогичен расчету для контента. Имея данные по эффективным попыткам, воспользуемся следующим вычислительным кодом:
Итоговая таблица содержит два столбца: с идентификатором студента и соответствующим ему средним значением эффективных попыток.
Для вычисления в разрезе тем или уроков код необходимо слегка изменить, добавив разбиение на более мелкие корзинки «студент – урок»:
Продолжим разбираться с характеристиками студента, но в новых обстоятельствах, когда доступны не только попытки, но и помогающие механики, например подсказки. Как и в случае с контентом, можно рассчитать для студента нагрузку подсказками. Эта метрика отражает, насколько часто при решении заданий он полагается на подсказки.
Как и при вычислении нагрузки подсказками для контента, каждую пару «студент – задание» необходимо пометить дополнительной переменной, фиксирующей факт использования студентом подсказки при решении задания, где 1 – подсказка использовалась, а 0 – подсказка не использовалась. Затем для каждого студента нужно рассчитать долю случаев, в которых подсказка использовалась.
Значение нагрузки подсказками будет находиться в интервале (включительно) от 0, когда студент совсем не использовал подсказок, до 1, когда он применял подсказку при решении каждой задачи. Эта метрика позволяет идентифицировать студентов, которым нужна дополнительная поддержка. Например, если у студента одновременно низкая доля верных ответов и высокая, если не стопроцентная, нагрузка подсказками, ему точно необходима и помощь автоматизированных инструментов, и человеческая поддержка.
Снова обратимся к файлу book_dataset_2b.tsv. Откроем его, вычислим переменную попытки и отберем эффективные попытки[28]. Рассчитать нагрузку подсказками студента нам позволит следующий код:
Он устроен просто. Сначала сгруппируем данные по корзинкам «студент» (student_id). В каждой корзинке вычисляем среднее значение по переменной «использование подсказок» (hint). В результате получим таблицу, где показан фрагмент выгрузки расчетов нагрузки подсказками по студентам (скрин. 4).
Скриншот 4
И снова напомню, что нагрузку студента подсказками можно рассчитывать не только в целом по пройденному материалу, но и для отдельных тем или уроков:
Мини-практикум. Какова нагрузка подсказками в целом и по темам для студента
5214c659eeee27501cf51d0cf2eb6443? Как можно интерпретировать нагрузку в целом, если среднее значение нагрузки по студентам составляет 0,04? Как можно интерпретировать значения нагрузки по темам?
Правильный ответ: нагрузка подсказками для студента равна 0,33, что существенно превышает среднее значение по всем студентам. При этом распределение нагрузки по темам показывает, что студент использовал подсказки только в темах
b56d111eиa87ff039, однако пользовался ими при взаимодействии с половиной задач в каждой теме (нагрузки составляют 0,47 и 0,56 соответственно)[29].
На платформе могут быть доступны и другие помогающие механики. Нагрузка по ним рассчитывается аналогично. Но в таком случае, как и для контента, полезно вычислить еще одну дополнительную метрику – среднюю нагрузку помогающими механиками для студентов.
Основным сценарием практического использования базовых метрик студента является исследование, как учится студент. Это поможет выявить тех, кто испытывает трудности и кому требуется поддержка в виде как дополнительных материалов, так и, возможно, помощи человека. Кто попадет в эту группу? Это студенты, имеющие низкую долю верных решений, использующие большее число попыток и чаще других пользующиеся подсказками. И еще обращаю внимание: задача базовых метрик – сделать взаимодействие студентов и задач видимым, указать на места, требующие более детального рассмотрения.
И снова, как и в случае контента, мы получаем ситуацию, в которой чем сложнее устроено обучение на платформе, тем больше метрик необходимо отслеживать и тем сложнее принимать решения на их основе. Например, может встать вопрос, что делать, если у нас не одна, а несколько попыток решения, но есть необходимость рассчитать силу (долю верно решенных студентом ответов). Считать эту силу по первым попыткам, а потом пытаться качественно интерпретировать результаты с учетом индекса всех попыток? Это сложно и трудоемко. Очевидна необходимость создания единой метрики, интегрирующей весь учебный опыт при этом простой для интерпретации.
Об этой единой метрике мы поговорим в следующих главах книги.