机器学习与Python - 算法

机器学习算法可大致分为两类 -  监督无监督.本章将详细讨论它们.

监督学习

此算法由目标或结果或因变量组成,该变量是从给定的一组中预测的.预测变量或自变量.使用这些变量集,我们生成一个将输入变量映射到所需输出变量的函数.培训过程一直持续到模型达到培训数据所需的准确度水平.

监督学习的例子 - 回归,决策树,随机森林,KNN,Logistic回归等.

无监督学习

在此算法中,没有目标或结果或因变量来预测或估计.它用于将给定数据集聚类到不同的组中,广泛用于将客户划分为不同的组以进行特定干预. Apriori算法和K-means是无监督学习的一些例子.

强化学习

使用此算法,机器经过培训,可以使决定.在这里,算法通过使用试错法和反馈方法不断训练自己.这台机器从过去的经验中学习,并试图捕捉最好的知识,以做出准确的商业决策.

马尔可夫决策过程是强化学习的一个例子.

通用机器学习算法列表

以下是几乎可以应用于任何数据问题的常用机器学习算法列表 :

  • 线性回归

  • Logistic回归

  • 决策树

  • SVM

  • Naive Bayes

  • KNN

  • K-Means

  • 随机森林

  • 维度降低算法

  • Gradient Boosting算法,如GBM,XGBoost,LightGBM和CatBoost

本节详细讨论每一个 :

线性回归

线性回归用于估算基于conti的现实世界价值,如房屋成本,通话次数,总销售额等核变量.在这里,我们通过拟合最佳线来建立依赖变量和自变量之间的关系.这条最佳拟合线称为回归线,用线性方程 Y = a * X + b 表示.

在这个等式中 :

Y  - 从属变量

a  - 斜率

X  - 自变量

b  - 截距

这些系数 a b 是基于最小化数据点之间距离的平方差和回归得出的line.

示例

理解线性回归的最佳方法是考虑一个例子.假设我们被要求按照他们的权重递增顺序安排学生上课.通过观察学生并在视觉上分析他们的高度和构建,我们可以根据需要使用这些参数(高度和构建)的组合来安排它们.这是现实世界的线性回归示例.我们已经发现高度和构建通过关系与权重相关,看起来类似于上面的等式.

线性回归的类型

线性回归主要有两种类型 -  简单线性回归多元线性回归.简单线性回归的特征在于一个独立变量,而多元线性回归的特征在于多个独立变量.在找到最佳拟合线时,您可以拟合多项式或曲线回归.您可以为此目的使用以下代码.

import matplotlib.pyplot as plt
plt.scatter(X, Y)

yfit = [a + b * xi for xi in X]
plt.plot(X, yfit)

构建线性回归器

回归是估计输入数据和连续值输出数据之间关系的过程.这些数据通常采用实数形式,我们的目标是估计控制从输入到输出的映射的基础函数.

考虑输入和输出之间的映射显示 : 去;

1 --> 2
3 --> 6
4.3 --> 8.6
7.1 --> 14.2

通过分析模式,您可以轻松估算输入和输出之间的关系.我们可以观察到输出是每种情况下输入值的两倍,因此转换将是 :   f(x)= 2x

线性回归是指使用输入变量的线性组合估计相关函数.前面的示例是一个由一个输入变量和一个输出变量组成的示例.

线性回归的目标是提取将输入变量与输出变量相关联的相关线性模型.这旨在使用线性函数最小化实际输出和预测输出之间的差的平方和.这种方法称为普通最小二乘法.你可以假设那里的弯曲线更适合这些点,但线性回归不允许这样做.线性回归的主要优点是它并不复杂.您也可以在非线性回归中找到更准确的模型,但它们会更慢.这里模型尝试使用直线近似输入数据点.

让我们了解如何在Python中构建线性回归模型.

请考虑为您提供了一个名为 data_singlevar.txt 的数据文件.它包含以逗号分隔的行,其中第一个元素是输入值,第二个元素是与此输入值对应的输出值.你应该使用它作为输入参数 :

假设一组点的最佳拟合线为 :

y = a + b * x

其中b =(sum(xi * yi) -  n * xbar * ybar)/sum(( xi  -  xbar)^ 2)

a = ybar  -  b * xbar

使用以下用于此目的的代码 :

# sample points
X = [0, 6, 11, 14, 22]
Y = [1, 7, 12, 15, 21]

# solve for a and b
def best_fit(X, Y):
   xbar = sum(X)/len(X)
   ybar = sum(Y)/len(Y)
   n = len(X) # or len(Y)

   numer = sum([xi*yi for xi,yi in zip(X, Y)]) - n * xbar * ybar
   denum = sum([xi**2 for xi in X]) - n * xbar**2

   b = numer / denum
   a = ybar - b * xbar

   print('best fit line:\ny = {:.2f} + {:.2f}x'.format(a, b))
   
   return a, b

# solution
a, b = best_fit(X, Y)
#best fit line:
#y = 0.80 + 0.92x

# plot points and fit line
import matplotlib.pyplot as plt
plt.scatter(X, Y)
yfit = [a + b * xi for xi in X]
plt.plot(X, yfit)
plt.show()
best fit line:
y = 1.48 + 0.92x

如果运行上面的代码,您可以观察输出图形

请注意,此示例仅使用糖尿病数据集的第一个特征,以说明两个该回归技术的维度图.在图中可以看到直线,显示线性回归如何尝试绘制直线,以最大程度地最小化数据集中观察到的响应之间的残差平方和线性近似预测的响应.

您可以使用下面显示的程序代码计算系数,剩余的平方和和方差分数;

import matplotlib.pyplot as plt
import numpy as np
from sklearn import datasets, linear_model
from sklearn.metrics import mean_squared_error, r2_score
# Load the diabetes dataset
diabetes = datasets.load_diabetes()
# Use only one feature
diabetes_X = diabetes.data[:, np.newaxis, 2]
# Split the data into training/testing sets
diabetes_X_train = diabetes_X[:-30]
diabetes_X_test = diabetes_X[-30:]

# Split the targets into training/testing sets
diabetes_y_train = diabetes.target[:-30]
diabetes_y_test = diabetes.target[-30:]
# Create linear regression object
regr = linear_model.LinearRegression()
# Train the model using the training sets
regr.fit(diabetes_X_train, diabetes_y_train)
# Make predictions using the testing set
diabetes_y_pred = regr.predict(diabetes_X_test)
# The coefficients
print('Coefficients: \n', regr.coef_)

# The mean squared error
print("Mean squared error: %.2f" 
      % mean_squared_error(diabetes_y_test, diabetes_y_pred))
# Explained variance score: 1 is perfect prediction
print('Variance score: %.2f' % r2_score(diabetes_y_test, diabetes_y_pred))

# Plot outputs
plt.scatter(diabetes_X_test, diabetes_y_test, color = 'black')
plt.plot(diabetes_X_test, diabetes_y_pred, color = 'blue', linewidth = 3)
plt.xticks(())
plt.yticks(())
plt.show()

执行后,您可以观察到以下输出te上面给出的代码 :

Automatically created module for IPython interactive environment
('Coefficients: \n', array([ 941.43097333]))
Mean squared error: 3035.06
Variance score: 0.41

Logistic回归

逻辑回归是机器从统计学习中借用的另一种技术.它是二元分类问题的首选方法,即两个类值的问题.

这是一个分类算法,而不是名称所示的回归算法.它用于根据给定的自变量集估计离散值或值,如0/1,Y/N,T/F.它通过将数据拟合到logit函数来预测事件发生的概率.因此,它也被称为 logit回归.因为,它预测概率,其输出值介于0和1之间.

示例

让我们通过一个简单的例子来理解这个算法./p>

假设有一个难题要解决,只有2个结果场景 - 要么有解决方案要么没有解决方案.现在假设,我们有各种各样的谜题来测试一个人擅长哪些科目.结果可能是这样的 - 如果给出三角学谜题,一个人可能有80%的可能解决它.另一方面,如果给出地理谜题,该人可能只有20%可能解决它.这是Logistic回归有助于解决的问题.根据数学,结果的对数几率表示为预测变量的线性组合.

odds = p/ (1-p) = probability of event occurrence / probability of not event occurrence

ln(odds) = ln(p/(1-p)) ; ln is the logarithm to the base ‘e’.
logit(p) = ln(p/(1-p)) = b0+b1X1+b2X2+b3X3....+bkXk

注意,在上面 p 中是存在感兴趣特征的概率.它选择的参数最大化了观察样本值的可能性,而不是最小化误差平方和(如普通回归).

注意记录日志是最好的数学之一复制阶梯函数的方法.

在进行逻辑回归和减去时,以下几点值得注意;

  • 它类似于回归,其目的是找到权衡每个输入变量的系数的值.

  • 与线性回归不同,使用称为逻辑函数的非线性函数找到输出的预测.

  • 逻辑函数看起来像一个大的'S' '并且会将任何值更改为0到1的范围.这很有用,因为我们可以将规则应用于逻辑函数的输出,以将值分配给0和1并预测类值.

  • 学习逻辑回归模型的方式,由它做出的预测也可以用作属于0级或1级的给定数据实例的概率.这对于需要为预测提供更多推理的问题非常有用.

  • 与线性回归一样,当删除输出变量的不相关属性并删除类似属性时,逻辑回归效果更好.

以下代码显示了如何使用逻辑曲线开发逻辑表达式的绘图,其中合成数据集被分类为值0或1,即第一或第二类.

import numpy as np
import matplotlib.pyplot as plt
from sklearn import linear_model
# This is the test set, it's a straight line with some Gaussian noise
xmin, xmax = -10, 10
n_samples = 100
np.random.seed(0)
X = np.random.normal(size = n_samples)
y = (X > 0).astype(np.float)
X[X > 0] *= 4
X += .3 * np.random.normal(size = n_samples)
X = X[:, np.newaxis]

# run the classifier
clf = linear_model.LogisticRegression(C=1e5)
clf.fit(X, y)

# and plot the result
plt.figure(1, figsize = (4, 3))
plt.clf()
plt.scatter(X.ravel(), y, color='black', zorder=20)
X_test = np.linspace(-10, 10, 300)
def model(x):
return 1 / (1 + np.exp(-x))
loss = model(X_test * clf.coef_ + clf.intercept_).ravel()
plt.plot(X_test, loss, color='blue', linewidth=3)
ols = linear_model.LinearRegression()
ols.fit(X, y)
plt.plot(X_test, ols.coef_ * X_test + ols.intercept_, linewidth=1)
plt.axhline(.5, color='.5')
plt.ylabel('y')
plt.xlabel('X')
plt.xticks(range(-10, 10))
plt.yticks([0, 0.5, 1])
plt.ylim(-.25, 1.25)
plt.xlim(-4, 10)
plt.legend(('Logistic Regression Model', 'Linear Regression Model'),
loc="lower right", fontsize='small')
plt.show()

决策树算法

这是一种主要使用的监督学习算法对于分类问题.它适用于离散和连续因变量.在该算法中,我们将总体分成两个或更多个同类集.这是基于最重要的属性来完成的,以尽可能不同的组.

决策树广泛用于机器学习,包括分类和回归.在决策分析中,决策树用于在视觉上和明确地表示决策和决策.它使用树状的决策模型.

绘制决策树,其根位于顶部,分支位于底部.在图像中,粗体文本表示条件/内部节点,树基于该节点/内部节点分割成分支/边缘.不再拆分的分支端是决策/叶子.

示例

考虑使用泰坦尼克数据集来预测是否乘客是否会幸存.下面的模型使用数据集中的3个特征/属性/列,即性别,年龄和sibsp(没有配偶/子女).在这种情况下,乘客是否死亡或幸存,分别表示为红色和绿色文本.

在一些例子中,我们看到人口根据多个属性被分类到不同的组中,以识别"他们是否做某事".为了将人口分成不同的异构群体,它使用各种技术,如基尼,信息增益,卡方,熵等.

理解决策树如何工作的最佳方法是玩Jezzball  - 来自微软的经典游戏.基本上,在这个游戏中,你有一个移动墙壁的房间,你需要创建墙壁,以便在没有球的情况下清除最大区域.

所以,每次你拆分房间时一堵墙,你试图在同一个房间里创造两个不同的人口.决策树以非常类似的方式工作,将人口分成尽可能不同的群体.

观察下面给出的代码及其输出 :

#Starting implementation
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
%matplotlib inline
from sklearn import tree
df = pd.read_csv("iris_df.csv")
df.columns = ["X1", "X2", "X3","X4", "Y"]
df.head()

#implementation
from sklearn.cross_validation import train_test_split
decision = tree.DecisionTreeClassifier(criterion="gini")
X = df.values[:, 0:4]
Y = df.values[:, 4]
trainX, testX, trainY, testY = train_test_split( X, Y, test_size = 0.3)
decision.fit(trainX, trainY)
print("Accuracy: \n", decision.score(testX, testY))

#Visualisation
from sklearn.externals.six import StringIO
from IPython.display import Image
import pydotplus as pydot
dot_data = StringIO()
tree.export_graphviz(decision, out_file=dot_data)
graph = pydot.graph_from_dot_data(dot_data.getvalue())
Image(graph.create_png())

输出

Accuracy:
0.955555555556

示例

这里我们使用钞票认证数据集来了解准确性.

# Using the Bank Note dataset
from random import seed
from random import randrange
from csv import reader

# Loading a CSV file
filename ='data_banknote_authentication.csv'
def load_csv(filename):
   file = open(filename, "rb")
   lines = reader(file)
   dataset = list(lines)
   return dataset

# Convert string column to float
def str_column_to_float(dataset, column):
   for row in dataset:
      row[column] = float(row[column].strip())

# Split a dataset into k folds
def cross_validation_split(dataset, n_folds):
   dataset_split = list()
   dataset_copy = list(dataset)
   fold_size = int(len(dataset) / n_folds)
   for i in range(n_folds):
      fold = list()
      while len(fold) < fold_size:
         index = randrange(len(dataset_copy))
         fold.append(dataset_copy.pop(index))
      dataset_split.append(fold)
   return dataset_split

# Calculating accuracy percentage
def accuracy_metric(actual, predicted):
correct = 0
for i in range(len(actual)):
if actual[i] == predicted[i]:
correct += 1
return correct / float(len(actual)) * 100.0

# Evaluating an algorithm using a cross validation split
def evaluate_algorithm(dataset, algorithm, n_folds, *args):
   folds = cross_validation_split(dataset, n_folds)
   scores = list()
   for fold in folds:
      train_set = list(folds)
      train_set.remove(fold)
      train_set = sum(train_set, [])
      test_set = list()
      for row in fold:
         row_copy = list(row)
         test_set.append(row_copy)
         row_copy[-1] = None
      predicted = algorithm(train_set, test_set, *args)
      actual = [row[-1] for row in fold]
      accuracy = accuracy_metric(actual, predicted)
      scores.append(accuracy)
   return scores

# Splitting a dataset based on an attribute and an attribute value
def test_split(index, value, dataset):
   left, right = list(), list()
   for row in dataset:
      if row[index] < value:
         left.append(row)
      else:
         right.append(row)
   return left, right
   
# Calculating the Gini index for a split dataset
def gini_index(groups, classes):
   # count all samples at split point
   n_instances = float(sum([len(group) for group in groups]))
   # sum weighted Gini index for each group
   gini = 0.0
   for group in groups:
      size = float(len(group))
      # avoid divide by zero
      if size == 0:
         continue
      score = 0.0
      # score the group based on the score for each class
      for class_val in classes:
         p = [row[-1] for row in group].count(class_val) / size
      score += p * p
      # weight the group score by its relative size
      gini += (1.0 - score) * (size / n_instances)
return gini

# Selecting the best split point for a dataset
def get_split(dataset):
   class_values = list(set(row[-1] for row in dataset))
   b_index, b_value, b_score, b_groups = 999, 999, 999, None
   for index in range(len(dataset[0])-1):
      for row in dataset:
         groups = test_split(index, row[index], dataset)
         gini = gini_index(groups, class_values)
         if gini < b_score:
            b_index, b_value, b_score, b_groups = index, 
row[index], gini, groups
   return {'index':b_index, 'value':b_value, 'groups':b_groups}
   
# Creating a terminal node value
def to_terminal(group):
outcomes = [row[-1] for row in group]
return max(set(outcomes), key=outcomes.count)

# Creating child splits for a node or make terminal
def split(node, max_depth, min_size, depth):
   left, right = node['groups']
   del(node['groups'])

   # check for a no split
   if not left or not right:
      node['left'] = node['right'] = to_terminal(left + right)
      return
      
   # check for max depth
   if depth >= max_depth:
      node['left'], node['right'] = to_terminal(left), to_terminal(right)
      return

   # process left child
   if len(left) <= min_size:
      node['left'] = to_terminal(left)
   else:
      node['left'] = get_split(left)
      split(node['left'], max_depth, min_size, depth+1)
   # process right child
   if len(right) <= min_size:
      node['right'] = to_terminal(right)
   else:
      node['right'] = get_split(right)
      split(node['right'], max_depth, min_size, depth+1)
   
# Building a decision tree
def build_tree(train, max_depth, min_size):
   root = get_split(train)
   split(root, max_depth, min_size, 1)
   return root
   
# Making a prediction with a decision tree
   def predict(node, row):
   if row[node['index']] < node['value']:
      if isinstance(node['left'], dict):
         return predict(node['left'], row)
      else:
         return node['left']
   else:
      if isinstance(node['right'], dict):
         return predict(node['right'], row)
      else:
         return node['right']
         
# Classification and Regression Tree Algorithm
def decision_tree(train, test, max_depth, min_size):
   tree = build_tree(train, max_depth, min_size)
   predictions = list()
   for row in test:
      prediction = predict(tree, row)
      predictions.append(prediction)
   return(predictions)
   
# Testing the Bank Note dataset
seed(1)
# load and prepare data
filename = 'data_banknote_authentication.csv'
dataset = load_csv(filename)

# convert string attributes to integers
for i in range(len(dataset[0])):
   str_column_to_float(dataset, i)
   
# evaluate algorithm
n_folds = 5
max_depth = 5
min_size = 10
scores = evaluate_algorithm(dataset, decision_tree, n_folds, max_depth, min_size)
print('Scores: %s' % scores)
print('Mean Accuracy: %.3f%%' % (sum(scores)/float(len(scores))))

当您执行上面给出的代码时,您可以观察输出如下 :

Scores: [95.62043795620438, 97.8102189781022, 97.8102189781022, 
94.52554744525547, 98.90510948905109]

Mean Accuracy: 96.934%

支持向量机(SVM)

支持向量机,也称为SVM,是众所周知的监督分类算法,可以分离不同类别的数据.

通过优化线条对这些向量进行分类,使每组中最近的点距离彼此最远.

此向量默认是线性的,是一个因此通常可视化为线性.但是,如果内核类型从默认类型"高斯"或线性变化,矢量也可以采用非线性形式.

这是一种分类方法,我们在数据项作为n维空间中的一个点(其中n是要素的数量),每个要素的值是特定坐标的值.

例如,如果我们只有在个体的高度头发长度这两个特征中,我们应该首先在二维空间中绘制这两个变量,其中每个点有两个坐标称为支持向量.

现在,找到某条线在两个不同分类的数据组之间分割数据.这将是这样的线,使得距离两组中每个组中最近点的距离最远.

在上面的例子中,将数据分成两个不同分类的组的线是黑线,因为两个最近的点距离线最远.这一行是我们的分类器.然后,根据测试数据在线路两侧的位置,我们可以对新数据进行分类.

from sklearn import svm
df = pd.read_csv('iris_df.csv')
df.columns = ['X4', 'X3', 'X1', 'X2', 'Y']
df = df.drop(['X4', 'X3'], 1)
df.head()
from sklearn.cross_validation import train_test_split
support = svm.SVC()
X = df.values[:, 0:2]
Y = df.values[:, 2]
trainX, testX, trainY, testY = train_test_split( X, Y, test_size = 0.3)
sns.set_context('notebook', font_scale=1.1)
sns.set_style('ticks')
sns.lmplot('X1','X2', scatter=True, fit_reg=False, data=df, hue='Y')
plt.ylabel('X2')
plt.xlabel('X1')

当您运行上面显示的代码和减号时,您可以注意到以下输出和绘图;

 
 Text(0.5,27.256,'X1')