如何获得一个KNN模型使用分位数来缩放由于非正态分布数据导致的变量,使其更适合数据中的非极值?

问题描述

我想通过k均值/模式对数据进行聚类。由于数据中的变量不是正态分布的,因此我没有使用z变换来缩放数据。我正在按数据的每一列按其分位数(0、0.2、0.4、0.6、0.8、1分位数)对数据进行缩放,例如如果该值在0到0.2分位数之间,则将其标记为1。我的数据框由5列百分比组成。每行的总和为100%。您会看到它就像每一列都是股票,每一行都是投资者,并且单元格显示出投资者投资组合中有多少是由某只股票组成的(假设市场上只有这五只股票)。我的目标是了解市场上的投资者类型-他们的投资组合特征。这里是一个示例数据帧(很长的代码,很抱歉,但是我需要包括一定数量的数据点,以仍然获得与原始数据相比类似的变量分布):

mydf <- structure(list(perc1 = c(0.639,100,5.5556,11.1111,3.3058,0.9901,2.5641,16.6667,33.3333,6.25,8.6957,19.0476,3.8462,14.2857,0.2041,4.878,15.3846,37.5,0),perc2 = c(1.278,88.8889,62.5,7.6923,13.3333,0.8163,28.5714,50,perc3 = c(97.4441,68.5185,76.4706,25,30.7692,71.4286,76.0331,95.5446,64.1026,92.3077,66.6667,31.5789,47.619,97.6077,46.1538,55.5556,20,35.7143,98.6735,38.4615,78.0488,perc4 = c(0,30,40,35.1351,75,7.1429,80,2.4793,57.1429,0.495,17.9487,42.8571,86.9565,22.2222,21.0526,4.7619,19.2308,7.3171,42.1053,12.5,18.75,perc5 = c(0.639,70,25.9259,60,64.8649,23.5294,83.3333,21.4286,18.1818,1.9802,58.3333,31.25,4.3478,47.3684,2.3923,23.0769,85.7143,64.2857,0.3061,9.7561,53.8462,77.7778,57.8947,81.25,100)),class = "data.frame",row.names = c(NA,-100L))

在检查5个变量的分布时,我们可以看到变量1-3的值大部分为零,而最后一个变量具有100%的百分比值:

> quantile(mydf[,1],probs = 0:5/5)
      0%      20%      40%      60%      80%     100% 
  0.0000   0.0000   0.0000   0.0000   1.3049 100.0000 
> quantile(mydf[,2],probs = 0:5/5)
  0%  20%  40%  60%  80% 100% 
   0    0    0    0    0  100 
> quantile(mydf[,3],probs = 0:5/5)
       0%       20%       40%       60%       80%      100% 
  0.00000   0.00000   0.00000   0.00000  39.99996 100.00000 
> quantile(mydf[,4],probs = 0:5/5)
       0%       20%       40%       60%       80%      100% 
  0.00000   0.00000   0.29700  21.52044  50.00000 100.00000 
> quantile(mydf[,5],probs = 0:5/5)
       0%       20%       40%       60%       80%      100% 
  0.00000   0.57242  28.57140  60.00000 100.00000 100.00000 

现在,我缩放变量并使用k模式(具有10个簇):

require(klaR)
mydf_scaled <- do.call(cbind,lapply(mydf,function (x) {
  return(as.character(.bincode(x,quantile(x,probs = 0:5/5),include.lowest = T)))
}))
mymodel <- klaR::kmodes(mydf_scaled,modes = 10)

然后我得到以下10个簇:

> mymodel$modes
   perc1 perc2 perc3 perc4 perc5
1      1     1     1     3     4
2      1     1     5     1     1
3      1     1     1     5     1
4      5     1     1     5     2
5      1     1     1     1     4
6      1     1     1     4     3
7      1     1     4     3     3
8      1     1     5     3     2
9      5     1     5     3     2
10     5     1     1     1     1

我现在遇到的问题是,由于分位数几乎为零,对于perc1我只能得到值1或5,而对于perc2我只能得到一个值,因为该变量的大多数值都是零。对于perc5,我从未获得类别5,因为80%的分位数已经是100%。因此,我无法很好地区分某些变量。对于perc2,尽管有一些我感兴趣的非零值,但我无法获得任何区别。与perc1类似,与只具有两个值1和5相比,我想在正值之间进行更详细的区分(我只能说它是零值或正值,而不是对正值在聚类中的差异如何)。我如何优化群集以向我提供有关群集中正值的差异的更多信息,而又不会完全弄清我的数据?我不想删除任何数据。

我的一个主意是只取数据框中的正值的分位数来缩放变量(并在开头添加零以说明零值-因此我将取0,然后取0.2、0.4 ,正值的0.6、0.8和1分位数):

mydf_scaled2 <- do.call(cbind,c(0,quantile(x[x > 0],probs = 1:5/5)),include.lowest = T)))
}))
mymodel2 <- klaR::kmodes(mydf_scaled2,modes = 10)

哪个返回以下群集:

> mymodel2$modes
   perc1 perc2 perc3 perc4 perc5
1      1     1     1     5     1
2      2     2     2     2     1
3      1     1     1     1     4
4      1     1     1     4     2
5      1     1     1     3     3
6      1     3     1     3     2
7      2     4     1     1     1
8      1     1     1     3     2
9      1     1     5     1     1
10     3     1     1     2     3

这将导致有关变量中非零值的更多详细信息。但是,我不确定使用这种方法是否有意义,并且由于计算分位数的方法不同,我得到的结果是否代表我的数据还是它过度代表了非零值。

是否有人知道我该如何解决我的问题(无法在群集中的正值之间进行区分)并仍然获得可以很好地代表我的数据的群集?我应该使用其他方法缩放变量吗?谢谢!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...