проблема
Функция, которую я написал для расширения длинной таблицы повторяющихся многомерных данных временных рядов для ввода в функции классификатора, по-видимому, приводит к ошибочным результатам даже для простых тестовых данных, но я не могу найти проблему.
фон
Я держу кучу повторных испытаний многомерных временных рядов в длинном формате 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