《写给程序员的数据挖掘实践指南》——5.4一个编程的例子

简介:

本节书摘来自异步社区出版社《写给程序员的数据挖掘实践指南》一书中的第5章,第5.4节,作者:【美】Ron Zacharski(扎哈尔斯基),更多章节内容可以访问云栖社区“异步社区”公众号查看。

5.4一个编程的例子

回到上一章当中提到的来自卡内基梅隆大学的汽车MPG数据集,该数据集的格式如下:

image

下面试图基于气缸的数目、排水量(立方英寸)、功率、重量和加速时间预测汽车的MPG。我将所有392个实例放到mpgData.txt文件中,然后编写了如下的短Python程序,该程序利用分层采样方法将数据分到10个桶中(数据集及Python代码都可以从网站guidetodatamining.com下载)。

import random
def buckets(filename, bucketName, separator, classColumn):
  """the original data is in the file named filename
  bucketName is the prefix for all the bucket names
  separator is the character that divides the columns
  (for ex., a tab or comma) and classColumn is the column
  that indicates the class"""

  # put the data in 10 buckets
  numberOfBuckets = 10
  data = {}
  # first read in the data and divide by category
  with open(filename) as f:
    lines = f.readlines()
  for line in lines:
    if separator != '\t':
      line = line.replace(separator, '\t')
    # first get the category
    category = line.split()[classColumn]
    data.setdefault(category, [])
    data[category].append(line)
  # initialize the buckets
  buckets = []
  for i in range(numberOfBuckets):
    buckets.append([])
  # now for each category put the data into the buckets
  for k in data.keys():
    #randomize order of instances for each class
  random.shuffle(data[k])
  bNum = 0
  # divide into buckets
  for item in data[k]:
    buckets[bNum].append(item)
    bNum = (bNum + 1) % numberOfBuckets
  # write to file
  for bNum in range(numberOfBuckets):
    f = open("%s-%02i" % (bucketName, bNum + 1), 'w')
    for item in buckets[bNum]:
      f.write(item)
    f.close()

buckets("mpgData.txt", 'mpgData','\t',0)

执行上述代码会产生10个分别为mpgData01、mpgData02… mpgData10的文件。

image

能否修改上一章中近邻算法的代码,以使test函数能够在刚刚构建的10个文件上进行10折交叉验证(该数据集可以从网站guidetodatamining.com下载)?

你的程序应该输出类似如下矩阵的混淆矩阵:
image

该解答只涉及如下方面:

修改initializer方法以便从9个桶中读取数据;

加入一个新的方法对一个桶中的数据进行测试;

加入一个新的过程来执行10折交叉验证过程。

下面依次来考察上述修改。

initializer方法的签名看起来如下:

def __init__(self, bucketPrefix, testBucketNumber, dataFormat):

每个桶的文件名类似于mpgData-01、mpgData-02,等等。这种情况下,bucketPrefix将是“mpgData”,而testBucketNumber是包含测试数据的桶。如果testBucketNumber为3,则分类器将会在桶1、2、4、5、6、7、8、9、10上进行训练。dataFormat是一个如何解释数据中每列的字符串,比如:

"class  num  num  num  num  num  comment"

它表示第一列代表实例的类别,下面5列代表实例的数值型属性,最后一列会被看成注释。

新的初始化方法的完整代码如下:

import copy

class Classifier:
  def __init__(self, bucketPrefix, testBucketNumber, dataFormat):

    """ a classifier will be built from files with the bucketPrefix
    excluding the file with textBucketNumber. dataFormat is a
    string that describes how to interpret each line of the data
    files. For example, for the mpg data the format is:
    "class num  num  num  num  num  comment"
    """
    self.medianAndDeviation = []

    # reading the data in from the file
    self.format = dataFormat.strip().split('\t')
    self.data = []
    # for each of the buckets numbered 1 through 10:
    for i in range(1, 11):
      # if it is not the bucket we should ignore, read the data
      if i != testBucketNumber:
        filename = "%s-%02i" % (bucketPrefix, i)
        f = open(filename)
        lines = f.readlines()
        f.close()
        for line in lines:
          fields = line.strip().split('\t')
          ignore = []
          vector = []
          for i in range(len(fields)):
            if self.format[i] == 'num':
              vector.append(float(fields[i]))
            elif self.format[i] == 'comment':
              ignore.append(fields[i])
            elif self.format[i] == 'class':
              classification = fields[i]
          self.data.append((classification, vector, ignore))
  self.rawData = copy.deepcopy(self.data)
  # get length of instance vector
  self.vlen = len(self.data[0][1])
  # now normalize the data
  for i in range(self.vlen):
    self.normalizeColumn(i)

testBucket方法
下面编写一个新的方法来测试一个桶中的数据。

def testBucket(self, bucketPrefix, bucketNumber):
  """Evaluate the classifier with data from the file
  bucketPrefix-bucketNumber"""

  filename = "%s-%02i" % (bucketPrefix, bucketNumber)
  f = open(filename)
  lines = f.readlines()
  totals = {}
  f.close()
  for line in lines:
    data = line.strip().split('\t')
    vector = []
    classInColumn = -1
    for i in range(len(self.format)):
      if self.format[i] == 'num':
        vector.append(float(data[i]))
      elif self.format[i] == 'class':
        classInColumn = i
    theRealClass = data[classInColumn]
    classifiedAs = self.classify(vector)
    totals.setdefault(theRealClass, {})
    totals[theRealClass].setdefault(classifiedAs, 0)
    totals[theRealClass][classifiedAs] += 1
  return totals

它以bucketPrefix和bucketNumber为输入,如果前者为“mpgData”、后者为3的话,测试数据将会从文件mpgData-03中读取,而testBucket将会返回如下格式的字典:

{'35':   {'35': 1, '20': 1, '30': 1},
 '40':   {'30': 1},
 '30':   {'35': 3, '30': 1, '45': 1, '25': 1},
 '15':   {'20': 3, '15': 4, '10': 1},
 '10':   {'15': 1},
 '20':   {'15': 2, '20': 4, '30': 2, '25': 1},
 '25':   {'30': 5, '25': 3}}

字典的键代表的是实例的真实类别。例如,上面第一行表示真实类别为35mpg的实例的结果。每个键的值是另一部字典,该字典代表分类器对实例进行分类的结果。例如行

'15':    {'20': 3, '15': 4, '10': 1},

表示实际为15mpg的3个实例被错分到20mpg类别中,而有4个实例被正确分到15mpg中,1个实例被错分到10mpg中。

10折交叉验证的执行流程
最后,我们需要编写一个过程来实现10折交叉验证。也就是说,我们要构造10个分类器。每个分类器利用9个桶中的数据进行训练,而将其余数据用于测试。

def tenfold(bucketPrefix, dataFormat):
  results = {}
  for i in range(1, 11):
    c = Classifier(bucketPrefix, i, dataFormat)
    t = c.testBucket(bucketPrefix, i)
    for (key, value) in t.items():
      results.setdefault(key, {})
      for (ckey, cvalue) in value.items():
        results[key].setdefault(ckey, 0)
        results[key][ckey] += cvalue

    # now print results
  categories = list(results.keys())
  categories.sort()
  print(   "\n   Classified as: ")
  header = "     "
  subheader = "   +"
  for category in categories:
    header += category + "  "
    subheader += "----+"
  print (header)
  print (subheader)
  total = 0.0
  correct = 0.0
  for category in categories:
    row = category + " |"
    for c2 in categories:
      if c2 in results[category]:
        count = results[category][c2]
      else:
        count = 0
      row += " %2i |" % count
      total += count
      if c2 == category:
        correct += count
    print(row)
  print(subheader)
  print("\n%5.3f percent correct" %((correct * 100) / total))
  print("total of %i instances" % total)

tenfold("mpgData", "class num num num num num comment")

运行上述程序会产生如下结果:
image

相关文章
|
4月前
|
数据挖掘 索引 Python
Python数据挖掘编程基础3
字典在数学上是一个映射,类似列表但使用自定义键而非数字索引,键在整个字典中必须唯一。可以通过直接赋值、`dict`函数或`dict.fromkeys`创建字典,并通过键访问元素。集合是一种不重复且无序的数据结构,可通过花括号或`set`函数创建,支持并集、交集、差集和对称差集等运算。
30 9
|
4月前
|
数据挖掘 Python 容器
Python数据挖掘编程基础
Python包含四种内置数据结构:列表(List)、元组(Tuple)、字典(Dictionary)和集合(Set),统称为容器。列表与元组均为序列结构,前者使用方括号表示且可修改,后者用圆括号表示且不可修改。列表支持多种方法和列表解析功能,以简化元素操作。例如,通过列表解析可以简洁地实现`d=[i+1 for i in c]`,输出结果为`[2,3,4]`。
47 7
|
4月前
|
数据挖掘 Python
Python数据挖掘编程基础8
在Python中,默认环境下并不会加载所有功能,需要手动导入库以增强功能。Python内置了诸多强大库,例如`math`库可用于复杂数学运算。导入库不仅限于`import 库名`,还可以通过别名简化调用,如`import math as m`;也可指定导入库中的特定函数,如`from math import exp as e`;甚至直接导入库中所有函数`from math import *`。但需注意,后者可能引发命名冲突。读者可通过`help('modules')`查看已安装模块。
51 0
|
4月前
|
人工智能 数据挖掘 Serverless
Python数据挖掘编程基础
函数式编程中的`reduce`函数用于对可迭代对象中的元素进行累积计算,不同于逐一遍历的`map`函数。例如,在Python3中,计算n的阶乘可以使用`reduce`(需从`funtools`库导入)实现,也可用循环命令完成。另一方面,`filter`函数则像一个过滤器,用于筛选列表中符合条件的元素,同样地功能也可以通过列表解析来实现。使用这些函数不仅使代码更加简洁,而且由于其内部循环机制,执行效率通常高于普通的`for`或`while`循环。
37 0
|
4月前
|
分布式计算 数据挖掘 Serverless
Python数据挖掘编程基础6
函数式编程(Functional Programming)是一种编程范型,它将计算机运算视为数学函数计算,避免程序状态及易变对象的影响。在Python中,函数式编程主要通过`lambda`、`map`、`reduce`、`filter`等函数实现。例如,对于列表`a=[5,6,7]`,可通过列表解析`b=[i+3 for i in a]`或`map`函数`b=map(lambda x:x+3, a)`实现元素加3的操作,两者输出均为`[8,9,10]`。尽管列表解析代码简洁,但其本质仍是for循环,在Python中效率较低;而`map`函数不仅功能相同,且执行效率更高。
20 0
|
4月前
|
数据挖掘 Python
Python数据挖掘编程基础5
函数是Python中用于提高代码效率和减少冗余的基本数据结构,通过封装程序逻辑实现结构化编程。用户可通过自定义或函数式编程方式设计函数。在Python中,使用`def`关键字定义函数,如`def pea(x): return x+1`,且其返回值形式多样,可为列表或多个值。此外,Python还支持使用`lambda`定义简洁的行内函数,例如`c=lambda x:x+1`。
49 0
|
4月前
|
数据挖掘 Python
Python数据挖掘编程基础
判断与循环是编程的基础,Python中的`if`、`elif`、`else`结构通过条件句来执行不同的代码块,不使用花括号,依赖缩进区分代码层次。错误缩进会导致程序出错。Python支持`for`和`while`循环,`for`循环结合`range`生成序列,简洁直观。正确缩进不仅是Python的要求,也是一种良好的编程习惯。
35 0
|
4月前
|
数据挖掘 Python
Python数据挖掘编程基础
本章介绍了Python数据挖掘编程的基础知识,涵盖Python入门所需的命令、判断与循环、函数、库导入等内容,并重点讲解了数据分析预处理和建模常用库。通过学习基本运算、数据结构、字符串操作等,帮助读者快速掌握Python语言,为后续数据挖掘工作打下坚实基础。例如,通过代码`a=3`进行赋值,利用`a*3`执行乘法运算,使用`a**3`计算幂,以及通过对字符串的拼接和分割操作,展示Python的强大功能。
59 0

热门文章

最新文章