您的位置:

python手写识别数字源码的简单介绍

本文目录一览:

怎么用python识别数字

str = input("please input the number:")

if str.isdigit(): #为True,表示输入的所有字符都是数字.

if str.isalnum()  #为True,表示输入的字符中有数字.

str.isalpha()     #为True,表示输入的所有字符都是字母.

python svm 怎么训练模型

支持向量机SVM(Support Vector Machine)是有监督的分类预测模型,本篇文章使用机器学习库scikit-learn中的手写数字数据集介绍使用Python对SVM模型进行训练并对手写数字进行识别的过程。

准备工作

手写数字识别的原理是将数字的图片分割为8X8的灰度值矩阵,将这64个灰度值作为每个数字的训练集对模型进行训练。手写数字所对应的真实数字作为分类结果。在机器学习sklearn库中已经包含了不同数字的8X8灰度值矩阵,因此我们首先导入sklearn库自带的datasets数据集。然后是交叉验证库,SVM分类算法库,绘制图表库等。

12345678910

#导入自带数据集from sklearn import datasets#导入交叉验证库from sklearn import cross_validation#导入SVM分类算法库from sklearn import svm#导入图表库import matplotlib.pyplot as plt#生成预测结果准确率的混淆矩阵from sklearn import metrics

读取并查看数字矩阵

从sklearn库自带的datasets数据集中读取数字的8X8矩阵信息并赋值给digits。

12

#读取自带数据集并赋值给digitsdigits = datasets.load_digits()

查看其中的数字9可以发现,手写的数字9以64个灰度值保存。从下面的8×8矩阵中很难看出这是数字9。

12

#查看数据集中数字9的矩阵digits.data[9]

以灰度值的方式输出手写数字9的图像,可以看出个大概轮廓。这就是经过切割并以灰度保存的手写数字9。它所对应的64个灰度值就是模型的训练集,而真实的数字9是目标分类。我们的模型所要做的就是在已知64个灰度值与每个数字对应关系的情况下,通过对模型进行训练来对新的手写数字对应的真实数字进行分类。

1234

#绘制图表查看数据集中数字9的图像plt.imshow(digits.images[9], cmap=plt.cm.gray_r, interpolation='nearest')plt.title('digits.target[9]')plt.show()

设置模型的特征X和预测目标Y

查看数据集中的分类目标,可以看到一共有10个分类,分布为0-9。我们将这个分类目标赋值给Y,作为模型的预测目标。

12

#数据集中的目标分类digits.target

12

#将数据集中的目标赋给YY=digits.target

手写数字的64个灰度值作为特征赋值给X,这里需要说明的是64个灰度值是以8×8矩阵的形式保持的,因此我们需要使用reshape函数重新调整矩阵的行列数。这里也就是将8×8的两维数据转换为64×1的一维数据。

123

#使用reshape函数对矩阵进行转换,并赋值给Xn_samples = len(digits.images)X = digits.images.reshape((n_samples, 64))

查看特征值X和预测目标Y的行数,共有1797行,也就是说数据集中共有1797个手写数字的图像,64列是经过我们转化后的灰度值。

12

#查看X和Y的行数X.shape,Y.shape

将数据分割为训练集和测试集

将1797个手写数字的灰度值采用随机抽样的方法分割为训练集和测试集,其中训练集为60%,测试集为40%。

12

#随机抽取生成训练集和测试集,其中训练集的比例为60%,测试集40%X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, Y, test_size=0.4, random_state=0)

查看分割后的测试集数据,共有1078条数据。这些数据将用来训练SVM模型。

12

#查看训练集的行数X_train.shape,y_train.shape

对SVM模型进行训练

将训练集数据X_train和y_train代入到SVM模型中,对模型进行训练。下面是具体的代码和结果。

12

#生成SVM分类模型clf = svm.SVC(gamma=0.001)

12

#使用训练集对svm分类模型进行训练clf.fit(X_train, y_train)

使用测试集测对模型进行测试

使用测试集数据X_test和y_test对训练后的SVM模型进行检验,模型对手写数字分类的准确率为99.3%。这是非常高的准确率。那么是否真的这么靠谱吗?下面我们来单独测试下。

12

#使用测试集衡量分类模型准确率clf.score(X_test, y_test)

我们使用测试集的特征X,也就是每个手写数字的64个灰度值代入到模型中,让SVM模型进行分类。

12

#对测试集数据进行预测predicted=clf.predict(X_test)

然后查看前20个手写数字的分类结果,也就是手写数字所对应的真实数字。下面是具体的分类结果。

12

#查看前20个测试集的预测结果predicted[:20]

再查看训练集中前20个分类结果,也就是真实数字的情况,并将之前的分类结果与测试集的真实结果进行对比。

12

#查看测试集中的真实结果expected=y_test

以下是测试集中前20个真实数字的结果,与前面SVM模型的分类结果对比,前20个结果是一致的。

12

#查看测试集中前20个真实结果expected[:20]

使用混淆矩阵来看下SVM模型对所有测试集数据的预测与真实结果的准确率情况,下面是一个10X10的矩阵,左上角第一行第一个数字60表示实际为0,SVM模型也预测为0的个数,第一行第二个数字表示实际为0,SVM模型预测为1的数字。第二行第二个数字73表示实际为1,SVM模型也预测为1的个数。

12

#生成准确率的混淆矩阵(Confusion matrix)metrics.confusion_matrix(expected, predicted)

从混淆矩阵中可以看到,大部分的数字SVM的分类和预测都是正确的,但也有个别的数字分类错误,例如真实的数字2,SVM模型有一次错误的分类为1,还有一次错误分类为7。

谁可以提供Python环境中用KNN手写识别数据MNIST的读取代码

其实就是python怎么读取binnary

file

mnist的结构如下,选取train-images

TRAINING

SET

IMAGE

FILE

(train-images-idx3-ubyte):

[offset]

[type]

[value]

[description]

0000

32

bit

integer

0x00000803(2051)

magic

number

0004

32

bit

integer

60000

number

of

images

0008

32

bit

integer

28

number

of

rows

0012

32

bit

integer

28

number

of

columns

0016

unsigned

byte

??

pixel

0017

unsigned

byte

??

pixel

........

xxxx

unsigned

byte

??

pixel

也就是之前我们要读取4个

32

bit

integer

试过很多方法,觉得最方便的,至少对我来说还是使用

struct.unpack_from()

filename

=

'train-images.idx3-ubyte'binfile

=

open(filename

,

'rb')buf

=

binfile.read()

先使用二进制方式把文件都读进来

index

=

0magic,

numImages

,

numRows

,

numColumns

=

struct.unpack_from('IIII'

,

buf

,

index)index

+=

struct.calcsize('IIII')

然后使用struc.unpack_from

'IIII'是说使用大端法读取4个unsinged

int32

然后读取一个图片测试是否读取成功

im

=

struct.unpack_from('784B'

,buf,

index)index

+=

struct.calcsize('784B')

im

=

np.array(im)im

=

im.reshape(28,28)

fig

=

plt.figure()plotwindow

=

fig.add_subplot(111)plt.imshow(im

,

cmap='gray')plt.show()

'784B'的意思就是用大端法读取784个unsigned

byte

完整代码如下

import

numpy

as

npimport

structimport

matplotlib.pyplot

as

plt

filename

=

'train-images.idx3-ubyte'binfile

=

open(filename

,

'rb')buf

=

binfile.read()

index

=

0magic,

numImages

,

numRows

,

numColumns

=

struct.unpack_from('IIII'

,

buf

,

index)index

+=

struct.calcsize('IIII')

im

=

struct.unpack_from('784B'

,buf,

index)index

+=

struct.calcsize('784B')

im

=

np.array(im)im

=

im.reshape(28,28)

fig

=

plt.figure()plotwindow

=

fig.add_subplot(111)plt.imshow(im

,

cmap='gray')plt.show()

只是为了测试是否成功所以只读了一张图片

对于一个学完python编程基础知识想做出一个手写汉字识别的项目出来,需要学习什么?

对于汉字识别你可以考虑一下baidu aip

pip install baidu-aip

每人每天有500次识别的机会。

如何利用Python做简单的验证码识别

1   摘要

验证码是目前互联网上非常常见也是非常重要的一个事物,充当着很多系统的 防火墙 功能,但是随时OCR技术的发展,验证码暴露出来的安全问题也越来越严峻。本文介绍了一套字符验证码识别的完整流程,对于验证码安全和OCR识别技术都有一定的借鉴意义。

然后经过了一年的时间,笔者又研究和get到了一种更强大的基于CNN卷积神经网络的直接端到端的验证识别技术(文章不是我的,然后我把源码整理了下,介绍和源码在这里面):

基于python语言的tensorflow的‘端到端’的字符型验证码识别源码整理(github源码分享)

2   关键词

关键词:安全,字符图片,验证码识别,OCR,Python,SVM,PIL

3   免责声明

本文研究所用素材来自于某旧Web框架的网站 完全对外公开 的公共图片资源。

本文只做了该网站对外公开的公共图片资源进行了爬取, 并未越权 做任何多余操作。

本文在书写相关报告的时候已经 隐去 漏洞网站的身份信息。

本文作者 已经通知 网站相关人员此系统漏洞,并积极向新系统转移。

本报告的主要目的也仅是用于 OCR交流学习 和引起大家对 验证安全的警觉 。

4   引言

关于验证码的非技术部分的介绍,可以参考以前写的一篇科普类的文章:

互联网安全防火墙(1)--网络验证码的科普

里面对验证码的种类,使用场景,作用,主要的识别技术等等进行了讲解,然而并没有涉及到任何技术内容。本章内容则作为它的 技术补充 来给出相应的识别的解决方案,让读者对验证码的功能及安全性问题有更深刻的认识。

5   基本工具

要达到本文的目的,只需要简单的编程知识即可,因为现在的机器学习领域的蓬勃发展,已经有很多封装好的开源解决方案来进行机器学习。普通程序员已经不需要了解复杂的数学原理,即可以实现对这些工具的应用了。

主要开发环境:

python3.5

python SDK版本

PIL

图片处理库

libsvm

开源的svm机器学习库

关于环境的安装,不是本文的重点,故略去。

6   基本流程

一般情况下,对于字符型验证码的识别流程如下:

准备原始图片素材

图片预处理

图片字符切割

图片尺寸归一化

图片字符标记

字符图片特征提取

生成特征和标记对应的训练数据集

训练特征标记数据生成识别模型

使用识别模型预测新的未知图片集

达到根据“图片”就能返回识别正确的字符集的目标

7   素材准备

7.1   素材选择

由于本文是以初级的学习研究目的为主,要求 “有代表性,但又不会太难” ,所以就直接在网上找个比较有代表性的简单的字符型验证码(感觉像在找漏洞一样)。

最后在一个比较旧的网站(估计是几十年前的网站框架)找到了这个验证码图片。

原始图:

放大清晰图:

此图片能满足要求,仔细观察其具有如下特点。

有利识别的特点 :

由纯阿拉伯数字组成

字数为4位

字符排列有规律

字体是用的统一字体

以上就是本文所说的此验证码简单的重要原因,后续代码实现中会用到

不利识别的特点 :

图片背景有干扰噪点

这虽然是不利特点,但是这个干扰门槛太低,只需要简单的方法就可以除去

7.2   素材获取

由于在做训练的时候,需要大量的素材,所以不可能用手工的方式一张张在浏览器中保存,故建议写个自动化下载的程序。

主要步骤如下:

通过浏览器的抓包功能获取随机图片验证码生成接口

批量请求接口以获取图片

将图片保存到本地磁盘目录中

这些都是一些IT基本技能,本文就不再详细展开了。

关于网络请求和文件保存的代码,如下:

def downloads_pic(**kwargs):

   pic_name = kwargs.get('pic_name', None)

   url = 'httand_code_captcha/'

   res = requests.get(url, stream=True)

   with open(pic_path + pic_name+'.bmp', 'wb') as f:        for chunk in res.iter_content(chunk_size=1024):            if chunk:  # filter out keep-alive new chunks                f.write(chunk)

               f.flush()

       f.close()

循环执行N次,即可保存N张验证素材了。

下面是收集的几十张素材库保存到本地文件的效果图:

8   图片预处理

虽然目前的机器学习算法已经相当先进了,但是为了减少后面训练时的复杂度,同时增加识别率,很有必要对图片进行预处理,使其对机器识别更友好。

针对以上原始素材的处理步骤如下:

读取原始图片素材

将彩色图片二值化为黑白图片

去除背景噪点

8.1   二值化图片

主要步骤如下:

将RGB彩图转为灰度图

将灰度图按照设定阈值转化为二值图

image = Image.open(img_path)

imgry = image.convert('L')  # 转化为灰度图table = get_bin_table()

out = imgry.point(table, '1')

上面引用到的二值函数的定义如下:

1234567891011121314   def get_bin_table(threshold=140):    """    获取灰度转二值的映射table    :param threshold:    :return:    """    table = []    for i in range(256):        if i threshold:            table.append(0)        else:            table.append(1)     return table   

由PIL转化后变成二值图片:0表示黑色,1表示白色。二值化后带噪点的 6937 的像素点输出后如下图:

1111000111111000111111100001111100000011

1110111011110111011111011110111100110111

1001110011110111101011011010101101110111

1101111111110110101111110101111111101111

1101000111110111001111110011111111101111

1100111011111000001111111001011111011111

1101110001111111101011010110111111011111

1101111011111111101111011110111111011111

1101111011110111001111011110111111011100

1110000111111000011101100001110111011111

如果你是近视眼,然后离屏幕远一点,可以隐约看到 6937 的骨架了。

8.2   去除噪点

在转化为二值图片后,就需要清除噪点。本文选择的素材比较简单,大部分噪点也是最简单的那种 孤立点,所以可以通过检测这些孤立点就能移除大量的噪点。

关于如何去除更复杂的噪点甚至干扰线和色块,有比较成熟的算法: 洪水填充法 Flood Fill ,后面有兴趣的时间可以继续研究一下。

本文为了问题简单化,干脆就用一种简单的自己想的 简单办法 来解决掉这个问题:

对某个 黑点 周边的九宫格里面的黑色点计数

如果黑色点少于2个则证明此点为孤立点,然后得到所有的孤立点

对所有孤立点一次批量移除。

下面将详细介绍关于具体的算法原理。

将所有的像素点如下图分成三大类

顶点A

非顶点的边界点B

内部点C

种类点示意图如下:

其中:

A类点计算周边相邻的3个点(如上图红框所示)

B类点计算周边相邻的5个点(如上图红框所示)

C类点计算周边相邻的8个点(如上图红框所示)

当然,由于基准点在计算区域的方向不同,A类点和B类点还会有细分:

A类点继续细分为:左上,左下,右上,右下

B类点继续细分为:上,下,左,右

C类点不用细分

然后这些细分点将成为后续坐标获取的准则。

主要算法的python实现如下:

def sum_9_region(img, x, y):    """

   9邻域框,以当前点为中心的田字框,黑点个数

   :param x:

   :param y:

   :return:    """

   # todo 判断图片的长宽度下限

   cur_pixel = img.getpixel((x, y))  # 当前像素点的值

   width = img.width

   height = img.height    if cur_pixel == 1:  # 如果当前点为白色区域,则不统计邻域值

       return 0    if y == 0:  # 第一行

       if x == 0:  # 左上顶点,4邻域

           # 中心点旁边3个点

           sum = cur_pixel \                  + img.getpixel((x, y + 1)) \                  + img.getpixel((x + 1, y)) \                  + img.getpixel((x + 1, y + 1))            return 4 - sum        elif x == width - 1:  # 右上顶点

           sum = cur_pixel \                  + img.getpixel((x, y + 1)) \                  + img.getpixel((x - 1, y)) \                  + img.getpixel((x - 1, y + 1))            return 4 - sum        else:  # 最上非顶点,6邻域

           sum = img.getpixel((x - 1, y)) \                  + img.getpixel((x - 1, y + 1)) \                  + cur_pixel \                  + img.getpixel((x, y + 1)) \                  + img.getpixel((x + 1, y)) \                  + img.getpixel((x + 1, y + 1))            return 6 - sum    elif y == height - 1:  # 最下面一行

       if x == 0:  # 左下顶点

           # 中心点旁边3个点

           sum = cur_pixel \                  + img.getpixel((x + 1, y)) \                  + img.getpixel((x + 1, y - 1)) \                  + img.getpixel((x, y - 1))            return 4 - sum        elif x == width - 1:  # 右下顶点

           sum = cur_pixel \                  + img.getpixel((x, y - 1)) \                  + img.getpixel((x - 1, y)) \                  + img.getpixel((x - 1, y - 1))            return 4 - sum        else:  # 最下非顶点,6邻域

           sum = cur_pixel \                  + img.getpixel((x - 1, y)) \                  + img.getpixel((x + 1, y)) \                  + img.getpixel((x, y - 1)) \                  + img.getpixel((x - 1, y - 1)) \                  + img.getpixel((x + 1, y - 1))            return 6 - sum    else:  # y不在边界

       if x == 0:  # 左边非顶点

           sum = img.getpixel((x, y - 1)) \                  + cur_pixel \                  + img.getpixel((x, y + 1)) \                  + img.getpixel((x + 1, y - 1)) \                  + img.getpixel((x + 1, y)) \                  + img.getpixel((x + 1, y + 1))            return 6 - sum        elif x == width - 1:  # 右边非顶点

           # print('%s,%s' % (x, y))

           sum = img.getpixel((x, y - 1)) \                  + cur_pixel \                  + img.getpixel((x, y + 1)) \                  + img.getpixel((x - 1, y - 1)) \                  + img.getpixel((x - 1, y)) \                  + img.getpixel((x - 1, y + 1))            return 6 - sum        else:  # 具备9领域条件的

           sum = img.getpixel((x - 1, y - 1)) \                  + img.getpixel((x - 1, y)) \                  + img.getpixel((x - 1, y + 1)) \                  + img.getpixel((x, y - 1)) \                  + cur_pixel \                  + img.getpixel((x, y + 1)) \                  + img.getpixel((x + 1, y - 1)) \                  + img.getpixel((x + 1, y)) \                  + img.getpixel((x + 1, y + 1))            return 9 - sum

Tips:这个地方是相当考验人的细心和耐心程度了,这个地方的工作量还是蛮大的,花了半个晚上的时间才完成的。

计算好每个像素点的周边像素黑点(注意:PIL转化的图片黑点的值为0)个数后,只需要筛选出个数为 1或者2 的点的坐标即为 孤立点 。这个判断方法可能不太准确,但是基本上能够满足本文的需求了。

经过预处理后的图片如下所示:

对比文章开头的原始图片,那些 孤立点 都被移除掉,相对比较 干净 的验证码图片已经生成。

9   图片字符切割

由于字符型 验证码图片 本质就可以看着是由一系列的 单个字符图片 拼接而成,为了简化研究对象,我们也可以将这些图片分解到 原子级 ,即: 只包含单个字符的图片。

于是,我们的研究对象由 “N种字串的组合对象” 变成 “10种阿拉伯数字” 的处理,极大的简化和减少了处理对象。

9.1   分割算法

现实生活中的字符验证码的产生千奇百怪,有各种扭曲和变形。关于字符分割的算法,也没有很通用的方式。这个算法也是需要开发人员仔细研究所要识别的字符图片的特点来制定的。

当然,本文所选的研究对象尽量简化了这个步骤的难度,下文将慢慢进行介绍。

使用图像编辑软件(PhoneShop或者其它)打开验证码图片,放大到像素级别,观察其它一些参数特点:

可以得到如下参数:

整个图片尺寸是 40*10

单个字符尺寸是 6*10

左右字符和左右边缘相距2个像素

字符上下紧挨边缘(即相距0个像素)

这样就可以很容易就定位到每个字符在整个图片中占据的像素区域,然后就可以进行分割了,具体代码如下:

def get_crop_imgs(img):    """

   按照图片的特点,进行切割,这个要根据具体的验证码来进行工作. # 见原理图

   :param img:

   :return:    """

   child_img_list = []    for i in range(4):

       x = 2 + i * (6 + 4)  # 见原理图

       y = 0

       child_img = img.crop((x, y, x + 6, y + 10))

       child_img_list.append(child_img)    return child_img_list

然后就能得到被切割的 原子级 的图片元素了:

9.2   内容小结

基于本部分的内容的讨论,相信大家已经了解到了,如果验证码的干扰(扭曲,噪点,干扰色块,干扰线……)做得不够强的话,可以得到如下两个结论:

4位字符和40000位字符的验证码区别不大

纯字母

不区分大小写。分类数为26

区分大小写。分类数为52

纯数字。分类数为10

数字和区分大小写的字母组合。分类数为62

纯数字 和 数字及字母组合 的验证码区别不大

在没有形成 指数级或者几何级 的难度增加,而只是 线性有限级 增加计算量时,意义不太大。

10   尺寸归一

本文所选择的研究对象本身尺寸就是统一状态:6*10的规格,所以此部分不需要额外处理。但是一些进行了扭曲和缩放的验证码,则此部分也会是一个图像处理的难点。

11   模型训练步骤

在前面的环节,已经完成了对单个图片的处理和分割了。后面就开始进行 识别模型 的训练了。

整个训练过程如下:

大量完成预处理并切割到原子级的图片素材准备

对素材图片进行人为分类,即:打标签

定义单张图片的识别特征

使用SVM训练模型对打了标签的特征文件进行训练,得到模型文件

12   素材准备

本文在训练阶段重新下载了同一模式的4数字的验证图片总计:3000张。然后对这3000张图片进行处理和切割,得到12000张原子级图片。

在这12000张图片中删除一些会影响训练和识别的强干扰的干扰素材,切割后的效果图如下:

13   素材标记

由于本文使用的这种识别方法中,机器在最开始是不具备任何 数字的观念的。所以需要人为的对素材进行标识,告诉 机器什么样的图片的内容是 1……。

这个过程叫做 “标记”。

具体打标签的方法是:

为0~9每个数字建立一个目录,目录名称为相应数字(相当于标签)

人为判定 图片内容,并将图片拖到指定数字目录中

每个目录中存放100张左右的素材

一般情况下,标记的素材越多,那么训练出的模型的分辨能力和预测能力越强。例如本文中,标记素材为十多张的时候,对新的测试图片识别率基本为零,但是到达100张时,则可以达到近乎100%的识别率

14   特征选择

对于切割后的单个字符图片,像素级放大图如下:

从宏观上看,不同的数字图片的本质就是将黑色按照一定规则填充在相应的像素点上,所以这些特征都是最后围绕像素点进行。

字符图片 宽6个像素,高10个像素 ,理论上可以最简单粗暴地可以定义出60个特征:60个像素点上面的像素值。但是显然这样高维度必然会造成过大的计算量,可以适当的降维。

通过查阅相应的文献 [2],给出另外一种简单粗暴的特征定义:

每行上黑色像素的个数,可以得到10个特征

每列上黑色像素的个数,可以得到6个特征

最后得到16维的一组特征,实现代码如下:

def get_feature(img):    """

   获取指定图片的特征值,

   1. 按照每排的像素点,高度为10,则有10个维度,然后为6列,总共16个维度

   :param img_path:

   :return:一个维度为10(高度)的列表    """

   width, height = img.size

   pixel_cnt_list = []

   height = 10    for y in range(height):

       pix_cnt_x = 0        for x in range(width):            if img.getpixel((x, y)) == 0:  # 黑色点

               pix_cnt_x += 1

       pixel_cnt_list.append(pix_cnt_x)    for x in range(width):

       pix_cnt_y = 0        for y in range(height):            if img.getpixel((x, y)) == 0:  # 黑色点

               pix_cnt_y += 1

       pixel_cnt_list.append(pix_cnt_y)    return pixel_cnt_list

然后就将图片素材特征化,按照 libSVM 指定的格式生成一组带特征值和标记值的向量文

怎样用python实现深度学习

基于Python的深度学习库、深度学习方向、机器学习方向、自然语言处理方向的一些网站基本都是通过Python来实现的。

机器学习,尤其是现在火爆的深度学习,其工具框架大都提供了Python接口。Python在科学计算领域一直有着较好的声誉,其简洁清晰的语法以及丰富的计算工具,深受此领域开发者喜爱。

早在深度学习以及Tensorflow等框架流行之前,Python中即有scikit-learn,能够很方便地完成几乎所有机器学习模型,从经典数据集下载到构建模型只需要简单的几行代码。配合Pandas、matplotlib等工具,能很简单地进行调整。

而Tensorflow、PyTorch、MXNet、Keras等深度学习框架更是极大地拓展了机器学习的可能。使用Keras编写一个手写数字识别的深度学习网络仅仅需要寥寥数十行代码,即可借助底层实现,方便地调用包括GPU在内的大量资源完成工作。

值得一提的是,无论什么框架,Python只是作为前端描述用的语言,实际计算则是通过底层的C/C++实现。由于Python能很方便地引入和使用C/C++项目和库,从而实现功能和性能上的扩展,这样的大规模计算中,让开发者更关注逻辑于数据本身,而从内存分配等繁杂工作中解放出来,是Python被广泛应用到机器学习领域的重要原因。