Тело цикла в tableFor
рассчитывает, в какую ячейку таблицы попадает каждая из журнальных записей. Она смотрит, содержит ли запись нужное событие, и связано ли оно с обращением в белку. Затем цикл увеличивает на единицу элемент массива, соответствующий нужной ячейке.
Теперь у нас есть все инструменты для подсчёта корреляций. Осталось только подсчитать корреляции для каждого из событий, и посмотреть, не выдаётся ли что из списка. Но как хранить эти корреляции?
Объекты как карты (map)
Один из способов – хранить корреляции в массиве, используя объекты со свойствами name
и value
. Однако поиск корреляций в массиве будет довольно громоздким: нужно будет пройтись по всему массиву, чтобы найти объект с нужным именем. Можно было бы обернуть этот процесс в функцию, но код пришлось бы писать всё равно, и компьютер выполнял бы больше работы, чем необходимо.
Способ лучше – использовать свойства объектов с именами событий. Мы можем использовать квадратные скобки для создания и чтения свойств и оператор in
для проверки существования свойства.
var map = {};
function storePhi(event, phi) {
map[event] = phi;
}
storePhi("пицца", 0.069);
storePhi("тронул дерево", -0.081);
console.log("пицца" in map);
// → true
console.log(map["тронул дерево"]);
// → -0.081
Карта (map) – способ связать значения из одной области (в данном случае – названия событий) со значениями в другой (в нашем случае – коэффициенты ϕ).
С таким использованием объектов есть пара проблем – мы обсудим их в главе 6, но пока волноваться не будем.
Что, если нам надо собрать все события, для которых сохранены коэффициенты? Они не создают предсказуемую последовательность, как было бы в массиве, поэтому цикл for
использовать не получится. JavaScript предлагает конструкцию цикла специально для обхода всех свойств объекта. Она похожа на цикл for
, но использует команду in
.
for (var event in map)
console.log("Корреляция для '" + event
"' получается " + map[event]);
// → Корреляция для 'пицца' получается 0.069
// → Корреляция для 'тронул дерево' получается -0.081
Итоговый анализ
Чтобы найти все типы событий, представленных в наборе данных, мы обрабатываем каждое вхождение по очереди, и затем создаём цикл по всем событиям вхождения. Мы храним объект phis
, в котором содержатся корреляционные коэффициенты для всех типов событий, которые мы уже нашли. Если мы встречаем новый тип, которого ещё не было в phis
, мы подсчитываем его корреляцию и добавляем её в объект.
function gatherCorrelations(journal) {
var phis = {};
for (var entry = 0; entry < journal.length; entry++) {
var events = journal[entry].events;
for (var i = 0; i < events.length; i++) {
var event = events[i];
if (!(event in phis))
phis[event] = phi(tableFor(event, journal));
}
}
return phis;
}
var correlations = gatherCorrelations(JOURNAL);
console.log(correlations.пицца);
// → 0.068599434
Смотрим, что получилось:
for (var event in correlations)
console.log(event + ": " + correlations[event]);
// → морковка: 0.0140970969
// → упражнения: 0.0685994341
// → выходной: 0.1371988681
// → хлеб: -0.0757554019
// → пудинг: -0.0648203724
// и так далее...
Большинство корреляций лежат близко к нулю. Морковки, хлеб и пудинг, очевидно, не связаны с обращением в белку. Но оно вроде бы более часто происходит на выходных. Давайте отфильтруем результаты, чтобы выводить только корреляции больше 0,1 или меньше -0,1
for (var event in correlations) {
var correlation = correlations[event];
if (correlation > 0.1 || correlation < -0.1)
console.log(event + ": " + correlation);
}
// → выходной: 0.1371988681
// → чистил зубы: -0.3805211953
// → конфета: 0.1296407447
// → работа: -0.1371988681
// → спагетти: 0.2425356250
// → читал: 0.1106828054
// → арахис: 0.5902679812
Ага! У двух факторов корреляции заметно больше остальных. Арахис сильно влияет на вероятность превращения в белку, тогда как чистка зубов наоборот, препятствует этому.
Интересно. Попробуем вот что: