проблема
Функция, которую я написал для расширения длинной таблицы повторяющихся многомерных данных временных рядов для ввода в функции классификатора, по-видимому, приводит к ошибочным результатам даже для простых тестовых данных, но я не могу найти проблему.
фон
Я держу кучу повторных испытаний многомерных временных рядов в длинном формате data.table, подобном этому, для скорости и простоты использования с большинством идиом R:
> this.data
Time Trial Class Channel Value
1: -100.00000 1 -1 V1 0.4551513
2: -96.07843 2 -1 V1 0.8241555
3: -92.15686 3 -1 V1 0.7667328
4: -88.23529 4 -1 V1 0.7475106
5: -84.31373 5 -1 V1 0.9810273
---
204796: 884.31373 196 1 V4 50.2642220
204797: 888.23529 197 1 V4 50.5747661
204798: 892.15686 198 1 V4 50.5749421
204799: 896.07843 199 1 V4 50.1988299
204800: 900.00000 200 1 V4 50.7756015
В частности, приведенные выше данные имеют столбец Time с 256 уникальными числами от 0 до 900, которые повторяются для каждого Channel, для каждого Trial. Точно так же каждый Channel является одним из V1,V2,V3,V4, повторяющихся для каждого Time образца, для каждого Trial. Другими словами, любая комбинация Time,Trial,Channel однозначно определяет Value. Для простоты, все Trial до 100 имеют Class -1, а все выше 99 имеют Class 1. (Для тестирования, все Value в Class 1 имеют среднее значение 50, а Class 0 имеют среднее значение 0 . (Эти данные можно сгенерировать и настроить с помощью функции dummy.plug(), включенной в суть, которую я составил. )
Чтобы обрабатывать данные с использованием различных алгоритмов классификации машинного обучения, кажется, необходимо преобразовать данные во что-то более широкое, чтобы каждый из временных рядов имел свой собственный столбец, а другие оставались в виде идентификаторов. (Например, ступенчатому классификатору stepclass из klaR нужны функции в разных столбцах, поэтому он может выбирать, какие из них отбрасывать или добавлять в свою модель по мере обучения.) Поскольку есть повторные испытания, мне не удалось создать существующие функции, такие как работа семьи cast, поэтому я написал свою собственную:
##### converting from long table form to channel-split wide form #####
# for multivariate repeated time series
channel.form <- function(input.table,
value.col = "Voltage",
split.col = "Channel",
class.col = "Class",
time.col = "Time",
trial.col = "Trial") {
# Converts long table format to slightly wider format split by channels.
# For epoched datasets.
setkeyv(input.table, class.col)
chan.split <- split(input.table,input.table[,get(split.col)])
chan.d <- cbind(lapply(chan.split, function(x){
x[,value.col,with=FALSE]}))
chan.d <- as.data.table(matrix(unlist(chan.d),
ncol = input.table[,length(unique(get(split.col)))],
byrow=TRUE))
# reintroduce class labels
# since the split is over identical sections for each channel, we can just use
# the first split's labels
chan.d <- chan.d[,c(class.col):= chan.split[[1]][,get(class.col)]]
chan.d[,c(class.col):=as.factor(get(class.col))]
# similarly with time and trial labels
chan.d <- chan.d[,Time:= chan.split[[1]][,get(time.col)]]
chan.d <- chan.d[,Trial:= chan.split[[1]][,get(trial.col)]]
return(chan.d)
}
Используя эту функцию, я беру несколько подготовленных мной многомерных испытаний в длинное data.table, подобное приведенному вверху, и преобразую их в более широкое, которое выглядит следующим образом:
> this.data.training.channel
V1 V2 V3 V4 Class Time Trial
1: -50.58389 -50.56397 -50.74251 -50.86700 -1 -100.00000 1
2: -50.92713 -50.28009 -50.15078 -50.70161 -1 -96.07843 2
3: -50.84276 -50.02456 -50.20015 -50.45228 -1 -76.47059 7
4: -50.68679 -50.05475 -50.04270 -50.83900 -1 -72.54902 8
5: -50.55954 -50.88998 -50.01273 -50.86856 -1 -68.62745 9
---
35836: 49.52361 49.37465 49.73997 49.10543 1 876.47059 194
35837: 49.93162 49.38352 49.62406 49.16854 1 888.23529 197
35838: 49.67510 49.63853 49.54259 49.81198 1 892.15686 198
35839: 49.26295 49.98449 49.60437 49.03918 1 896.07843 199
35840: 49.05030 49.42035 49.48546 49.73438 1 900.00000 200
На этом этапе я беру расширенную таблицу и передаю ее классификатору, такому как lda(), а затем проверяю ее на отдельной случайной части тех же данных:
lda.model <- lda(Class ~ . -Trial, this.data.training.channel)
lda.pred <- predict(lda.model, this.data.testing.channel)
симптомы
Однако, даже если я генерирую неприлично разделенные фиктивные данные (см. рисунок ниже), я получаю почти случайные результаты с существующими разумными библиотеками. (Я знаю, что библиотеки, вероятно, не виноваты, потому что, если я позволю алгоритму использовать пробный индекс в качестве функции обучения, он правильно классифицирует каждый ввод.)

> table(predicted = lda.pred$class, data = this.data.testing.channel[,Class])
data
predicted -1 1
-1 2119 1878
1 5817 5546
> 1-sum(lda.pred$class != this.data.testing.channel[,Class])/length(lda.pred$class)
[1] 0.4984375
> table(predicted = sda.pred$class, data = this.data.testing.channel[,Class])
data
predicted -1 1
-1 3705 3969
1 3719 3967
> 1-sum(sda.pred$class != this.data.testing.channel[,Class])/length(sda.pred$class)
[1] 0.4994792
Частота ошибок — это, по сути, подбрасывание монеты, несмотря на то, что значения из класса 1 примерно в 50 раз превышают значения из класса -1. Должно быть, я совершаю какую-то огромную ошибку (я думаю, что это ошибка программирования, иначе я бы закончил перекрестную проверку), но я потратил дни, подталкивая ее и переписывая код без каких-либо улучшений. (В качестве примера обратите внимание, что я получаю один и тот же результат независимо от того, масштабирую ли я входные значения так, чтобы они имели среднее значение 0, дисперсию 1.)
воспроизведение проблемы
Полный список, который можно запустить для воспроизведения проблемы, доступен здесь.
возможные проблемы я рассмотрел, что я пробовал
(полный список см. в предыдущих редакциях вопроса из-за соображений длины)
Я написал функцию (включенную в gist) для создания легко отделяемых фиктивных данных и написал еще одну функция для усреднения каждого из двух классов, ограненных Channel и окрашенных Class, как на графике выше. Игра с каждым из параметров (разница в средних значениях населения, количество каналов и т. д.), кажется, дает ожидаемый результат, а также просмотр соответствующих подмножеств с использованием вызовов типа this.data[Trial==1,unique(Time),by=Subject].
что мне нужно, чтобы решить это?
Буду очень признателен за любые советы по исправлению этого. Я просто не вижу, что я делаю неправильно.
Если бы кто-то либо диагностировал/обнаружил проблему, либо смог проиллюстрировать, используя другой подход, измененную таблицу из данных, которая работала с этими (популярными) функциями классификатора, я бы не просто согласился, я бы присудил награду (после тестирование, конечно).
информация о сеансе
R version 3.0.2 (2013-09-25)
Platform: x86_64-pc-linux-gnu (64-bit)
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8
[4] LC_COLLATE=en_US.UTF-8 LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C LC_ADDRESS=C
[10] LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] parallel grid stats graphics grDevices utils datasets methods
[9] base
other attached packages:
[1] doMC_1.3.2 iterators_1.0.6 AUC_0.3.0
[4] LiblineaR_1.80-7 RcppRoll_0.1.0 RcppArmadillo_0.4.300.0
[7] Rcpp_0.11.1 foreach_1.4.1 cvTools_0.3.2
[10] robustbase_0.90-2 latticist_0.9-44 vcd_1.3-1
[13] latticeExtra_0.6-26 lattice_0.20-29 pheatmap_0.7.7
[16] RColorBrewer_1.0-5 klaR_0.6-10 MASS_7.3-29
[19] ggplot2_0.9.3.1 reshape2_1.2.2 data.table_1.9.2
[22] sda_1.3.3 fdrtool_1.2.12 corpcor_1.6.6
[25] entropy_1.2.0 zoo_1.7-11 testthat_0.8
loaded via a namespace (and not attached):
[1] codetools_0.2-8 colorspace_1.2-4 combinat_0.0-8 compiler_3.0.2 DEoptimR_1.0-1
[6] dichromat_2.0-0 digest_0.6.4 gtable_0.1.2 gWidgets_0.0-52 labeling_0.2
[11] munsell_0.4.2 plyr_1.8 proto_0.3-10 scales_0.2.3 stringr_0.6.2
[16] tools_3.0.2