这种从长到宽的重塑我做错了什么?

bri*_*tar 5 r machine-learning reshape 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
Run Code Online (Sandbox Code Playgroud)

具体地说,上述数据具有一个Time具有从0到900的256个唯一编号的列,每个编号Channel对于每个编号重复Trial.类似地,每个Channel都是V1,V2,V3,V4每个Time样本重复的一个Trial.换句话说,任何组合都Time,Trial,Channel唯一地指定a Value.为了简单起见,Trial100以下的所有s都是Class-1,而99以上的所有都是Class1.(出于测试目的,1中的Values Class均值为50,而Class0中的s 均值为0.(此数据)可以使用我制作的要点中dummy.plug()包含的功能生成和调整.)

为了使用不同的机器学习分类算法处理数据,似乎有必要将数据重新整形为更宽一些,以便每个时间序列都有自己的列,而其他时间序列仍然是ID.(例如,逐级分类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) 
}
Run Code Online (Sandbox Code Playgroud)

使用这个函数,我做了一些我已经准备好的多变量试验,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
Run Code Online (Sandbox Code Playgroud)

此时,我将扩展表放到分类器中lda(),然后在相同数据的单独随机部分上进行测试:

lda.model <- lda(Class ~ . -Trial, this.data.training.channel)
lda.pred <- predict(lda.model, this.data.testing.channel)
Run Code Online (Sandbox Code Playgroud)

症状

然而,即使我生成了淫秽分离的虚拟数据(见下图),我现有合理的库也会获得近乎可能的结果.(我知道库可能没有错,因为如果我允许算法使用试验索引作为训练功能,它会正确地对每个输入进行分类.)

在四个渠道中将两类数据分开

> 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
Run Code Online (Sandbox Code Playgroud)

错误率基本上是硬币翻转,尽管类的值1大约是类的值的50倍-1.我必须犯一些巨大的错误(我认为这是一个编程问题,否则我会在交叉验证上结束),但我花了几天时间来刺激它并重写代码而没有任何改进.(作为一个例子,请注意我得到相同的结果,无论我是否缩放输入值,使它们的均值为0,方差为1.)

再现问题

此处提供可以运行以重现问题的完整要点.

我考虑的可能问题,我尝试过的

(由于篇幅考虑,请参阅完整列表的问题的先前修订版)

我写了一个函数(包含在要点中)来生成易于分离的虚拟数据,并编写了另一个函数来平均两个类中的每一个,由上面的图表分割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   
Run Code Online (Sandbox Code Playgroud)

MrF*_*ick 2

我无法重现您的错误,并且我发现了一些问题dummy.plug()。我用生成的数据

library(data.table)
library(reshape2)
library("MASS")

set.seed(115)
pp<-dummy.plug(trial.count = 200,
    chan.count = 4,
    mean.diff = 100,
    value.name = "Value")
Run Code Online (Sandbox Code Playgroud)

我不关心 data.table,所以我只是将其转换为基本的 data.frame。

dd<-as.data.frame(pp)
Run Code Online (Sandbox Code Playgroud)

现在您说TimeTrial、 和Channel应该唯一标识一个值,但虚拟数据中的情况似乎并非如此。我看到

subset(dd, Time==-100 & Trial==1 & Channel=="V1")

#       Time Trial Class Channel      Value
# 1     -100     1    -1      V1 0.73642916
# 6401  -100     1    -1      V1 0.17648939
# 12801 -100     1    -1      V1 0.41366964
# 19201 -100     1    -1      V1 0.07044473
# 25601 -100     1    -1      V1 0.86583284
# 32001 -100     1    -1      V1 0.24255411
# 38401 -100     1    -1      V1 0.92473225
# 44801 -100     1    -1      V1 0.69989600
Run Code Online (Sandbox Code Playgroud)

因此,每个组合显然有多个值。因此,为了继续,我决定只取观察值的平均值。dcast我使用没有任何问题

xx<-dcast(dd, Class+Time+Trial~Channel, fun.aggregate=mean)
Run Code Online (Sandbox Code Playgroud)

然后我分割训练/测试数据集

train.trials = sample(unique(dd$Trial), 140)
train.data = subset(xx, Trial %in% train.trials)
test.data = subset(xx, !Trial %in% train.trials)
Run Code Online (Sandbox Code Playgroud)

然后我按照上面的方式运行lda

lda.model <- lda(Class ~ . -Trial, train.data)
lda.pred <- predict(lda.model, test.data)
Run Code Online (Sandbox Code Playgroud)

我检查了我的表现

table(lda.pred$class, test.data$Class)
#        -1    1
#   -1  704    0
#   1     0 1216
Run Code Online (Sandbox Code Playgroud)

而且我看起来比你做得更好。

除非我将 data.table 转换为 data.frame 时发生了一些不好的事情,否则您的测试数据似乎存在问题。也许您的非强制重塑功能有问题。看到dcast工作得很好,也许您想检查您的功能是否也正常工作。