用混合特征计算分类的矢量距离

时间:2013-11-25 20:51:31

标签: machine-learning nearest-neighbor feature-selection

我正在做一个比较各种分类算法的有效性的项目,但我陷入了一个令人沮丧的问题。数据可在此处找到:http://archive.ics.uci.edu/ml/datasets/Adult分类问题是一个人是否根据人口普查数据每年超过5万。

两个示例条目如下:

45岁,私人,98092,HS-grad,9岁,已婚 - 公民 - 配偶,销售,丈夫,白人,男性,0,0,60,美国,< = 50K

50岁,Self-emp-not-inc,386397,单身汉,13岁,已婚 - 公民配偶,销售,丈夫,白人,男,0,0,60,美国,< = 50K

我熟悉使用欧氏距离来计算向量之间的差异,但我不确定如何使用连续和离散属性的混合。有没有有效的方法以有意义的方式表示两个向量之间的差异?我很难理解像第三个属性那样大的值(由基于因子提取数据集的人计算的权重,因此相似的权重应该具有相似的属性)和它之间的差异可以保留意义来自男性或女性等离散特征,如果我正确理解方法,则只是欧几里得距离1。我确定可以删除某些类别,但我不想删除那些因素而非显着分类的内容。我得到这个问题后首先处理k-NN,然后是贝叶斯分类器,最后是一个决策树模型,如C4.5或ID3,如果我有时间的话。

3 个答案:

答案 0 :(得分:1)

当然,您可以通过多种方式延长欧几里德距离。最简单的扩展将是以下规则:

如果匹配则

距离= 0,否则为1

挑战将是使k-NN的距离概念“相关”跟进。在某些情况下(例如教育),我认为最好将教育(离散变量)映射到连续变量,例如教育年限。所以你需要写一个映射的函数,例如“HS-grad”到12,“Bachelors”到16,就像那样。

除此之外,直接使用k-NN是行不通的,因为多个不相似维度之间的“距离”概念没有明确定义。我认为你最好不要抛弃其中的一些尺寸,或者以不同的方式对它们进行加权。我不知道你的数据集中的第三个数字(例如98092)意味着什么,但如果你使用天真的欧几里德距离,那么与其他维度(例如年龄)相比,这将非常超重。

我不是机器学习专家,但我个人很想在缩小的维度数据集上启动k-NN,你只需要选择一些广泛的人口统计数据(例如年龄,教育程度,婚姻状况)并忽略那些棘手的/“吵闹的“类别。

答案 1 :(得分:0)

您需要将分类变量编码为1-of-n二进制变量(变量的n个选项,以及这些变量中的一个且只有一个是活动的)。然后标准化您的功能---为每个功能,减去其平均值并除以标准偏差。或者归一化到0-1的范围。它并不完美,但至少可以使尺寸相当。

答案 2 :(得分:0)

为每个数据点创建单独的地图,并使用地图转换为双精度值。

def createMap(data: RDD[String]) : Map[String,Double] = {  
 var mapData:Map[String,Double] = Map()
 var counter = 0.0
 data.collect().foreach{ item => 
  counter = counter +1
  mapData += (item -> counter)
 }
 mapData
}

def getLablelValue(input: String): Int = input match {
 case "<=50K" => 0
 case ">50K" => 1
}


val census = sc.textFile("/user/cloudera/census_data.txt")
val orgTypeRdd  = census.map(line => line.split(", ")(1)).distinct
val gradeTypeRdd = census.map(line => line.split(", ")(3)).distinct
val marStatusRdd = census.map(line => line.split(", ")(5)).distinct
val jobTypeRdd = census.map(line => line.split(", ")(6)).distinct
val familyStatusRdd = census.map(line => line.split(", ")(7)).distinct
val raceTypeRdd = census.map(line => line.split(", ")(8)).distinct
val genderTypeRdd = census.map(line => line.split(", ")(9)).distinct
val countryRdd = census.map(line => line.split(", ")(13)).distinct
val salaryRange = census.map(line => line.split(", ")(14)).distinct

val orgTypeMap = createMap(orgTypeRdd)
val gradeTypeMap = createMap(gradeTypeRdd)
val marStatusMap = createMap(marStatusRdd)
val jobTypeMap = createMap(jobTypeRdd)
val familyStatusMap = createMap(familyStatusRdd)
val raceTypeMap = createMap(raceTypeRdd)
val genderTypeMap = createMap(genderTypeRdd)
val countryMap = createMap(countryRdd)
val salaryRangeMap = createMap(salaryRange)


val featureVector = census.map{line => 
  val fields = line.split(", ")
 LabeledPoint(getLablelValue(fields(14).toString) , Vectors.dense(fields(0).toDouble,  orgTypeMap(fields(1).toString) , fields(2).toDouble , gradeTypeMap(fields(3).toString) , fields(4).toDouble , marStatusMap(fields(5).toString), jobTypeMap(fields(6).toString), familyStatusMap(fields(7).toString),raceTypeMap(fields(8).toString),genderTypeMap (fields(9).toString), fields(10).toDouble , fields(11).toDouble , fields(12).toDouble,countryMap(fields(13).toString) , salaryRangeMap(fields(14).toString)))
}