Python实现的随机森林算法与简单总结


Posted in Python onJanuary 30, 2018

本文实例讲述了Python实现的随机森林算法。分享给大家供大家参考,具体如下:

随机森林是数据挖掘中非常常用的分类预测算法,以分类或回归的决策树为基分类器。算法的一些基本要点:

*对大小为m的数据集进行样本量同样为m的有放回抽样;
*对K个特征进行随机抽样,形成特征的子集,样本量的确定方法可以有平方根、自然对数等;
*每棵树完全生成,不进行剪枝;
*每个样本的预测结果由每棵树的预测投票生成(回归的时候,即各棵树的叶节点的平均)

著名的python机器学习包scikit learn的文档对此算法有比较详尽的介绍: http://scikit-learn.org/stable/modules/ensemble.html#random-forests

出于个人研究和测试的目的,基于经典的Kaggle 101泰坦尼克号乘客的数据集,建立模型并进行评估。比赛页面及相关数据集的下载:https://www.kaggle.com/c/titanic

泰坦尼克号的沉没,是历史上非常著名的海难。突然感到,自己面对的不再是冷冰冰的数据,而是用数据挖掘的方法,去研究具体的历史问题,也是饶有兴趣。言归正传,模型的主要的目标,是希望根据每个乘客的一系列特征,如性别、年龄、舱位、上船地点等,对其是否能生还进行预测,是非常典型的二分类预测问题。数据集的字段名及实例如下:

PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
1 0 3 Braund, Mr. Owen Harris male 22 1 0 A/5 21171 7.25 S
2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Thayer) female 38 1 0 PC 17599 71.2833 C85 C
3 1 3 Heikkinen, Miss. Laina female 26 0 0 STON/O2. 3101282 7.925 S
4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 1 0 113803 53.1 C123 S
5 0 3 Allen, Mr. William Henry male 35 0 0 373450 8.05 S

值得说明的是,SibSp是指sister brother spouse,即某个乘客随行的兄弟姐妹、丈夫、妻子的人数,Parch指parents,children

下面给出整个数据处理及建模过程,基于ubuntu+python 3.4( anaconda科学计算环境已经集成一系列常用包,pandas numpy sklearn等,这里强烈推荐)

懒得切换输入法,写的时候主要的注释都是英文,中文的注释是后来补充的:-)

# -*- coding: utf-8 -*-
"""
@author: kim
"""
from model import *#载入基分类器的代码
#ETL:same procedure to training set and test set
training=pd.read_csv('train.csv',index_col=0)
test=pd.read_csv('test.csv',index_col=0)
SexCode=pd.DataFrame([1,0],index=['female','male'],columns=['Sexcode']) #将性别转化为01
training=training.join(SexCode,how='left',on=training.Sex)
training=training.drop(['Name','Ticket','Embarked','Cabin','Sex'],axis=1)#删去几个不参与建模的变量,包括姓名、船票号,船舱号
test=test.join(SexCode,how='left',on=test.Sex)
test=test.drop(['Name','Ticket','Embarked','Cabin','Sex'],axis=1)
print('ETL IS DONE!')
#MODEL FITTING
#===============PARAMETER AJUSTMENT============
min_leaf=1
min_dec_gini=0.0001
n_trees=5
n_fea=int(math.sqrt(len(training.columns)-1))
#==============================================
'''''
BEST SCORE:0.83
min_leaf=30
min_dec_gini=0.001
n_trees=20
'''
#ESSEMBLE BY RANDOM FOREST
FOREST={}
tmp=list(training.columns)
tmp.pop(tmp.index('Survived'))
feaList=pd.Series(tmp)
for t in range(n_trees):
#  fea=[]
  feasample=feaList.sample(n=n_fea,replace=False)#select feature
  fea=feasample.tolist()
  fea.append('Survived')
#    feaNew=fea.append(target)
  subset=training.sample(n=len(training),replace=True)#generate the dataset with replacement
  subset=subset[fea]
#  print(str(t)+' Classifier built on feature:')
#  print(list(fea))
  FOREST[t]=tree_grow(subset,'Survived',min_leaf,min_dec_gini) #save the tree
#MODEL PREDICTION
#======================
currentdata=training
output='submission_rf_20151116_30_0.001_20'
#======================
prediction={}
for r in currentdata.index:#a row
  prediction_vote={1:0,0:0}
  row=currentdata.get(currentdata.index==r)
  for n in range(n_trees):
    tree_dict=FOREST[n] #a tree
    p=model_prediction(tree_dict,row)
    prediction_vote[p]+=1
  vote=pd.Series(prediction_vote)
  prediction[r]=list(vote.order(ascending=False).index)[0]#the vote result
result=pd.Series(prediction,name='Survived_p')
#del prediction_vote
#del prediction
#result.to_csv(output)
t=training.join(result,how='left')
accuracy=round(len(t[t['Survived']==t['Survived_p']])/len(t),5)
print(accuracy)

上述是随机森林的代码,如上所述,随机森林是一系列决策树的组合,决策树每次分裂,用Gini系数衡量当前节点的“不纯净度”,如果按照某个特征的某个分裂点对数据集划分后,能够让数据集的Gini下降最多(显著地减少了数据集输出变量的不纯度),则选为当前最佳的分割特征及分割点。代码如下:

# -*- coding: utf-8 -*-
"""
@author: kim
"""
import pandas as pd
import numpy as np
#import sklearn as sk
import math
def tree_grow(dataframe,target,min_leaf,min_dec_gini):
  tree={} #renew a tree
  is_not_leaf=(len(dataframe)>min_leaf)
  if is_not_leaf:
    fea,sp,gd=best_split_col(dataframe,target)
    if gd>min_dec_gini:
      tree['fea']=fea
      tree['val']=sp
#      dataframe.drop(fea,axis=1) #1116 modified
      l,r=dataSplit(dataframe,fea,sp)
      l.drop(fea,axis=1)
      r.drop(fea,axis=1)
      tree['left']=tree_grow(l,target,min_leaf,min_dec_gini)
      tree['right']=tree_grow(r,target,min_leaf,min_dec_gini)
    else:#return a leaf
      return leaf(dataframe[target])
  else:
    return leaf(dataframe[target])
  return tree
def leaf(class_lable):
  tmp={}
  for i in class_lable:
    if i in tmp:
      tmp[i]+=1
    else:
      tmp[i]=1
  s=pd.Series(tmp)
  s.sort(ascending=False)
  return s.index[0]
def gini_cal(class_lable):
  p_1=sum(class_lable)/len(class_lable)
  p_0=1-p_1
  gini=1-(pow(p_0,2)+pow(p_1,2))
  return gini
def dataSplit(dataframe,split_fea,split_val):
  left_node=dataframe[dataframe[split_fea]<=split_val]
  right_node=dataframe[dataframe[split_fea]>split_val]
  return left_node,right_node
def best_split_col(dataframe,target_name):
  best_fea=''#modified 1116
  best_split_point=0
  col_list=list(dataframe.columns)
  col_list.remove(target_name)
  gini_0=gini_cal(dataframe[target_name])
  n=len(dataframe)
  gini_dec=-99999999
  for col in col_list:
    node=dataframe[[col,target_name]]
    unique=node.groupby(col).count().index
    for split_point in unique: #unique value
      left_node,right_node=dataSplit(node,col,split_point)
      if len(left_node)>0 and len(right_node)>0:
        gini_col=gini_cal(left_node[target_name])*(len(left_node)/n)+gini_cal(right_node[target_name])*(len(right_node)/n)
        if (gini_0-gini_col)>gini_dec:
          gini_dec=gini_0-gini_col#decrease of impurity
          best_fea=col
          best_split_point=split_point
    #print(col,split_point,gini_0-gini_col)
  return best_fea,best_split_point,gini_dec
def model_prediction(model,row): #row is a df
  fea=model['fea']
  val=model['val']
  left=model['left']
  right=model['right']
  if row[fea].tolist()[0]<=val:#get the value
    branch=left
  else:
    branch=right
  if ('dict' in str( type(branch) )):
    prediction=model_prediction(branch,row)
  else:
    prediction=branch
  return prediction

实际上,上面的代码还有很大的效率提升的空间,数据集不是很大的情况下,如果选择一个较大的输入参数,例如生成100棵树,就会显著地变慢;同时,将预测结果提交至kaggle进行评测,发现在测试集上的正确率不是很高,比使用sklearn里面相应的包进行预测的正确率(0.77512)要稍低一点 :-(  如果要提升准确率,两个大方向: 构造新的特征;调整现有模型的参数。

这里是抛砖引玉,欢迎大家对我的建模思路和算法的实现方法提出修改意见。

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python中的列表知识点汇总
Apr 14 Python
Python实现各种排序算法的代码示例总结
Dec 11 Python
基于Python实现通过微信搜索功能查看谁把你删除了
Jan 27 Python
Python实现矩阵加法和乘法的方法分析
Dec 19 Python
seek引发的python文件读写的问题及解决
Jul 26 Python
Django 源码WSGI剖析过程详解
Aug 05 Python
python微信公众号开发简单流程实现
Mar 09 Python
Django Serializer HiddenField隐藏字段实例
Mar 31 Python
浅谈Python 参数与变量
Jun 20 Python
浅析python 字典嵌套
Sep 29 Python
python爬虫智能翻页批量下载文件的实例详解
Feb 02 Python
Elasticsearch 基本查询和组合查询
Apr 19 Python
Python决策树和随机森林算法实例详解
Jan 30 #Python
在Python 2.7即将停止支持时,我们为你带来了一份python 3.x迁移指南
Jan 30 #Python
python使用Tkinter实现在线音乐播放器
Jan 30 #Python
Python字典及字典基本操作方法详解
Jan 30 #Python
Python操作MySQL数据库的三种方法总结
Jan 30 #Python
python3.5 tkinter实现页面跳转
Jan 30 #Python
python 连接各类主流数据库的实例代码
Jan 30 #Python
You might like
php基础知识:类与对象(5) static
2006/12/13 PHP
使用PHP获取汉字的拼音(全部与首字母)
2013/06/27 PHP
ThinkPHP中公共函数路径和配置项路径的映射分析
2014/11/22 PHP
JQuery扩展插件Validate 3通过参数设置错误信息
2011/09/05 Javascript
jquery Mobile入门—多页面切换示例学习
2013/01/08 Javascript
在jQuery中 关于json空对象筛选替换
2013/04/15 Javascript
js在输入框屏蔽按键,只能键入数字的示例代码
2014/01/03 Javascript
jQuery中insertAfter()方法用法实例
2015/01/08 Javascript
自己动手写的javascript前端等待控件
2015/10/30 Javascript
jQuery使用正则验证15/18身份证的方法示例
2017/04/27 jQuery
ng-zorro-antd 入门初体验
2018/12/03 Javascript
Python动态加载模块的3种方法
2014/11/22 Python
Python and、or以及and-or语法总结
2015/04/14 Python
python数据结构之图的实现方法
2015/07/08 Python
Python实现的简单排列组合算法示例
2018/07/04 Python
python 重命名轴索引的方法
2018/11/10 Python
浅谈python在提示符下使用open打开文件失败的原因及解决方法
2018/11/30 Python
Flask教程之重定向与错误处理实例分析
2019/08/01 Python
python库matplotlib绘制坐标图
2019/10/18 Python
Python3.7 读取 mp3 音频文件生成波形图效果
2019/11/05 Python
Spring实战之使用util:命名空间简化配置操作示例
2019/12/09 Python
python中tab键是什么意思
2020/06/18 Python
python之语音识别speech模块
2020/09/09 Python
Django项目在pycharm新建的步骤方法
2021/03/02 Python
Html5移动端适配IphoneX等机型的方法
2019/06/25 HTML / CSS
美国手工艺品市场的领导者:Annie’s
2019/04/04 全球购物
应聘编辑职位自荐信范文
2014/01/05 职场文书
母校寄语大全
2014/04/10 职场文书
11.9消防日宣传标语
2014/10/08 职场文书
2015年公民道德宣传日活动总结
2015/03/23 职场文书
实习报告范文之电话客服岗位
2019/07/26 职场文书
创业计划书之外语培训班
2019/11/02 职场文书
Python使用海龟绘图实现贪吃蛇游戏
2021/06/18 Python
Mybatis是这样防止sql注入的
2021/12/06 Java/Android
redis数据一致性的实现示例
2022/03/18 Redis
SQL Server中的游标介绍
2022/05/20 SQL Server