An Introduction to Redis-ML (Part 5) (Redis-ML简介(第5部分))

Redis-ML简介(第5部分)

An Introduction to Redis-ML (Part 5)
原文作者:Tague Griffith
原文地址:https://dzone.com/articles/an-introduction-to-redis-ml-part-five-redis-labs
译者微博:@从流域到海域
译者博客:blog.csdn.net/solo95
本文同样刊载于腾讯云+:https://cloud.tencent.com/developer/article/1029707

Redis-ML简介(第5部分)

在阅读之前,请务必查看第1部分第2部分第3部分第4部分

决策树是用于机器学习中分类和回归问题的预测模型。决策树将一系列规则建模为二叉树。树的内部节点表示分割点(split)或规则,叶子表示分类或值。

树中的每个规则都在数据集的单个特征上运行。如果满足规则的条件,移动到左边的子树; 否则,向右移动。对于分类特征(枚举),规则所使用的测试是特定类别中的成员资格(即规则是测试是否是特定类别的一个成员,译者注)。

对于具有连续值的特征,测试是“小于”或“等于”。要评估数据结点,从根结点开始,通过评估内部节点中的规则遍历树,直到到达叶子节点。叶子节点被标记为返回的决策。下面显示了一个决策的树示例:


来自维基百科决策树学习文章的CART树

可以使用许多不同的算法(递归分区,自顶向下归纳等)来构建决策树,但评估过程总是相同的。为了提高决策树的准确性,通常将它们合并到随机森林中,随机森林使用多个树来对数据结点进行分类,并将多数决策作为最终分类。

为了演示决策树如何工作以及如何在Redis中表示决策树,我们将使用scikit-learn Python包和Redis构建一个泰坦尼克号生存预测器。

1912年4月15日,泰坦尼克号在与冰山相撞后在北大西洋沉没。由于碰撞造成1500多名乘客死亡,成为近代历史上最致命商业领域的海上灾害之一。尽管在灾难中存活包含一些幸运的因素,但从数据来看,某些特殊能力可以让一些旅客群体比其他旅客更有可能生存。

泰坦尼克号的数据集可以在这里找到,它是机器学习中使用的经典数据集。我们用于这篇文章的来自Vanderbilt档案的数据集副本包含了泰坦尼克号上1,309名乘客的记录。记录包括14个不同的域:乘客类别,幸存与否,姓名,性别,年龄,兄弟姐妹/配偶数量,在船上的父母/子女的数量,票号,票价,客舱,登船港口,救生艇,遗体编号,目的地。

在Excel中粗略扫描我们的数据会显示我们的数据集中有很多缺失的数据。缺少的字段会影响我们的结果,因此我们需要在构建决策树之前对数据进行一些清理。我们将使用panda库对数据进行预处理。您可以使用Python包管理器pip(或您的首选包管理器)来安装熊猫库:

pip install panda

使用panda,我们可以快速查看数据中每个记录类的数值:

(这14组数据与上面所说的14个域是一一对应的,译者注)

pclass       1309
survived     1309
name         1309
sex          1309
age          1046
sibsp        1309
parch        1309
ticket       1309
fare         1308
cabin         295
embarked     1307
boat          486
body          121
home.dest     745

由于cabin,boat , body和home.dest记录有大量的缺失记录,我们只是简单地将它们从数据集中删除。我们也将放弃ticket域,因为它没有什么预测价值。对于我们的预测,我们最终将建立一个有乘客类别(pclass),生存状态(survived),性别,年龄,兄弟姐妹/配偶(sibsp)数量,船上父母/孩子数量,票价,和登船港口(”embarked”)等记录的特征集(还剩下8个域,作者删除了6个没有预测价值的域,译者注)。即使删除了人数很少的列,仍然有几行缺少数据,为了简单起见,我们将从我们的数据集中删除这些乘客记录。

清理数据的初始阶段是使用以下代码完成的:

import pandas as pd  # load data from excel orig_df = pd.read_excel('titanic3.xls', 'titanic3', index_col=None)
#删除我们不打算处理的列,删除丢失数据的行
df = orig_df.drop(["name", "ticket", "body", "cabin", "boat", "home.dest"], axis=1) df = df.dropna()

我们需要对数据执行的最终预处理是使用整型常量对分类数据进行编码。pclass和survived列已被编码为整型常量,但sex列记录的是字符串值的男性或女性,embarked使用字母代码来表示每个端口。scikit软件包提供了执行数据编码预处理子包中的实用程序。

清理数据的第二阶段,转换非整数编码的分类特征,是通过以下代码完成的:

from sklearn import preprocessing 
# convert enumerated columns (sex,) 

encoder = preprocessing.LabelEncoder() 
df.sex = encoder.fit_transform(df.sex) 
df.embarked = encoder.fit_transform(df.embarked)

我们已经清理过了我们的数据,现在可以计算由乘客类别(pclass)和性别分组而来的几个特征列的平均值。

survived age sibsp parch fare pclass sex 1 female 0.961832 36.839695 0.564885 0.511450 112.485402 male 0.350993 41.029250 0.403974 0.331126 74.818213 2 female 0.893204 27.499191 0.514563 0.669903 23.267395 male 0.145570 30.815401 0.354430 0.208861 20.934335 3 female 0.473684 22.185307 0.736842 0.796053 14.655758 male 0.169540 25.863027 0.488506 0.287356 12.103374

注意建立在乘客类别基础上男女之间存活率的显著差异。我们用于构建决策树的算法将会发现这些统计差异,并使用它们来选择要分割的特征。

建立决策树

我们将使用scikit-learn在我们的数据上构建决策树分类器。我们首先将我们清理过的数据分成训练和测试集。使用下面的代码,我们从特征集中分离出我们数据的标签列(survived ),并保留我们数据的最后20条记录为测试集。

X = df.drop(['survived'], axis=1).values 
Y = df['survived'].values 
X_train = X[:-20] 
X_test = X[-20:] 
Y_train = Y[:-20] 
Y_test = Y[-20:]

一旦我们有了我们的训练和测试集,我们就可以创建一个最大深度为10的决策树。

#创建真实的分类器深度= 10
# Create the real classifier 
depth=10 
cl_tree = tree.DecisionTreeClassifier(max_depth=10, random_state=0) 
cl_tree.fit(X_train, Y_train)

我们的深度为10的决策树很难在博客文章中实现可视化,所以为了可视化决策树的结构,我们创建了第二棵树,并将树的深度限制为3.下图显示了决策树的结构,由分类器学习而来:

Titanic decision tree learned by scikit
Titanic decision tree learned by scikit

加载Redis预测器

Redis-ML模块提供了两个用于处理随机森林的命令:ML.FOREST.ADD命令在森林的上下文中创建决策树,ML.FOREST.RUN命令使用随机森林评估数据节点。这些ML.FOREST 命令具有以下语法:

ML.FOREST.ADD key tree path ((NUMERIC|CATEGORIC) attr val | LEAF val [STATS]) [...] 
ML.FOREST.RUN key sample (CLASSIFICATION|REGRESSION)

Redis-ML中的每个决策树都必须使用单个ML.FOREST.ADD命令加载。该ML.FOREST.ADD命令包含一个Redis密钥,后跟一个整数的树ID,后跟节点说明。节点说明由路径,序列组成。(root),l和r,表示树中节点的路径。内部节点是分割点或规则节点,并使用NUMERIC或CATEGORIC关键字来指定规则类型,要测试的属性以及要分割的阈。对于NUMERIC节点,该属性是针对阈值进行测试的,如果小于或等于该值,则采用左侧路径; 否则,就采取右侧。对于CATEGORIC节点,测试是平等的。相等的值走左边的路径,不相等的值走右边的路径。

scikit-learn中的决策树算法将分类属性视为数字,所以当我们在Redis中表示树时,我们将只使用NUMERIC节点类型。要将scikit树加载到Redis中,我们需要实现遍历树的惯例。下面的代码执行scikit决策树的预遍历来生成一个 ML.FOREST.ADD 命令(因为我们只有一棵树,我们生成一个只有一棵树的森林)。

# scikit represents decision trees using a set of arrays,
# create references to make the arrays easy to access

the_tree = cl_tree

t_nodes = the_tree.tree_.node_count

t_left = the_tree.tree_.children_left

t_right = the_tree.tree_.children_right

t_feature = the_tree.tree_.feature

t_threshold = the_tree.tree_.threshold

t_value = the_tree.tree_.value

feature_names = df.drop(['survived'], axis=1).columns.values

# create a buffer to build up our command

forrest_cmd = StringIO()
forrest_cmd.write("ML.FOREST.ADD titanic:tree 0 ")

# Traverse the tree starting with the root and a path of "."

stack = [ (0, ".") ]

while len(stack) > 0:
    node_id, path = stack.pop()

    # splitter node -- must have 2 children (pre-order traversal)

    if (t_left[node_id] != t_right[node_id]):
        stack.append((t_right[node_id], path + "r")) 
        stack.append((t_left[node_id], path + "l"))
        cmd = "{} NUMERIC {} {} ".format(path, feature_names[t_feature[node_id]], t_threshold[node_id])
        forrest_cmd.write(cmd)
    else:
        cmd = "{} LEAF {} ".format(path, np.argmax(t_value[node_id]))
        forrest_cmd.write(cmd)

# execute command in Redis

r = redis.StrictRedis('localhost', 6379)
r.execute_command(forrest_cmd.getvalue())

比较结果

将决策树加载到Redis中,我们可以创建两个向量来比较Redis的预测和scikit-learn的预测(结果):

#generate a vector of scikit-learn predictors 

s_pred = cl_tree.predict(X_test)

# generate a vector of Redis predictions

r_pred = np.full(len(X_test), -1, dtype=int)

for i, x in enumerate(X_test):
    cmd = "ML.FOREST.RUN titanic:tree "

    # iterate over each feature in the test record to build up the 

    # feature:value pairs

    for j, x_val in enumerate(x):
        cmd += "{}:{},".format(feature_names[j], x_val)  
    cmd = cmd[:-1]
    r_pred[i] = int(r.execute_command(cmd))

要使用该ML.FOREST.RUN 命令,我们必须生成一个由逗号分隔的:对组成的list。一个矢量的部分是一个字符串特征名称,必须与该ML.FOREST.ADD 命令中使用的特征名称相对应。

将r_pred和s_pred预测值与实际标签值进行比较:

Y_test: [0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0]

r_pred: [1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]

s_pred: [1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]

Redis的预测与scikit-learn软件包的预测相同,包括测试第0项和第14项的错误分类。

一个乘客的生存机会与(乘客)类别和性别密切相关,所以会有几个令人惊讶的个案,他们实际上死亡的可能性很大。调查这些异常值中的一部分会引出这个命运的旅程中引人入胜的故事。有很多在线资源讲述泰坦尼克号乘客和机组人员的故事,向我们展示了数据背后的人们。我鼓励你去调查一些错误分类的人,然后了解他们的故事。

在下一篇也是最后一篇文章中,我们将把所有东西都捆绑在一起,并将这个介绍打包到Redis-ML中。

posted @ 2018-01-26 16:42  从流域到海域  阅读(66)  评论(0编辑  收藏  举报