TowardsDataScience-博客中文翻译-2016-2018-五十九-

57 阅读47分钟

TowardsDataScience 博客中文翻译 2016~2018(五十九)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

预期寿命数据的分类技术

原文:towardsdatascience.com/classificat…

大陆分类法

Photo by chuttersnap on Unsplash

我们人类被赋予了分类的概念。我们对所有东西进行分类,从衣柜里所有的牛仔裤放在一个架子下,所有的衬衫放在另一个专为衬衫准备的架子上,到手机上的应用程序和电脑上的文件,每种文件或应用程序都有单独的文件夹。

现在,分类的一个更“数据科学”的定义是,它是一种数据分析形式,提取描述重要数据类别的模型或预测分类变量(类别或目标)值的任务。基本上,找出一个新的观察将属于哪一组预定义的类别。一个非常常见的例子是,我们希望将某些邮件归类为垃圾邮件,而将其他邮件归类为非垃圾邮件。机器能够通过从已知类别的训练数据中学习来完成这项任务。

只有当我们有离散标签作为输出时,才能使用分类算法。像上面的例子中,电子邮件是否被分类为垃圾邮件,只有两种可能的结果,这种情况被称为二元分类。

另一种类型是多标签分类。在多标签分类中,可以将多个标签分配给一个实例。这主要用于音视频分类、文本分类、情感分析中的情感分类等。

无论如何,这是继续阅读本文所需的基础知识和先决条件。

在本文中,我们将对各大洲进行分类,这是标签,将在预期寿命数据集中用作一个类别。

这是一个非常小的数据集,有 6 列 223 行,每个国家一行。栏目分别是排名、国家、整体生活、男性生活、女性生活和大洲。

为了执行这种分类,我们将使用 5 种不同的分类技术和算法,计算每种算法的精确度和准确度,并对它们进行比较。这 5 种分类算法是:

  • KNN — K 近邻算法使用类似距离函数(distance measures)的相似性度量对经过训练后的新数据点进行分类。
  • SVM —支持向量机是一种监督学习算法,它将创建一个模型,使用训练集将新的点分配到一个或另一个类别。根据问题,分配可以是线性的或非线性的。
  • OneR — OneR 基本上是一个规则算法,这个算法为数据中的每个预测器生成一个规则,然后选择误差最小的规则作为答案。尽管这看起来是一个非常简单的算法,因为它只生成一个规则,但它比一些更复杂的分类算法执行得更好。
  • RIPPER —RIPPER 是一个基于规则的学习器,它建立了一套识别类的规则,同时最小化了错误的数量。误差由被规则错误分类的训练样本的数量来定义。这是执行基于规则的分类的直接方式。
  • C 4.5 — C4.5 是一个统计分类器,因为它生成决策树。它像 ID3 一样从训练数据中构建决策树,并在树的每个节点上选择数据的属性,该属性最有效地将其样本集分成富含一个类或另一个类的子集。这是一种间接的基于规则的分类方法。

现在让我们从使用 R 编程的分析开始,让我们看看哪个分类器执行得最好。

我们将在整个代码中使用以下库/包:e1071、class、caret、rJava、RWeka。

#loading libraries
library("e1071")
library(class)
library(caret)
library(rJava)
library(RWeka)

数据预处理

  1. 数据预处理的第一步包括以下内容:
  • 使用 read.csv() 函数导入 R 中的数据集。
  • 通过查看数据集执行一些可视化的描述性分析,并使用 summary()和 str() 函数获得数据集的摘要。
  • 通过分解将类别标签 continental 转换为分类变量。
  • 一些不相关的列也将被删除,这些列不会在分析中使用。像第一个,秩列。
#importing csv file in R
dataset <- read.csv(file.choose())#displaying head(first five) elements
head(dataset) 
str(dataset)
#dimentions
dim(dataset) #Converting Continent to factor
dataset[c("Continent")]<- lapply(dataset[c("Continent")], factor)#removing the first (irrelevant) coulmn
dataset <- dataset[,-1]str(dataset)
summary(dataset)

输出

head(), str(), dim() functions

str(), summary() functions after the removal of the first column and the factor converstion

观察

尽管 Continent 列已经是 factor 数据类型,但我们仍然运行命令使其成为 factor。有了这个数据视图,我们可以清楚地了解数据的样子, head() 函数可以做到这一点。汇总函数向我们展示了一些重要的描述性信息。最重要的是,我们可以看到有多少国家位于哪个洲,这将有助于我们以后检查准确性。我们还可以观察整体、男性和女性预期寿命的均值,分别为 72.49、70.04 和 75.02。还可以观察中间值、四分位数、混合值和最大值。

2.对于数据预处理的第二部分,我们将:

  • 通过使用样本方法生成训练和测试元素的随机排列,将数据集以 80:20 的比例划分为训练集和测试集。
  • 将训练和测试样本保存在输出变量的列表中。
  • 我们可以通过打印输出变量来查看训练和测试样本。
#sampling 80% training data
traindata <- sample(seq_len(nrow(dataset)), size = floor(0.80 * nrow(dataset)))
data_train <- dataset[traindata, ]
data_test <- dataset[-traindata,]
t_train <- dataset$Continent[traindata]
t_test <- dataset$Continent[-traindata]output<-list(data_train,data_test,t_train,t_test)#a view of the devided data(into train and test)
print(output)

KNN-K 最近邻算法

KNN 分类将在预处理和训练方法的帮助下执行,可在 caret 包中获得。训练方法中的隧道长度将根据拟合模型结果选择为 20,这将帮助我们自动选择最佳值。

在我们的例子中,K 被选择为 5。此外,精确度用于选择使用最大值的最佳模型。

#KNN#setting seed
set.seed(12345)knn_train_test<-output
let_train<-knn_train_test[[1]]
let_test<-knn_train_test[[2]]#Preprocessing and training
trainX <- let_train[,names(let_train) != "Continent"]
preProcValues <- preProcess(x = trainX,method = c("center", "scale"))
print(preProcValues)#Fit Model- Using Caret's train model to find best k
ctrl <- trainControl(method="repeatedcv",repeats = 3)
knnFit <- train(Continent~., data = let_train, method = "knn", 
                trControl = ctrl,preProcess = c("center","scale"), 
                tuneLength = 20)
print(knnFit)
plot(knnFit)#Make predictions
knnPredict <- predict(knnFit,newdata = let_test )
knnPredict#Confusion Matrix
confusionMatrix(knnPredict, let_test$Continent )#Accuracy
knnoutput<-mean(knnPredict== let_test$Continent)
knnoutput

输出

preprocessing using the caret package and finding the knn fit i.e. value of K

plot depicting the choice of the value of K by using accuracy

prediction, confusion matrix and accuracy

观察

  • 首先,我们观察到,通过查看最高精度(通过重复交叉验证),K 的最佳值被选择为 5。
  • 该图还显示 K=5 时的最高精度值为 0.562,K=17 时的精度为 0.559。
  • KNN 的准确率是 44%。

SVM —支持向量机

SVM 分类功能将借助调整方法并使用 e1071 软件包进行部署。通过从调整方法中选择核为线性且成本为 1 来调整 svm 拟合分类。

#SVM #setting seed
set.seed(12345)train_test<- output
let_train<-train_test[[1]]
let_test<-train_test[[2]]#Fit model
svmfit <- svm(Continent ~., data = let_train, kernel = "linear", scale = FALSE)
svmfit
svm#Tune to check best performance
tuned <- tune(svm, Continent ~., data = let_train, kernel = "linear", ranges = list(cost=c(0.001,0.01,.1,1,10,100)))
summary(tuned)#Make predictions
p <- predict(svmfit, let_test, type="class")
length(let_test$Continent)
table(p, let_test$Continent)#Analyse results
#Confusion matrix
confusionMatrix(p, let_test$Continent )#Accuracy
#print(mean(p== let_test$Continent))
svmoutput<-mean(p== let_test$Continent)
svmoutput

输出

fitting the model using svmfit()

tuning to check for the best performance and predicting the classes

creating the confusion matrix and calculating the accuracy

观察

  • 我们观察到 SVM 的准确率为 55%

OneR —一个规则算法

#OneR#setting seed
set.seed(12345)oner_train_test<- output
let_train<-oner_train_test[[1]]
let_test<-oner_train_test[[2]]#Fitting model
model <- OneR(Continent~.,let_train)
model#prediction
pred <- predict(model, let_test)
predtable(pred,let_test$Continent)
summary(model)#confusion matrix 
confusionMatrix(pred, let_test$Continent)#Accuracy
acc<-mean(pred==let_test$Continent)
acc

输出

model 1/2

model 2/2

prediction() function, table and summary of the model

confusion matrix and accuracy

观察

  • 我们观察了使用训练数据映射的 178 个实例的建模。
  • 当使用测试数据进行预测时,只有 38 个正确分类的实例,而 140 个错误分类的实例,因为非洲被作为一个规则。
  • 这使得 OneR 算法的准确率只有 20%。

RIPPER —重复增量修剪以产生误差减少算法

Ripper 分类功能将借助 RWeka 包中的 JRip 方法进行部署。

#RIPPER Algorithm#setting seed
set.seed(12345)ripper_train_test<- output
let_train<-ripper_train_test[[1]]
let_test<-ripper_train_test[[2]]#fitting model using Weka control function of JRip
model1 <- JRip(Continent~., data=let_train) 
model1#prediction
pred1 <- predict(model1, let_test)
pred1table(pred1, let_test$Continent)
summary(model1)#confusion matrix
confusionMatrix(pred1, let_test$Continent)#Accuracy
acc<-mean(pred1==let_test$Continent)
acc

输出

modeling, prediction, tabulation of the prediction and summary

confusion matrix and accuracy

观察

  • 当使用测试数据进行预测时,95 个实例被正确分类,而 83 个被错误分类。
  • 混乱矩阵清楚地显示了哪个大陆被归类为什么。
  • 使用 RIPPER 算法可以观察到 48%的精度

C 4.5 算法

借助 RWeka 包中的 J48 方法部署了 C4.5 分类功能。

#C.45 Algorithm#setting seed
set.seed(12345)c45_train_test<- output
let_train<-c45_train_test[[1]]
let_test<-c45_train_test[[2]]# fit model-Using Weka Control function of J48
fit <- J48(Continent~., data=let_train)# summarize the fit
summary(fit)# make predictions
c45predictions <- predict(fit, let_test)# summarize accuracy
tb<-table(c45predictions, let_test$Continent)#Confusion Matrix
confusionMatrix(c45predictions, let_test$Continent )#Accuracy
#print(mean(c45predictions== let_test$Continent))
c45output<-mean(c45predictions== let_test$Continent)
c45output

输出

summary of the fit, confusion matrix and accuracy

观察

  • 通过总结拟合度,我们可以看到 138 个实例被正确分类,而 40 个被错误分类。
  • 使用 C4.5 算法得到的准确率为 48%
  • 精确度与 RIPPER 算法非常相似。

结论

最后,让我们列出本文中使用的各种分类器的所有精度值。

精度值——由分类器确定

  • KNN——44%
  • SVM——55%
  • OneR — 20%
  • 裂土器— 48%
  • C4.5 — 48%

显然,SVM 的表现远远超过了所有其他分类技术。RIPPER 和 C4.5 是最接近的,都显示出 48%的准确率,这是非常令人印象深刻的。OneR 算法表现最差,只有 20%的准确率。

在 Keras 中用深度学习对蝴蝶图像进行分类

原文:towardsdatascience.com/classify-bu…

不久前,我在荷兰组织 Vlinderstichting 的网站上读到了一篇有趣的博文。每年他们组织一次蝴蝶计数。志愿者帮助确定他们花园里不同的蝴蝶种类。Vlinderstichting 收集并分析结果。

由于蝴蝶种类的确定是由志愿者完成的,这个过程不可避免地容易出错。因此,Vlinderstichting的工作量太大,因为他们必须手动检查提交的内容是否正确。

具体来说,有三种蝴蝶的 Vlinderstichting 得到了许多错误的判定。这些是

在本文中,我将描述拟合深度学习模型的步骤,该模型有助于区分前两种蝴蝶。

使用 Flickr API 下载图像

为了训练一个卷积神经网络,我需要 找到带有正确标签的蝴蝶图像 。当然,我可以自己给我想分类的蝴蝶拍照。他们有时在我的花园里飞来飞去…

开玩笑,那要花很长时间。为此,我需要一种自动获取图像的方法。为此,我通过 Python 使用了 Flickr API

设置 Flickr API

首先,我用 pip 安装了 flickrapi 包 。然后我在 Flickr 网站上创建必要的 API 键来连接 Flickr API。

除了 flickrapi 包之外,我还导入了 osurllib 包,用于下载图像和设置目录。

from flickrapi import FlickrAPI
import urllib
import os
import config

config 模块中,我为 Flickr API 定义了公钥和密钥。这只是一个 Python 脚本(config.py ),代码如下:

API_KEY = 'XXXXXXXXXXXXXXXXX'  // replace with your key
API_SECRET = 'XXXXXXXXXXXXXXXXX'  // replace with your secret
IMG_FOLDER = 'XXXXXXXXXXXXXXXXX'  // replace with your folder to store the images

出于安全原因,我将这些 密钥保存在一个单独的文件中 。因此,您可以将代码保存在公共存储库中,如 GitHub 或 BitBucket,并将 config.py 放在. gitignore 中。因此,您可以与其他人共享您的代码,而不必担心有人会访问您的凭据。

为了提取不同蝴蝶种类的图像,我写了一个函数download _ Flickr _ photos。我会一步一步解释这个函数。此外,我已经在 GitHub上发布了完整的代码。

输入参数

首先,我检查输入参数的类型或值是否正确。如果没有,我会抛出一个错误。参数的解释可以在函数的 docstring 中找到。

if not (isinstance(keywords, str) or isinstance(keywords, list)):
    raise AttributeError('keywords must be a string or a list of strings')if not (size in ['thumbnail', 'square', 'medium', 'original']):
    raise AttributeError('size must be "thumbnail", "square", "medium" or "original"')if not (max_nb_img == -1 or (max_nb_img > 0 and isinstance(max_nb_img, int))):
    raise AttributeError('max_nb_img must be an integer greater than zero or equal to -1')

其次,我定义了稍后将在 walk 方法中使用的一些参数。我为关键字创建了一个列表,并确定需要从哪个 URL 下载图像。

if isinstance(keywords, str):
    keywords_list = []
    keywords_list.append(keywords)
else:
    keywords_list = keywords
if size == 'thumbnail':
    size_url = 'url_t'
elif size == 'square':
    size_url = 'url_q'
elif size == 'medium':
    size_url = 'url_c'
elif size == 'original':
    size_url = 'url_o'

连接到 Flickr API

接下来,我连接到 Flickr API。在 FlickrAPI 调用中,我使用了配置模块中定义的 API 键。

flickr = FlickrAPI(config.API_KEY, config.API_SECRET)

为每种蝴蝶创建子文件夹

我将每种蝴蝶的图片保存在单独的子文件夹中。每个子文件夹的名称是蝴蝶物种的名称,由关键字。如果子文件夹还不存在,我就创建它。

results_folder = config.IMG_FOLDER + keyword.replace(" ", "_") + "/"
if not os.path.exists(results_folder):
    os.makedirs(results_folder)

在 Flickr 图书馆里漫步

photos = flickr.walk(
    text=keyword,
    extras='url_m',
    license='1,2,4,5',
    per_page=50)

我使用 Flickr API 的 walk 方法来搜索指定关键字的图像。这个 walk 方法与 Flickr API 中的搜索方法具有相同的参数。

文本参数中, 我使用关键字来搜索与该关键字相关的图片。其次,在 extras 参数中, 我指定 url_m 为小、中尺寸的图片。在这个 Flickcurl C 库中给出了关于图像大小和它们各自 URL 的更多解释。

第三,在 许可参数中, 我选择了带有非商业许可的图像。关于许可证代码及其含义的更多信息可以在 Flickr API 平台上找到。最后, per_page 参数 指定了我允许每页显示多少张图片。

因此,我有一个名为 的图片生成器 来下载图片。

下载 Flickr 图像

有了照片生成器,我可以下载搜索查询中找到的所有图片。首先,我得到了下载图片的具体网址。然后我增加 count 变量,并使用这个计数器来创建图像文件名。

使用 urlretrieve 方法,我下载图像并保存在蝴蝶种类的文件夹中。如果出现错误,我会打印出错误消息。

for photo in photos:
    try:
        url=photo.get('url_m')
        print(url)
        count += 1
        urllib.request.urlretrieve(url,  results_folder + str(count) +".jpg")
    except Exception as e:
        print(e, 'Download failure')

为了下载多种蝴蝶,我创建了一个列表,并在循环 中调用函数 download_flickr_photos。为了简单起见,我只下载了上面提到的三种蝴蝶中的两种。

butterflies = ['meadow brown butterfly', 'gatekeeper butterfly']
for butterfly in butterflies:
    download_flickr_photos(butterfly)

图像的数据扩充

在少量图像 上训练 convnet 将导致 过拟合 。因此,该模型在分类新的、看不见的图像时会出错。数据扩充有助于避免这种情况。幸运的是,Keras 有一些很好的工具来轻松转换图像。

我写了另一篇关于如何防止过度合身的文章,你可以点击下面的链接。

我想和我儿子在路上给汽车“分类”的方式做个比较。目前他只有 2 岁,还没有见过像成年人一样多的车。所以你可以说他的图像“训练集”相当小。因此,他更有可能将汽车分类错误。例如,他有时会误把救护车当成警车。

随着他年龄的增长,他会看到更多的救护车和警车,以及我将给他的相应标签。因此,他的训练集将变得更大,从而他将更正确地对它们进行分类。

出于这个原因,我们需要 向 convnet 提供比目前更多的蝴蝶图片 。一个简单的解决方案是数据扩充。简而言之,这意味着对 Flickr 图像应用一组变换。

Keras 提供了 大范围的图像变换 。但首先,我们必须转换图像,以便 Keras 可以使用它们。

将图像转换为数字

我们从导入 Keras 模块开始。我们将用一个示例图像来演示图像转换。为此,我们使用了 load_img 方法。

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_imgi = load_img('data/train/maniola_jurtina/1.jpg' )
x = img_to_array(i)
x = x.reshape((1,) + x.shape)

load_img 方法创建一个 Python 图像库文件。我们需要将它转换成一个 Numpy 数组,以便稍后在imagedata generator方法中使用。用方便的 img_to_array 方法就搞定了。因此,我们有一个 75x75x3 形状的数组。这些尺寸反映了宽度、高度和 RGB 值。

事实上,图像的每个像素有 3 个 RGB 值。这些范围在 0 到 255 之间,代表红色、绿色和蓝色的强度。较低的值代表较高的强度,较高的值代表较低的强度。例如,一个像素可以表示为这三个值的列表[ 78,136,60]。黑色将表示为[0,0,0]。

最后,我们需要添加一个额外的维度,以避免在应用转换时出现值错误。这是通过 整形 功能完成的。

好了,现在我们有东西可以用了。让我们继续转换。

旋转

通过指定一个 0 到 180 之间的值,Keras 将 随机选择一个角度 来旋转图像。它会顺时针或逆时针转动。在我们的例子中,图像最大旋转 90 度。

ImageDataGenerator 还有一个参数 fill_mode 。默认值为“最近”。通过在原始图像的宽度和高度范围内旋转图像,我们得到了“空”像素。fill_mode 然后使用最近的像素来填充这个空白空间。

imgGen = ImageDataGenerator(rotation_range = 90)i = 1
for batch in imgGen.flow(x, batch_size=1, save_to_dir='example_transformations', save_format='jpeg', save_prefix='trsf'):
    i += 1
    if i &gt; 3:
        break

方法中,我们指定将转换后的图像保存到哪里。请确保该目录存在!为了方便起见,我们还给新创建的图像加上前缀。flow 方法可以无限运行,但是对于这个例子,我们只生成三个图像。所以当我们的计数器达到这个值时,我们就中断 for 循环。你可以在下面看到结果。

宽度移动

width _ shift _ range参数中,您可以指定图像向左或向右移动的原始宽度的比率。同样,fill_mode 将填充新创建的空像素。对于其余的示例,我将只展示如何用相应的参数实例化 ImageDataGenerator。生成图像的代码与旋转示例中的代码相同。

imgGen = ImageDataGenerator(width_shift_range = 90)

在变换后的图像中,我们看到图像向右移动。空像素被填充,这使它看起来有点拉伸。

通过为height _ shift _ range参数指定一个值,同样可以实现上移或下移。

重新调节

在任何其他预处理之前,重新缩放图像会将每个像素的 RGB 值 乘以选定的值 。在我们的示例中,我们对值应用最小-最大缩放。因此,这些值的范围将在 0 和 1 之间。这使得值更小,模型更容易处理。

imgGen = ImageDataGenerator(rescale = 1./255)

剪(羊毛)

使用 剪切范围 参数,我们可以指定必须如何应用剪切变换。当该值设置得太高时,这种变换会产生相当奇怪的图像。所以不要定的太高。

imgGen = ImageDataGenerator(shear_range = 0.2)

一款云视频会议软件

这种变换将 放大到画面 内部。就像剪切参数一样,这个值不应该被夸大以保持图像的真实感。

imgGen = ImageDataGenerator(zoom_range = 0.2)

水平翻转

这种变换水平翻转图像。生活有时会很简单…

imgGen = ImageDataGenerator(horizontal_flip = True)

所有转换组合

现在我们已经分别看到了每个变换的效果,我们一起应用所有的组合。

imgGen = ImageDataGenerator(
    rotation_range = 40,
    width_shift_range = 0.2,
    height_shift_range = 0.2,
    rescale = 1./255,
    shear_range = 0.2,
    zoom_range = 0.2,
    horizontal_flip = True)i = 1
for batch in imgGen.flow(x, batch_size=1, save_to_dir='example_transformations', save_format='jpeg', save_prefix='all'):
    i += 1
    if i &gt; 3:
        break

设置文件夹结构

我们需要将这些图像存储在特定的文件夹结构中。因此,我们可以使用方法flow _ from _ directory来扩充图像并创建相应的标签。该文件夹结构需要如下所示:

  • 列车
  • 马尼奥拉 _ 尤尔蒂纳
  • 0.jpg
  • 1.jpg
  • pyronia_tithonus
  • 0.jpg
  • 1.jpg
  • 验证
  • 马尼奥拉 _ 尤尔蒂纳
  • 0.jpg
  • 1.jpg
  • pyronia_tithonus
  • 0.jpg
  • 1.jpg

为了创建这个文件夹结构,我创建了一个要点img _ train _ test _ split . py。请随意在您的项目中使用它。

创建发电机

和以前一样,我们为训练生成器指定配置参数。验证图像将不会被转换为训练图像。我们只划分 RGB 值,使它们变小。

flow _ from _ directory方法从 train 或 validation 文件夹中获取图像,并生成 32 个转换图像的批次。通过将 class_mode 设置为‘二进制’,基于图像的文件夹名称创建一维标签。

train_datagen = ImageDataGenerator(
    rotation_range = 40,
    width_shift_range = 0.2,
    height_shift_range = 0.2,
    rescale = 1./255,
    shear_range = 0.2,
    zoom_range = 0.2,
    horizontal_flip = True)validation_datagen = ImageDataGenerator(rescale=1./255)train_generator = train_datagen.flow_from_directory(
    'data/train',
    batch_size=32,
    class_mode='binary')validation_generator = validation_datagen.flow_from_directory(
    'data/validation',
    batch_size=32,
    class_mode='binary')

不同的图像尺寸呢?

Flickr API 允许您下载特定大小的图像。然而, 在现实应用中,图像尺寸并不总是恒定的 。如果图像的纵横比相同,我们可以简单地调整图像的大小。否则,我们可以裁剪图像。不幸的是,很难在保持我们想要分类的对象完整的同时裁剪图像。

Keras 可以处理不同大小的图像。配置模型时,您可以在input _ shape中为宽度和高度指定 None。

input_shape=(3, None, None)  # Theano
input_shape=(None, None, 3)  # Tensorflow

我想展示的是,它可以处理不同的图像尺寸,然而,它有一些缺点。

  • 并非所有层(如展平)都将“无”作为输入尺寸
  • 运行起来计算量可能很大

构建深度学习模型

在本文的剩余部分,我将讨论卷积神经网络的结构,并用我们的 butterfly 项目中的一些例子来说明。在本文的最后,我们将有我们的第一个分类结果。

卷积神经网络由哪几层组成?

当然,您可以选择将多少层及其类型添加到您的卷积神经网络(也称为 CNN 或 convnet)。在这个项目中,我们将从以下结构开始:

让我们了解每一层的作用,以及我们如何用 Keras 创建它们。

输入层

这些不同版本的图像通过几次变换进行了修改。然后,这些图像被转换成数字表示或矩阵。

这个矩阵的尺寸将是 宽 x 高 x(颜色)通道数 *。*对于 RGB 图像,通道数量为三个。对于灰度图像,这等于 1。下面你可以看到一个 7×7 的 RGB 图像的数字表示。

由于我们的图像大小为 75×75,我们需要在添加第一个卷积层时在 input_shape 参数中指定。

cnn = Sequential()
cnn.add(Conv2D(32,(3,3), input_shape = (3 ,75 ,75)))

卷积层

在前几层中,卷积神经网络将寻找的低级特征,如水平或垂直边缘。我们在网络中走得越远,它将寻找更高级的特征,例如蝴蝶的翅膀。但是,当它只获得数字作为输入时,它如何检测特征呢?这就是过滤器发挥作用的地方。

过滤器(或内核)

您可以将滤镜想象为扫描图像的特定大小的探照灯。下面的过滤器示例的尺寸为 3x3x3,包含检测垂直边缘的权重。对于灰度图像,尺寸应该是 3x3x1。通常,过滤器的尺寸小于我们要分类的图像。通常使用 3×3、5×5 或 7×7。第三维应该总是等于通道的数量。

扫描图像时,会转换 RGB 值。它通过将 RGB 值乘以滤镜的权重来完成这一转换。最后,相乘后的值在所有通道上求和。在我们的 7x7x3 图像示例和 3x3x3 滤镜中,这将导致 5x5x1 的结果。

下面的动画说明了这个 卷积运算 。为简单起见,我们只在红色通道中寻找垂直边缘。因此,绿色和蓝色通道的权重都等于零。但是您应该记住,这些通道的乘法结果会添加到红色通道的结果中。

如下所示,卷积层将产生数值结果。当您有较高的数字时,这意味着过滤器遇到了它正在寻找的特征。在我们的例子中,垂直边缘。

我们可以指定想要一个以上的过滤器。这些过滤器可以在图像中寻找它们自己的特征。假设我们使用 32 个大小为 3x3x3 的过滤器。在我们的示例中,所有过滤器的结果叠加在一起,最终得到一个 5x5x32 的体积。在上面的代码片段中,我们添加了 32 个大小为 3x3x3 的过滤器。

进展

在上面的例子中,我们看到滤镜 一次上移 一个像素。这就是所谓的跨步。我们可以增加过滤器上移的像素数量。增加步幅将更快地减小原始图像的尺寸。在下面的示例中,您可以看到滤镜如何以步长 2 移动,这将导致 3x3x3 滤镜的 3x3x1 结果和 7x7x3 图像。

填料

通过应用滤镜,原始图像的 维度被快速缩小 。尤其是图像边缘的像素在卷积运算中只使用一次。这导致了信息的丢失。如果要避免这种情况,可以指定填充。填充会在图像周围添加“额外像素”。

假设我们在 7x7x3 图像周围添加一个像素的填充。这产生了 9x9x3 的图像。如果我们应用一个 3x3x3 的过滤器,步长为 1,我们最终得到 7x7x1 的结果。因此,在这种情况下,我们保留原始图像的尺寸,外部像素被多次使用。

您可以计算具有特定填充和步长的卷积运算的结果,如下所示:

1 + [(原始维度+填充 x 2 —过滤维度)/步幅大小]

例如,假设我们有这样的 conv 层设置:

  • 7x7x3 图像
  • 3x3x3 过滤器
  • 1 个像素的填充
  • 2 像素的步幅

这将得出 1+[(7+1 x 2–3)/2]= 4

为什么我们需要卷积层?

使用 conv 层的一个好处是估计的参数数量 要少得多 。比普通隐藏层低得多。假设我们继续使用 7x7x3 的示例图像和 3x3x3 的滤镜,没有填充,步幅为 1。卷积层将有 5x5x1 + 1 个偏差= 26 个权重要估计。在隐层中具有 7x7x3 输入和 5x5x1 神经元的神经网络中,我们将需要估计 3.675 个权重。想象一下,当你有更大的图像时,这个数字是多少…

ReLu 层

整流线性单元层。 这一层给网络增加了非线性。卷积层是线性层,因为它将滤波器权重和 RGB 值的乘积相加。

对于 x <= 0. Otherwise, it is equal to the value of x. The code in Keras to add a ReLu layer is:

*cnn.add(Activation(‘relu’))*

Pooling

Pooling aggregates the input volume in order to 的所有值,ReLu 函数的结果等于零。进一步减小尺寸 。这加快了计算时间,因为要估计的参数数量减少了。除此之外,通过使网络更加健壮,它有助于避免过拟合。下面我们举例说明最大池的大小为 2×2,步幅为 2。

Keras 中添加大小为 2×2 的池的代码是:

*cnn.add(MaxPooling2D(pool_size = (2 ,2)))*

全连接层

最后,convnet 能够检测输入图像中的更高级特征。然后,这可以作为全连接层的输入。在此之前,我们将展平最后一个 ReLu 层的输出。展平意味着我们把它转换成一个矢量。然后向量值被连接到完全连接层中的所有神经元。为了在 Python 中做到这一点,我们使用了以下 Keras 函数:

*cnn.add(Flatten())        
cnn.add(Dense(64))*

拒绝传统社会的人

就像合用一样,辍学可以帮助 避免过度适应 。在模型训练期间,它随机将输入的指定部分设置为零。辍学率在 20%到 50%之间被认为是有效的。

*cnn.add(Dropout(0.2))*

乙状结肠激活

因为我们想要产生一个 概率 图像是两个蝴蝶种类之一(即二进制分类),我们可以使用一个 sigmoid 激活层。

*cnn.add(Activation('relu'))
cnn.add(Dense(1))
cnn.add(Activation( 'sigmoid'))*

卷积神经网络在蝴蝶图像中的应用

现在我们可以定义完整的卷积神经网络结构,如本文开头所示。首先,我们需要导入必要的 Keras 模块。然后,我们可以开始添加我们上面解释的层。

*from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Flatten, Dense, Dropout
from keras.preprocessing.image import ImageDataGeneratorimport timeIMG_SIZE = # Replace with the size of your images
NB_CHANNELS = # 3 for RGB images or 1 for grayscale images
BATCH_SIZE = # Typical values are 8, 16 or 32
NB_TRAIN_IMG = # Replace with the total number training images
NB_VALID_IMG = # Replace with the total number validation images*

我做了一些额外的参数明确的 conv 层。这里有一个简短的解释:

  • kernel_size 指定过滤器的大小。因此,对于第一个 conv 层,这是 2×2 的大小
  • ****padding = ' same '**表示应用零填充,这样原始图像尺寸被保留。
  • ****padding = ' valid '**表示我们不应用任何填充。
  • ****data _ format = ' channels _ last '**只是在 input_shape 参数中最后指定颜色通道的个数。
*cnn = Sequential()cnn.add(Conv2D(filters=32, 
               kernel_size=(2,2), 
               strides=(1,1),
               padding='same',
               input_shape=(IMG_SIZE,IMG_SIZE,NB_CHANNELS),
               data_format='channels_last'))
cnn.add(Activation('relu'))
cnn.add(MaxPooling2D(pool_size=(2,2),
                     strides=2))cnn.add(Conv2D(filters=64,
               kernel_size=(2,2),
               strides=(1,1),
               padding='valid'))
cnn.add(Activation('relu'))
cnn.add(MaxPooling2D(pool_size=(2,2),
                     strides=2))cnn.add(Flatten())        
cnn.add(Dense(64))
cnn.add(Activation('relu'))cnn.add(Dropout(0.25))cnn.add(Dense(1))
cnn.add(Activation('sigmoid'))cnn.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])*

最后,我们编译这个网络结构,并设置损失参数为binary _ cross entropy*,这对于二进制目标是好的,并使用 准确度 作为评估度量。*

在指定了网络结构之后,我们为训练和验证样本创建生成器。在训练样本上,我们如上所述应用 数据扩充 。对于验证样本,我们不应用任何增强,因为它们仅用于评估模型性能。

*train_datagen = ImageDataGenerator(
    rotation_range = 40,                  
    width_shift_range = 0.2,                  
    height_shift_range = 0.2,                  
    rescale = 1./255,                  
    shear_range = 0.2,                  
    zoom_range = 0.2,                     
    horizontal_flip = True)validation_datagen = ImageDataGenerator(rescale = 1./255)train_generator = train_datagen.flow_from_directory(
    '../flickr/img/train',
    target_size=(IMG_SIZE,IMG_SIZE),
    class_mode='binary',
    batch_size = BATCH_SIZE)validation_generator = validation_datagen.flow_from_directory(
    '../flickr/img/validation',
    target_size=(IMG_SIZE,IMG_SIZE),
    class_mode='binary',
    batch_size = BATCH_SIZE)*

使用生成器上的flow _ from _ directory****方法,我们可以轻松地遍历指定目录中的所有图像。

最后,我们可以在训练数据上拟合卷积神经网络,并用验证数据进行评估。模型的最终权重可以被保存并在以后重用。

**start = time.time()
cnn.fit_generator(
    train_generator,
    steps_per_epoch=NB_TRAIN_IMG//BATCH_SIZE,
    epochs=50,
    validation_data=validation_generator,
    validation_steps=NB_VALID_IMG//BATCH_SIZE)
end = time.time()
print('Processing time:',(end - start)/60)cnn.save_weights('cnn_baseline.h5')**

历元的数量 被任意设置为 50。一个时期是向前传播的循环,检查误差,然后在向后传播期间调整权重。

steps _ per _ epoch设置为训练图像的数量除以批量大小(顺便说一下,双除法符号将确保结果是整数而不是浮点数)。指定一个大于 1 的批量将会加快进程。validation_steps 参数同上。

结果

运行 50 个纪元后,我们的训练精度为 0.8091,验证精度为 0.7359。所以卷积神经网络仍然遭受相当多的过拟合*。我们还看到验证的准确性变化很大。这是因为我们有一小组验证样本。最好每轮评估都做 k 倍交叉验证。但这需要相当长的时间。***

为了解决过度拟合问题,我们可以:

  • 增加辍学率
  • 在每一层应用下降
  • 查找更多培训数据

我们将研究前两个选项并监控结果。我们第一个模型的结果将作为基线。在应用额外的漏失层并增加漏失率后,模型的过度拟合程度会有所降低。

我希望你们都喜欢读这篇文章,并且学到了一些新的东西。完整代码可在 Github 上获得。干杯!

从音频数据中分类歌曲流派

原文:towardsdatascience.com/classify-so…

这些建议非常中肯!这个播放列表怎么这么了解我?

Photo by bruce mars on Unsplash

介绍

在过去的几年里,拥有巨大目录的流媒体服务已经成为大多数人收听他们喜爱的音乐的主要方式。但与此同时,提供的音乐数量之多意味着用户在试图寻找符合他们口味的新音乐时可能会有点不知所措。

出于这个原因,流媒体服务已经开始研究对音乐进行分类的方法,以便进行个性化推荐。一种方法包括直接分析给定歌曲中的原始音频信息,根据各种指标对原始数据进行评分。在本文中,我将检查由一个名为 Echo Nest 的研究小组收集的数据。我们的目标是浏览这个数据集,将歌曲分为“嘻哈”或“摇滚”——所有这些都不需要我们自己去听。在这样做的过程中,我们将学习如何清理我们的数据,进行一些探索性的数据可视化,并通过一些简单的机器学习算法(如决策树和逻辑回归)使用特征约简来实现馈送数据的目标。

那么,让我们开始吧

  1. 加载并准备数据集

首先,让我们加载关于我们的跟踪的元数据以及由 Echo Nest 编译的跟踪度量。一首歌不仅仅是它的标题、艺术家和收听次数。我们有另一个数据集,它有每个音轨的音乐特征,比如从-1 到 1 的范围内的danceabilityacousticness。它们存在于两个不同的文件中,格式不同——CSV 和 JSON。CSV 是表示表格数据的流行文件格式,而 JSON 是另一种常见的文件格式,数据库经常使用这种格式返回给定查询的结果。

同样,让我们检查一下我们的数据框看起来像什么

。连续变量之间的成对关系**

我们通常希望避免使用相互之间相关性很强的变量,从而避免特征冗余,原因如下:

  • 为了保持模型简单并提高可解释性(对于许多特性,我们冒着过度拟合的风险)。
  • 当我们的数据集非常大时,使用较少的特征可以大大加快我们的计算时间。

为了了解我们的数据中是否有任何强相关的特征,我们将使用pandas包中的内置函数。

从上面的图中,我们可以看到任何特征之间都没有很强的相关性。因此,我们不需要从数据中删除任何特征。

3。归一化特征数据

如前所述,简化我们的模型并使用尽可能少的必要特征来获得最佳结果是非常有用的。由于我们没有发现我们的特征之间有任何特别强的相关性,我们可以使用一种称为 主成分分析的通用方法来减少特征的数量。

不同流派之间的差异可能只由数据集中的几个特征来解释。PCA 沿最高方差轴旋转数据,从而允许我们确定数据的每个特征对类间方差的相对贡献。

但是,由于 PCA 使用要素的绝对方差来旋转数据,因此相对于其他要素而言,具有更大范围值的要素会压倒算法并使算法产生偏差。为了避免这种情况,我们必须首先规范化我们的数据。有几种方法可以做到这一点,但一种常见的方法是通过标准化,这样所有的特征都有一个mean = 0standard deviation = 1(结果是一个 z 值)。

让我们看看标准化后我们的数据框是什么样子的

4。对我们的缩放数据进行主成分分析

既然我们已经对数据进行了预处理,我们就可以使用 PCA 来确定我们可以将数据的维度减少多少。我们可以使用 scree-plots累积解释比率图来找到用于进一步分析的组件数量。

Scree-plots 根据每个组件解释的方差显示组件数,按方差降序排序。Scree-plots 帮助我们更好地理解哪些成分解释了我们数据中足够多的差异。当使用碎石图时,图中的“拐点”(从一个数据点到下一个数据点的陡峭下降)通常用于决定适当的截止点。

不幸的是,在该碎石图中似乎没有明显的弯头,这意味着使用该方法不容易找到固有维度的数量。

5。PCA 的进一步可视化

但是并没有失去一切!相反,我们也可以查看累积解释方差图来确定需要多少特征来解释,比如说,大约 90%的方差(这里的临界值有些随意,通常由“经验法则”决定)。一旦我们确定了合适的组分数量,我们就可以用那么多组分进行 PCA,理想地降低我们数据的维数。

现在,我们可以使用数据的低维 PCA 投影来将歌曲分类成流派。为此,我们首先需要将数据集分为“训练”和“测试”子集,其中“训练”子集将用于训练我们的模型,而“测试”数据集允许模型性能验证。

6。训练决策树对流派进行分类

在本文中,我们将使用一个简单的算法,称为决策树。决策树是基于规则的分类器,它接受特征并遵循二元决策的“树结构”,最终将数据点分类为两个或更多类别中的一个。除了易于使用和解释之外,决策树还允许我们将模型从训练数据生成的“逻辑流程图”可视化。

虽然我们的树的性能还不错,但是立即认为它是这项工作的完美工具是一个坏主意——总有其他模型表现更好的可能性!至少测试几个其他算法并找到最适合我们数据的算法总是一个值得的想法。

第七期。将我们的决策树模型比作逻辑回归**

有时最简单的是最好的,所以我们将从应用逻辑回归开始。逻辑回归利用所谓的逻辑函数来计算给定数据点属于给定类别的概率。一旦我们有了这两个模型,我们就可以在一些性能指标上对它们进行比较,比如假阳性和假阴性率(或者有多少点被错误分类)。

我们的两个模型都做得很好,平均精度都达到了 87%。然而,在我们的分类报告中,我们可以看到摇滚歌曲被很好地分类了,但是嘻哈歌曲被不成比例地错误分类为摇滚歌曲。

为什么会这样?

好吧,仅仅通过查看每个类别的数据点数量,我们就可以看到摇滚类别的数据点远远多于嘻哈类别的数据点,这可能会扭曲我们的模型区分不同类别的能力。这也告诉我们,我们的模型的大部分准确性是由其仅分类摇滚歌曲的能力驱动的,这并不理想。

8。平衡我们的数据以获得更好的性能

考虑到这一点,我们可以对每个类别中正确分类的值进行加权,使其与每个类别中数据点的出现次数成反比。因为“摇滚”的正确分类并不比“嘻哈”的正确分类更重要(反之亦然),所以我们只需要在这里衡量我们的类别时考虑数据点的样本大小的差异,而不是每个类别的相对重要性。

我们现在已经平衡了数据集,但在这样做的过程中,我们删除了许多可能对训练我们的模型至关重要的数据点。让我们测试一下,看看平衡我们的数据是否能在保持总体分类性能的同时,改善模型对“岩石”分类的偏向。

9。平衡我们的数据集能改善模型偏差吗?

请注意,我们已经减小了数据集的大小,并且将在不应用任何降维的情况下继续前进。在实践中,当处理非常大的数据集和计算时间变得非常大时,我们会更严格地考虑降维。

成功!平衡我们的数据消除了对更普遍的阶级的偏见。为了更好地了解我们的模型实际表现如何,我们可以应用所谓的交叉验证 (CV)。这一步允许我们以更严格的方式比较模型。

10。使用交叉验证评估我们的模型

由于我们将数据分割成训练集和测试集的方式会影响模型性能,CV 尝试以多种方式分割数据,并在每次分割时测试模型。虽然有许多不同的 CV 方法,都有各自的优缺点,但我们在这里将使用所谓的 K 倍交叉验证。K-fold 首先将数据分成 K 个不同的大小相等的子集。然后,它迭代地使用每个子集作为测试集,同时使用剩余的数据作为训练集。最后,我们可以汇总每个折叠的结果,得到最终的模型性能分数。

现在,我们已经对我们的数据集执行了 k 倍交叉验证,我们可以非常确定我们的模型将在未来看不见的数据点上概括 72%的时间。

来源:www.datacamp.com/projects/44…

基于自动视觉的猫狗图像分类

原文:towardsdatascience.com/classifying…

我第一次正式接触谷歌云平台是在 2018 年 11 月参加 CalHacks 5.0 的时候。我很快发现他们的云 AI 套件由一系列机器学习产品组成——Cloud AutoML、Cloud Natural Language、Cloud Vision API,仅举几例。

在本学期早些时候我的一次 DataX 课上,我们使用 Python Keras 库对猫和狗的照片进行分类。这给了我用类似的数据集工作的想法。出于一个更无聊的原因,我的兄弟们非常喜欢宠物(尤其是猫和狗),我认为部署这种模型对他们来说也是一件有趣的事情。

通过 Keras 进行图像分类通常需要我(1)找到并标记数据集;(2)训练一个 ML 分类器;(3)部署 ML 模型;& (4)使用 REST API 创建一个服务器来调用 web 上的 ML 分类器。

多亏了 Cloud AutoML,我们只需要执行上面的步骤 1!

数据集:猫和狗的图像

幸运的是,为此目的找到一个合适的数据集并不是一件容易的事情。我输入“kaggle 猫狗数据集”,这个链接作为谷歌搜索结果之一弹出。我分别选取了 150 张猫狗的图片,将这些图片导入到云平台上。之后,我给每张照片贴上“狗”或“猫”的标签。

Uploading a total of 300 images for the model (150 each for cats and dogs respectively)

培训和评估

下一步是训练模型。默认情况下,AutoML Vision 在训练模型时会将数据集随机分为 3 个独立的集合。

  • 训练数据集:80% —用于训练
  • 验证数据集:10% —用于超参数调整和决定何时停止训练
  • 测试数据集:10% —用于模型评估

对模型进行训练和评估后,我发现了以下情况:

Precision and Recall values for the Model

准确率和召回率都是 100% —这意味着什么?从所有被分配了猫/狗标签的测试示例中,所有的测试示例实际上都被准确地分类了。并且,在所有应该被分配了猫/狗标签的测试例子中,所有的例子实际上都被分配了正确的标签。

根据混淆矩阵,ML 模型能够准确地对所有照片进行分类(100%)。毕竟没有那么令人困惑。

用新图像进行预测

接下来,我用新图像测试了 ML 模型。我下载的数据集实际上有超过 10 000 张图片,所以我随机选择了一张狗和一张猫的图片,并将这些图片上传到模型中。

I uploaded an image of a cat for prediction, and the model was able to predict with 100% accuracy that it was indeed a cat!

Also predicted with 100% accuracy that it was a dog!

即使有了新的图像,这个模型也预测得很好。

不过,我不相信。所以我在网上寻找斯芬克斯的照片——这是一种与狗有着高度相似外貌的猫。我想知道 ML 模型是否会与这张图片混淆。

Sphynxes — a breed of cats that resembles dogs; I was mildy surprised to find out that the ML model was still able to classify this 100% with a “cat” label

事实证明,这个模型仍然能够以 100%的准确率预测出这是一张猫的照片。

但是…如果我们有一只猫和一只狗在同一个图像中会怎么样?

看起来这个模型在这里有点混乱——但是这绝对是我需要努力的地方。

滑稽的吉娃娃对松饼挑战怎么样?

你可能已经在互联网上看到了“吉娃娃 vs 松饼”的迷因——这里是。鉴于巧克力碎片松饼(事后看来也可能是巧克力碎片饼干)与吉娃娃的高度相似性,我想测试一下这个模型是否能区分这两者。

看起来它被愚弄了。但老实说,我认为这也可能让人类眼花缭乱。

下一步是什么?

鉴于猫狗分类是一个相对典型的机器学习图像分类问题,算法可能已经针对它进行了良好的训练。我们可以看到,当我们试图将分类问题复杂化时,出现了一些复杂性。

虽然它可能没有最复杂的算法来解决挑战性问题,但它仍然为非 ML 专家提供了一个非常友好的切入点来开始涉足一点 ML!

嗯,下次更好玩的实验!

使用无监督学习基于投票历史对科罗拉多县进行分类

原文:towardsdatascience.com/classifying…

随着选举季节的临近,我想是时候写一写我几个月前做的一个项目了。这个项目围绕一个问题展开,“政治评论家如何判断一个县在历史上是投票支持民主党、共和党还是被认为是摇摆县?”我问了科罗拉多州的两位政治顾问这个问题,他们都以同样的方式回答了这个问题,“根据我们在科罗拉多州工作的经验,我们知道。”作为一名数据科学家和分析型思想家,这个答案并没有让我满意,因此我选择了这个项目。

带着一个问题,下一步是想出我将如何回答这个问题。第一部分是寻找、选择和收集我的数据。由于许多投票信息都是公开数据,我首先去了科罗拉多州的州务卿网站。接下来,我要对将要使用的数据做出一些选择。科罗拉多州州务卿的网站上有所有投票结果,所以我可以从所有可能的结果中选择。我知道,当人们投票给其他人时,投票率会增加,名字越大,也有助于激励公众投票。这让我决定我想要“最高票选举”的投票结果。这些类型的选举往往是人们谈论最多的,也是大多数人投票的原因。出于这个原因,我选择了总统、州长、参议员和国会竞选的投票结果。还有,我只回到了 2012 年。这让我把注意力集中在五年的时间跨度上,包括八场不同的比赛。我的想法是,这些数据足以得到准确的结果,但不能追溯到仅仅了解当前的政治气候。此外,为了简单起见,我只统计了每场竞选中民主党和共和党得票最多的人的票数。

在设置了我的数据参数并在科罗拉多州州务卿的网站上找到数据后,在训练一个模型之前,我必须做一些清理和加入工作。获取信息的最佳方式是从网站上复制下来,粘贴到 excel 电子表格中。(我知道懒惰,但这比使用可下载的杂乱无章的 excel 电子表格或废弃更乱的网站要容易得多。有时候你得做最容易的事。)当我得到可用格式的数据时,是时候为一些比赛做一些连接了。这对于所有的国会竞选都是必要的,因为有些国会选区会将县分开。例如,博尔德县是国会第二选区和第四选区的一部分。在这种情况下,我将博尔德县第 2 区和第 4 区的民主党人的选票相加,得到博尔德县民主党人的总票数。我对共和党的选票和其他几个处理分裂选区的县也采取了同样的做法。为了使数据正常化,我计算了每个政党总票数的百分比。这将使我能够更好地比较不同大小的县,无论是大县还是小县,都不会影响或扭曲我的模型。

我的下一步是建立一个模型。对于这种类型的问题,我知道我需要一个无监督的学习模型,因为我没有目标变量来训练模型。对于那些不熟悉无监督学习的人,我能找到的最好的单一定义来自 Techopedia。

www.techopedia.com/definition/…

旁注,但无监督学习已经慢慢成为我最喜欢的方法来分析数据,找到我看不到或想不到要寻找的模式。我认为它难以置信地未被充分利用,并且可以为人们试图解决的许多问题提供价值,但是,这可能是另一个博客的话题。无论如何,我强烈建议人们去调查一下。

我需要用来解决这个问题的模型类型叫做聚类模型。我想看看哪些县的表现彼此相似,并对它们进行分组标记。我知道两种主要的聚类无监督学习模型,K-Means 和 DBSCAN(基于密度的含噪声应用空间聚类)。虽然这两个模型都是无监督聚类模型,但它们之间有一个很大的区别。K-Means 让您选择模型将找到多少个分类,而 DBSCAN 将选择模型将自己给出多少个分类。虽然这两个模型都适用于这个数据集,但我的问题陈述要求 3 个不同的群体,共和党、民主党或摇摆派。因此,我使用 K-Means 纯粹是因为我能够设置我的模型将搜索的聚类数。

在运行 K-Means 模型时,它会根据所分配到的分类为每个数据点分配一个数字。我选择 K=3,这是我想要的 3 个集群,这些数字是 0、1 和 2。根据我的问题背景,为了找出这些数字的含义,我用配对图绘制了我的数据点,并将图形的色调设置为模型给该点的标签。在对图表的标签进行了一些分析和放大之后,我确定了每个标签的含义,并将它们重新标记为 DEM、REP 或 Swing,以便于理解。

为了仔细检查我的模型并查看我的结果,我将所有的数据转移到 Tableau,并在那里绘制每场比赛。当我仔细查看我的结果时,我开始注意到我的摇摆或“中间”分类并没有徘徊在投票范围的中心。

这些县中的大多数总是投票给共和党。虽然这一分类是科罗拉多州中三分之一的县,但它不包括在投票百分比方面仅徘徊在中心标记附近的县(每个政党的投票百分比相等)。这让我回到我的数据,并尝试一个不同的模型。我接下来尝试的型号是 DBSCAN。结果不如我已经试过的 K-Means 模型那样好。大多数县将导致“-1”分类。这意味着数据点噪音太大,无法对模型进行分类。即使在测试不同的最小样本和不同的 EPS 值后,(EPS 是两个点的最大距离,可以被认为是相同的分类),大多数县仍然被归类为“-1”。由于大多数点没有被分类,我知道 DBSCAN 模型不会满足我的需要。

我的下一步是回到 K-Means 模型,在模型中尝试不同的 K。我试过的不同 K 是 4,5,6。粗略地看了一下每个模型的结果,我知道我更加接近我所寻找的了。我将这些结果加载到 Tableau 中,并能够仔细查看每个模型以查看分类。我知道超过 3 个分类,我需要更多的标签名称,而不仅仅是民主党,共和党和摇摆。我将在民主党和共和党前面添加“精简”、“安全”和“稳固”等词,以便在对这些新标签进行分类时给我一些灵活性。

K-表示其中 K=4 包括标签;精简的民主党,精简的共和党,坚定的民主党,坚定的共和党。

虽然我认为 K=4 的 K-Means 模型在对县进行分类方面比 K=3 模型做得好得多,但它不能识别我正在寻找的“摇摆”县。

K-表示其中 K=5 包括标签;Leam 民主党,Lean 共和党,Safely 共和党,Solid 民主党和 Solid 共和党。

K=4 和 K=5 的主要区别在于,新的分类(我称之为安全共和党)是 K=4 的坚定共和党的一个子部分。这个模型没有提供太多新的信息,也没有识别出我要寻找的“摇摆”县。

K-表示其中 K=6 包括标签;摇摆不定,精益民主党,精益共和党,安全共和党,坚实的民主党和坚实的共和党。

就是这个。我能够确定四个郡正好位于投票范围的中间。虽然共和党人确实倾向于赢得这些县,但通常情况下,这场比赛在几个百分点之内,民主党人在这些县中获胜,这足以赢得“摇摆”的分类。这些县是 K=4 和 K=5 模型中精益共和党分类的一个子部分。下面是科罗拉多州的全貌以及每个县的分类。

现在戴上政治迷的帽子,为感兴趣的人谈谈我发现的一些有趣的事情。

在进行这个项目的过程中,有几场比赛吸引了我的注意力,我发现它们很有趣。引起我注意的第一批比赛都是众议院的比赛。首先引起我注意的是这些比赛是所有图形中线性度最低的。此外,众议院的比赛也是最混乱的分类。这是因为众议院选举不是全州范围的选举,每个地区都有自己的竞选人。这使得每个人都有很高的机会在选举中表现异常,导致上面图中提到的差异。一个很好的例子是 2016 年的选举,如下图所示。

另一个有趣的点是,每年的高姿态比赛比当年的其他选举更加线性。总统竞选往往是最引人注目的竞选,也往往有最高的投票率。当用图表表示时,这些往往比州长、参议院或众议院的竞选更加线性。以下是 2012 年总统竞选和 2014 年州长竞选。

我想说的最后一点是关于 2014 年的州长竞选,如上图所示。这是两个级别之间交叉最少的比赛,实际上根本没有交叉。我不知道这是不是侥幸,因为我的数据中只有一次州长竞选。如果这不是偶然的,其他州长竞选也是如此,那么可以肯定地说,了解科罗拉多州的最好方式是通过它的州长选举。

要查看其余的图表,请访问我的 Tableau 公开简介:public.tableau.com/profile/cbj… 要查看用于此的代码,请访问我的 GitHub:github.com/CBJohnson30

危机报告分类

原文:towardsdatascience.com/classifying…

这篇文章描述了我对日益增长的不稳定性的解决方案:由英国科技部、军情五处和军情六处组织的危机报告分类挑战。该解决方案在 579 个竞争对手中获得第三名。 链接到最终排行榜

任务描述

文本分类是给一段文本分配一个类别或范畴的任务。它是自然语言处理领域的一个分支,在情感分析、垃圾邮件检测和标签等方面都有应用。在这个挑战中,目标是用危机标签对《卫报》的文章进行分类。标签的几个例子是“澳大利亚安全和反恐”,“集束炸弹”,“埃博拉”,“法国火车袭击”,“美国枪支控制”。

挑战提供了一个训练集和一个测试集。训练集包括从 1999 年到 2014 年的所有新闻文章及其标签。大约有 160 万篇文章。测试集由 2015 年和 2016 年的文章样本组成。主题词典提供了所有的危机标签。主题词典中共有 160 个标签。标签可以分为两种类型:

  • 围绕特定事件的话题。例如“里约 20 地球峰会”、“突尼斯袭击 2015”。与这些主题相关的文章通常只在某一段时间内(一个月或一年)出现
  • 围绕概念的话题。例如“伦理”、“印度”、“德国”。与这些主题相关的文章在大多数年份都有。但是,内容每年都不一样。

任务的评估指标是微观平均 F1 分数。这是通过对测试示例的每个单独决策的真阳性、假阳性和假阴性求和来获得的,以产生其中每个测试示例(文档)被同等加权的全局平均值。

F1 得分= 2×TP / (2×TP + FP + FN)

数据集探索和基线

大多数文章的标签不在主题词典中。训练集中大约有 235,000 篇文章具有出现在主题词典中的标签。我们使用这个子集进行开发和验证。

Fig 1: Number of articles per topic

一些主题如“英国犯罪”、“伊拉克”、“宗教”和“移民”有大量的文章(超过 15000)。大多数题目至少有 100 个例子。有趣的部分是 12 个主题没有任何文章。分别是'布鲁塞尔袭击'、'巴士底日卡车袭击'、'寨卡病毒'、'奥兰多恐怖袭击'、'柏林圣诞市场袭击'、'查理周刊袭击'、'突尼斯袭击 2015 '、'圣贝纳迪诺枪击案'、'巴黎袭击'、'和平与和解'、'土耳其政变企图'、'法国火车袭击'、'激进主义'、'慕尼黑枪击案'。这些主题大多是发生在 2015 年和 2016 年的事件(除了“和平与和解”和“激进主义”),因此没有关于它们的培训数据。

这个挑战是一个多标签分类的例子,其中多个标签可以分配给每件商品。我把标签编码成一个 160 维的热向量。我尝试的两个基线是单词包和平均单词向量。在前一种情况下,我将文章转换成一袋单字和双字,并使用它们的频率作为特征。在后者中,我首先使用训练集来训练 300 维的单词嵌入。然后我把每篇文章转换成一个 300 dim 的均值嵌入。前一个特征集是稀疏向量,而后一个是密集向量。我在这两个特征集上应用的两个机器学习算法是前馈神经网络和梯度推进决策树。F1 的最佳基线得分为 0.38。

体系结构

我在这次挑战中使用了两种方法:

  • 在训练集中有文章的主题的监督学习。这让我在公开数据上的 F1 分数达到了 0.64 左右。
  • 用于在训练集中没有文章的主题的规则引擎,其在公开数据上将上述分数提高到 0.6626 F1 分数。

对于监督学习部分,这里是我实验的算法。所有模型都是用 Keras 实现的:

  • **卷积神经网络:**CNN 是用于文本分类的常用模型之一。Kim Yoon 关于用于句子分类的卷积神经网络的论文是一个很好的起点。我通过修改过滤器的数量、池大小和过滤器大小来试验不同的架构。我还用预先训练的手套向量、谷歌新闻向量和输入数据上训练的嵌入进行了实验。对我有用的架构是使用在输入上训练的嵌入。随后是 5 个卷积层,滤波器尺寸为 3、5、7、9 和 11。在这之后,有一个合并层,然后依次是 3 个卷积,池和辍学层。最后一层是尺寸为 160 的 softmax 层。 模型的最后一部分是确定每个主题的阈值。最初,我尝试将所有主题的阈值设为 0.5。然而,为每个主题选择不同的阈值有相当大的提升。阈值是在验证集上学习的。最好的成绩是 F1 得分 0.615。

Fig 2: CNN architecture diagram Source: www.aclweb.org/anthology/D…

  • **具有 softmax 层的双向 LSTM:**这是另一种用于文本分类的通用架构。基本层是单词嵌入,接着是双向 LSTM 层和 softmax 层。在对这个模型做了一点试验后,我意识到它有两个缺点。首先,与 CNN 模型相比,它在每个时期花费了大约 3 倍的时间(所有训练都是在 AWS p2.xlarge 中完成的,其中有 Tesla k80 GPU)。二是性能比 CNN 机型差很多。最好的 F1 成绩是 0.52。因此,我决定不再继续这种模式。

Fig 3: LSTM network for classification Source: deeplearning.net/tutorial/ls…

  • **关注 GRU 网络:**我试验的下一个模型是 GRU 网络上的关注层。gru 在某种意义上类似于 LSTMs,它们使用门控机制来学习长期依赖性。然而,它们具有较少的门(它们没有输出门),因此具有较少的参数。他们的训练速度相当快,F1 分数为 0.621。
  • **分层注意模型:**该体系结构首先由杨等人在论文【用于文档分类的分层注意网络】中提出。艾尔。这个模型的独特之处在于,它有两个层次的注意机制,既适用于单词,也适用于句子。这有助于它有区别地识别更多和更少的重要内容。我在这里使用了 Richard Liao 实现的模型。这个模型的优点是,当我们查看给定文本的注意力权重时,我们可以了解哪些单词和句子对标签有贡献。这对于调试非常有用。这也被证明是最佳的单一网络模型,F1 值为 0.626。

  • **以上模型的叠加:**在检查了这些模型的输出后,我意识到,对于很多题目来说,输出并不是高度相关的。这为堆叠这些模型提供了机会。我使用开发集的交叉验证,从每个模型中创建了一个 160 维的特征向量。这导致了一个 640 维的特征向量,我通过一个前馈网络。该网络有两个隐层,分别为 480 和 320 个单元。这给了我最好的 F1 成绩 0.6415。

到目前为止,我对没有训练数据的主题的预测为零。由于许多话题都是欧洲的重大恐怖袭击,我预计《卫报》会有大量报道。我试验的最初模型是检查文章中是否存在主题字符串。例如,对于主题“巴黎袭击”,将所有具有字符串“巴黎袭击”的文章标记为真。但是这个模型导致了召回率的损失,并且没有特别高的精度(与《查理周刊》袭击事件相关的文章也有‘巴黎袭击’这个短语)。该模型的下一次迭代涉及使用主题字符串中所有标记的计数作为特征,并使用手动阈值进行区分。然而,选择最佳阈值是困难的,我没有取得任何重大进展。

到目前为止,我还没有在任何文章中使用过的一个特性是文章的日期。这在这里很有用,因为在袭击发生之前不会有关于“巴黎袭击”的文章。另一个认识是,在攻击后的几天内,它的主题标签和攻击位置的主题标签有很高的相关性。例如,在巴黎袭击之后,标签“法国”和“巴黎”与“巴黎袭击”有很强的相关性。我使用这种相关性来创建一个种子文章集,这些文章极有可能属于新标签。考虑作为种子集一部分的文章是在攻击当天到攻击后一周内发表的文章(对于覆盖范围更大的攻击,这可能会增加)。然后,我建立了一个命名实体袋监督学习模型,以在结束后对文章进行分类(我最初尝试使用单词袋,但它给出的结果比命名实体袋差)。对于模型的反面例子,我使用了该日期之前文章的随机样本。这在实践中效果很好,我能够在公共数据集上获得 0.6626 的分数。

未来的工作

我很想在未来探索一些想法,但是没有足够的带宽:

  • 为每个主题标签建立一个模型,而不是一个统一的模型。
  • 将所有的 CNN、RNN 和注意力模型合并成一个大的神经网络,而不是堆叠。
  • 探索没有训练数据的主题的替代模型。
  • 更好地利用日期特性进行分类。直觉上,一篇 1999 年的文章和一篇 2014 年的文章权重相同是没有意义的。

不幸的是,作为竞赛协议的一部分,我们不得共享数据和代码。但是,希望这篇文章对所有文本分类从业者有用。

利用机器学习对市场库存进行大规模分类

原文:towardsdatascience.com/classifying…

克里斯 联合创始人&CTO attop hatter。这最初是向我们的工程团队内部发布的,但我们决定向其他对学习如何将机器学习应用于大规模分类问题感兴趣的人开放。

为什么这很重要?

分类法在像 Tophatter 这样的市场中扮演着几个重要的角色。

**对于购物者:**它支持浏览&深入体验,有助于信息检索。直觉上,我们期望一条通向客户关心的产品集的高效路线胜过一条低效路线。

对于 Tophatter: 是商业智能的一种形式。更具体地说,这是一种对产品进行分组的有效方法,以便识别关键的异常值(表现优异或表现不佳),并发现存在供需不平衡的领域。这些见解可用于对我们优先考虑的产品分销做出有影响力的改变。在一个典型的日子里,Tophatter 购物者进行近 100,000 次购买,每次购买都代表我们的库存调度算法的一个实例,该算法从数百万个产品中选择一个特定的产品进行优先排序。为了做出明智的选择,这种调度算法需要很好地理解产品是什么,以及它的性能如何。分类法是元数据的关键部分,它使调度算法能够做出明智的决策。

有哪些挑战?

对于一个有用的分类法,它应该是(1)正确地应用于所有产品,(2)易于使用,以及(3)当新的产品类别弹出时易于改变(有人坐立不安吗?).这具有挑战性,原因如下:

  • **(1)正确性:**市场通常依靠销售者对产品进行分类。这总是会导致一些不正确的分类。
  • **(2)易用性:**分类法可能经常很大而且不明确——一个产品可能看起来适合多个分支。此外,没有“标准”分类法。亚马逊、易贝和谷歌都有自己的,具体程度差别很大。这种复杂性在向市场添加库存时会引起摩擦,因为销售者必须将他们的内部分类映射到特定于他们希望销售的市场的分类。这既烦人又容易出错。
  • **(3)易更改性:**向分类中添加一个新节点很容易,但是我们将如何对应该映射到这个新节点的现有产品进行重新分类呢?删除节点也有同样的问题。

我们如何解决这个问题?

一种选择是定义一组标签来表示我们库存中不同类型的产品,手动将这些标签应用于我们产品的子集,并采用机器学习技术来训练分类器,以准确预测给定产品的适当标签。

让我们来看看这个解决方案的利弊:

赞成的意见

  • 如果我们的模型是好的,我们解决了“正确性”问题。不再有人为失误。
  • 从卖家的角度来看,它非常容易使用——系统会自动对每个产品进行分类,因此卖家什么都不用做!
  • 在大多数标签系统中,添加或删除标签很简单,如果我们的标签集发生变化,我们可以每天自动对产品进行重新分类。

骗局

  • 标签没有层次结构,而层次结构对于浏览/下钻很有用。
  • 该系统需要大量的人工工作来为产品手工贴标签,以便生成训练数据。此外,还有维护成本。我们需要一个反馈循环来增加我们的训练数据,这样我们的模型才能不断改进。
  • 这个系统比卖家给自己的产品分类的系统更复杂。复杂得多。它需要一个数据管道来推动未分类的产品通过分类器并存储结果。

让我们假设这是一个合理的解决方案,并探索一个简单的实现。

标签工具(Ruby,Rails,JS)

后端

有许多优秀的通用对象标记实现可用于各种 web 框架。对于 Rails,acts-as-tagable-on是一个很好的选择。

假设您有一个Product模型,您可以通过以下方式启用标记:

给产品添加标签就像product.tag_list.add('foo')一样简单。

前端

为创建、添加和删除标签构建一个良好的前端是至关重要的,因为管理标签的过程是生成我们需要的数据以训练我们的模型并随着时间的推移对其进行改进的过程。

为此,我选择使用一个与 Bootstrap 兼容的 jQuery 插件, bootstrap-tagsinput ,它允许我们快速地异步添加和删除标签。它还支持与 typeahead.js 的集成,因此我们可以执行标记自动完成,以加快标记速度并减少错误。

在我们的后端之上构建了一个前端标记工具之后,我们得到了以下结果:

机器学习(Python,Scikit-Learn)

给定一组用标签正确标记的 k 个产品示例,训练分类器来预测标签相对容易。我们将使用 scikit-learn 来完成这项工作。

培训用数据

为了让我们开始,我使用上面的标签工具来标记我们几百个最畅销的产品。决定一个框架来指导标记过程是很重要的,并且应该由您的分类法用例来指导。你需要知道需要什么样的特异性。我的经验是生成包含 3 个或更少单词的最具体的标签。比如,我没有选择“戒指”,而是选择了“[材质]戒指”(即“纯银戒指”)。我没有选择“平板”,而是选择了“安卓平板”。

这个手动标记步骤完成后,我将全套标记产品导出到一个 CSV 文件中。这是我们的训练数据。

我们可以很容易地用pandas加载它:

让我们快速浏览一下数据:

这些标签似乎对这些产品名称有意义。以下是标签在我们数据集中的分布情况:

有些标签没有很多例子。当预测在训练数据中不经常出现的标签时,我们的模型可能不会做得很好。这是我们可以在数据生成反馈回路中解决的问题。稍后会详细介绍。

特征探索

可以说,解决这种类型的机器学习问题时,最重要的步骤是探索训练数据,并搜索可能产生良好预测的特征。这可能需要一段时间。

为了简单起见,我们假设一般来说,产品的标题是标签预测的一个重要特征。实际上,有几个其他产品属性会非常有用(例如,描述、材料、价格、卖家等),我们应该尝试使用所有这些特性。

特征转换

为了将标题转换成我们可以用来使我们的模型适合我们的训练数据的向量,我们将使用CountVectorizer:

我们的词汇表中有大约 11K 个单词。现在让我们将标题转换成向量:

让我们检查一个特征向量:

注意,它只在内存中存储向量的非零部分。这个向量表明,我们的文本包含一个出现在索引241的单词,一个出现在索引1508的单词,等等。

培养

让我们使用多项式朴素贝叶斯分类器来拟合我们的训练数据:

让我们在不在我们的训练集中的产品上测试分类器:

该分类器似乎工作…至少对于坐立不安纺纱。我想知道它和热狗会有什么关系?😃

我们来看看分类器有多准确。我们将使用 70%的数据进行训练,然后使用剩余的 30%来测量准确性。

我们得到大约 96%的初始精确度。

根据最佳实践,我们应该始终有一个比较基准。为此,让我们将我们的结果与随机算法进行比较:

毫不奇怪,随机猜测很糟糕(即使分层)。

网格搜索优化

现在,让我们创建一个适当的管道,并使用网格搜索来调整CountVectorizer参数。你可能已经注意到我们没有使用停用词。相反,我们将调整我们的最小和最大文档频率参数,这将自动过滤掉出现频率过高(如停用词)或过低的单词。

你还会注意到我们引入了二元语法的概念——这为相邻词对的特征向量增加了列,可以改进我们的算法。当我们考虑相邻单词之间的关系时,我们将使用网格搜索来看看我们的算法是否更好。

这是我们的网格搜索尝试:

让我们以 70% / 30%的比例尝试这些参数:

不错——我们改进了一点。

其他分类器

现在让我们尝试一些不同的分类器,看看它们的表现如何:

看来LogisticRegression大有可为。我们暂时坚持这一点。

推算概率

当我们对产品的完整库存运行模型时,我们会遇到现有标签都不合适的情况。随着时间的推移,我们将希望扩展标签集,以包括几乎所有产品的适当标签,但我们还没有做到这一点。因此,我们想要抛弃明显不好的预测。

我们可以询问分类器,对于我们集合中的任何标签,它认为正确的概率是多少。这里有一个例子:

注意,我输入了一个标题,专门引用了两种不同类型的产品。分类器发现 2 个标签高于 0.1 的概率阈值。

反馈回路

我们需要弄清楚什么是合理的门槛。现在,我们将只选择概率最高的标签,并构建一个验证工具来显示概率,并允许人们接受或拒绝预测(确保跳过有把握的预测,以防止不必要的工作)。在这个过程中,我们可以添加新的标签来构建我们的标签集,并通过纠正错误的预测来改善我们的训练数据。这是使我们的模型表现良好的关键反馈循环。

这是我们验证工具的预览,它允许我们快速接受、拒绝或修正预测:

如果您想要快速改进模型,使该工具高效且易于使用是至关重要的。

投入生产

最后一步是弄清楚如何将未标记的产品输入到这个模型中,并通过验证工具持久化消费预测。如果您的产品数据库很大(就像我们的一样),您可能会希望使用 build 来处理大量数据,比如 Spark。你甚至可以相对容易地将这个 scikit 模型移植到 Spark ML 上。也许这是未来的博客文章🙂).

如果你的产品数据库没有数百万行,你可以在一个简单的 Python 脚本中做任何事情——如果你喜欢使用 ORM 进行数据库读/写,我们是 SQLAlchemy 的忠实粉丝。

关于 Tophatter

Tophatter Inc 由 Ashvin Kumar(首席执行官)和 Chris Estreich(首席技术官)创建,于 2012 年 1 月推出。迄今为止,该公司已经从 CRV 的古德沃特资本公司和奥古斯特资本公司筹集了 3500 万美元。该公司在全球拥有 75 名员工,并正在硅谷和上海的办公室积极招聘员工。更多关于 Tophatter 的信息,请访问:【www.tophatter.com/about】T4。

用卷积神经网络对皮肤损伤进行分类

原文:towardsdatascience.com/classifying…

医学深度学习指南和介绍。

Photo by Rawpixel on Unsplash.

想象一下。

你醒来后发现皮肤上有一个可怕的疤痕,于是你去医生办公室检查。他们说没事,所以你可以回家,几个月内不要担心,但随后你会从那个地方开始一跳一跳地疼——现在看起来很丑,很危险。由于你的医生的误诊,它已经发展成了恶性肿瘤。误诊的普遍程度很吓人。一项研究表明,超过 1/20 的美国成年人在过去被误诊,其中一半以上是有害的。许多皮肤损伤可能是无害的,但其他的可能会威胁生命。立即发现这些肿瘤非常重要,因为这是治疗它们最容易的时候。

最近,我们看到人工智能已经成为我们日常生活中不可或缺的一部分。我们发现它被用在我们的文本推荐、广告个性化、虚拟助手等等。随着人工智能在这些领域取得如此巨大的进步,它有无限的潜力通过**深度学习对医疗保健产生影响。**考虑到这一点,我着手制定一个端到端的解决方案,使用深度学习对皮肤病变进行分类。

我们可以通过使用卷积神经网络来实现准确可靠的医学图像分析技术,卷积神经网络是一种用于分析图像的深度神经网络。在我们进入 CNN 之前,让我们稍微回溯一下,看看神经网络是如何工作的。神经网络本质上是以类似于人脑工作方式的方式模拟的计算机程序。像我们的大脑一样,神经网络由一大堆神经元组成,这些神经元不能单独做很多事情,但当它们在网络中连接在一起时,可以完成一些非常难以置信的任务。

神经元是做什么的?

A neuron takes in some inputs, operates on it, and gives an output. Source.

神经元的工作很简单,它接受几个输入;让我们称它们为 X1、X2 和 X3,如图所示,然后输出一个结果。每个输入都有一个与之相关的权重系数。这些权重影响神经元的输出,并且它们被不断地改变以获得改进的输出(这更准确)。

把神经网络想象成一群白蚁。一只白蚁本身是微不足道的,并不能真正做任何事情,但当你有数百万只白蚁在一起时,它们可以通过学习并最终进化来完成令人难以置信的任务。

A neural network with 2 hidden layers. Source.

神经网络通常被用作**监督学习的一种方法,**这基本上意味着它们学习如何通过识别数据中的模式来进行预测。我们给它的数据越多,它就越有可能做出更好的预测。但是神经网络如何在我们处理的一些非常复杂的数据中找到模式呢?

它的学习方式与人类相似。首先,它浏览数据并做出超级随机的预测,这些预测根本不太准确,然后它使用一种叫做 反向传播 的技术,从它犯下的错误中学习,然后试图修复它们。它做得越多,预测就越准确。它们甚至经常能够识别人类永远看不到的模式和相互关系!

那么我们如何将这一点应用到皮肤病变的图片上呢?我们使用一种特殊类型的神经网络,称为卷积神经网络。

卷积神经网络

卷积神经网络不同于普通的神经网络,因为它们包含一种特殊类型的层,称为卷积层,它包含一个过滤器,能够理解图像中某些类型的模式。

A graphical demonstration of a filter. Source.

你可以把滤镜想象成手电筒。你将它照射在一张照片的不同部分,寻找一些特征,并在特征图上写下它是否存在(或在多大程度上存在)。通常,位于最开始的图层会被用于一些非常简单的事情,比如边缘检测。随后,图层可以检测更复杂的特征,如眼睛、鼻子和手指。所有这些特征图被放入网络末端的一长串特征中,用于最终对图像进行分类。

除了卷积层,CNN 还包含几个其他层,即池和分类层。

Standard architecture of a CNN

汇集层对于确保 CNN 的训练不会花费太多时间是非常重要的。他们通过**缩小图像的尺寸来做到这一点。**它的工作方式与卷积层非常相似,在卷积层中,过滤器会通过图像,但现在,过滤器会通过数据,提取最重要的信息,并将其放入较小的矩阵中。这使得您的计算机更容易使用。

A Pooling Layer reducing a feature map by taking the largest value. Source.

所有这些层在最后连接在一起,成为一个产生最终分类的soft max函数(分类层)。

构建分类器

让我们开始构建我用来对皮肤损伤进行分类的模型。我使用 native Keras 构建了 CNN,如果您没有机器学习的经验,请不要担心,通过本指南,您应该能够很好地理解它是如何工作的!我使用了转移学习来创建这个模型,这意味着我使用了一个叫做 MobileNet 的预训练网络**,它是用超过 1400 万张图像的数据集 ImageNet 训练的,并且给它添加了一些层,所以它可以对皮肤病变进行分类。这个想法是,我们采用一个用大量数据训练的模型,并将其用于我们没有那么多数据的新任务。通常,这有助于**提高最终模型的准确性,并减少训练时间!****

我们使用 MobileNet 主要是因为它的速度**。当我开始做这个项目时,我遇到的一个问题是像 Resnet50 这样的模型在训练速度和实时预测方面的性能非常差。**

是什么让 MobileNet 更快?

之前,我解释了卷积层如何通过图像上的过滤器。当图像有不止一个颜色通道时(RGB 有 3 个通道),这很难计算。这就是深度方向可分离卷积发挥作用的地方。这就是 MobileNet 的特别之处,也是它比其他网络快得多的原因。

深度方向卷积将卷积过程分为两步。它将滤镜传递给图像中的每个单独的层,使滤镜的深度为 1。如果有三层,红色,绿色和蓝色,它将通过不同的过滤器通过每一层。之后,它通过一个称为逐点卷积的过程,对所有层应用 1x1 卷积来合并层。深度方向可分离卷积的总计算量比标准卷积低8-9 倍**,这使得它能够在移动设备上运行!我简单地看了一下,如果你想更好地理解深度方向的卷积,看看这篇论文。**

10000 哈姆

HAM10000 数据集中,我们将获得训练模型所需的图像。这是 7 种不同类型的皮肤损伤的大约 10,000 个标记图像的集合。

这些是在数据集中发现的病变类型:

  • 光化性角化病
  • 基底细胞癌
  • 良性角化病
  • 皮肤纤维瘤
  • 恶性黑色素瘤
  • 黑素细胞痣
  • 血管病变

你可以在这里找到更多关于它的信息。

现在我们来看一下代码。

我们从导入我们需要的所有库开始。一大堆 Keras 进口需要构建我们 CNN 的不同部分。我们还导入了 NumpyitertoolsScikit-Learn 。随着我们的发展,我们将探索这些功能的用途!

现在,让我们声明一些变量,这些变量在以后会对我们有用。我们设置了一些变量,这些变量包含了训练数据和评估数据的位置,这样我们更容易处理。样本的数量就是我们使用的数据集中有多少图像。批量大小是指在网络权重更新之前您处理的图像数量。我们输入到神经网络的图像的大小是 224x224,稍后我会详细介绍这一点。最后,我们需要声明网络需要向前/向后传递多少次,直到它分析了每一张图像,我们可以通过将数据中的图像总数除以批量大小,然后取整来完成。

我们需要做的另一个真正重要的步骤是数据预处理**,因为我们使用的是 MobileNet 的迁移学习。我们需要重新训练这个网络中的几个层,以便它能处理皮肤损伤图像。注意,MobileNet 接收 224x224 尺寸的输入图像,我们需要预处理数据以符合这个标准。**

在这里,我们对网络进行了一些重要的更改。MobileNet 模型通过添加一个丢弃层和一个密集输出层进行了修改。我们使用 dropout 来防止过度拟合数据。当网络变得非常非常擅长对你给它的数据进行分类时,这种情况就会发生,但除此之外就没什么了。在添加这一层之后,我们添加最后的致密层,它具有附加的激活功能。这需要它收集所有的特征地图,然后给我们预测。在我们对网络结构做了这些改变后,我们想冻结一些层来加快训练速度。在这种情况下,我们冻结了除最后 23 层以外的所有内容,因此我们的图像数据仅在 MobileNet 的最后 23 层上进行训练。

既然我们已经微调了我们的模型,我们需要创建几个度量来确定我们的模型有多精确。然后我们为我们的模型编辑所有的信息,这样它就可以被训练了。对于训练,我们使用 Adam 优化器分类交叉熵损失函数。本质上,损失函数测量模型预测的错误程度,优化器改变权重,试图使模型更加准确。这两个函数在机器学习中非常重要,你可以在上面的链接中了解更多。

现在,最后,我们训练模型,将我们上面创建的所有组件拼凑在一起。程序将此保存到文件中,如果我们想要实现这个模型,这是至关重要的。

该模型获得了大约 85%的准确率,用 HAM10000 数据集进行了测试,但是,我预测在现实世界中它不会那么可靠。当然,这个问题很容易解决,只要有一个更大的图像集合来训练它,并在更广泛的环境中进行训练。

为了在网络上运行这个,我将 Keras 模型转换为 TensorflowJS 模型,并且能够通过遵循这个指南很容易地在网络上实现它。

你可以在我的网站上看到这个模型的实现这里,如果你想仔细看看这个模型,一定要看看我的 GitHub

Web implementation of the model.

这里是模型的 web 实现,我已经提供了项目的描述以及一些关于皮肤损伤类型的信息,来源于这里

如果您没有任何图片来测试它,我还为每个类提供了一些示例图片。该模型在非皮肤背景的病变图片上表现不太好,因为它没有经过这样的图像训练。正如我上面所说的,从 HAM10000 数据集计算的准确性约为 85%,虽然这对于医疗用途来说肯定是不够的,但专业支持和更大的数据集将产生一个可用于临床使用和家庭诊断的模型。

像这样的技术的影响是巨大的。通过使用人工智能技术,我们有可能消除临床上的误诊,就像这样。我们拥有的数据和支持越多,它就越能成长并变得更加准确。只有 10,000 张图像,我们达到了大约 85%的准确率,但是想象一下,如果我们有数百万张图像,会有多好。这些模型将拥有医生的技能,医生已经看过并从数百万张图像中学习。你能想象吗?

人工智能已经在扰乱医疗保健领域。随着我们继续将它纳入主流医学,治疗和诊断的质量将会大大提高。我们已经看到人工智能取代了许多制造和文书工作,但许多人不认为人工智能对医疗保健这样重要的领域有影响。通过使用人工智能进行诊断,我们可以消除可预防的疾病,并创造一个我们不再需要担心获得准确诊断的未来。

如果你喜欢我的文章或者学到了新东西,请务必:

一个数据科学家的干净代码(?)

原文:towardsdatascience.com/clean-code-…

Keep it clean!

“我是一名数据科学家..我不需要写干净的代码,因为我的大部分代码都是一次性的”。“干净的代码和敏捷有利于软件开发..这在我的作品中毫无意义”。我听到上面这些话的次数&甚至不愿意尝试一些关于干净代码的建议,让我困惑。

让我告诉你..你也不需要为软件开发写干净的代码。你也不需要为软件开发实践敏捷。即使没有上述内容,你也可以制作一个完美的软件(维护/修改/扩展会变得困难。但这不是本文的重点)。当你在团队中工作时,你需要遵循干净的代码实践!不管你是在开发一个软件还是一个算法,或者必须尝试多种算法。

干净代码的基本思想是你的团队成员应该能够理解你写的东西。这在数据科学中尤其重要。作为一名科学家,你的实验必须是可重复的。必须可以验证。这意味着你团队中的其他人应该能够理解&重现你的结果。

我们存在于一个团队中。一个人做数据科学家是不可能的。在工业界,大多数时候你会从事应用科学的工作。这意味着你必须理解其他人的问题&他们(团队、业务人员)也需要理解你的解决方案。

作为一名数据科学家,您将与团队的以下成员(不限于)频繁互动:

其他数据科学家/数据分析师(此处可互换使用)—在算法、模型、结果解释、特征工程等方面与其他数据科学家协作。

数据工程师——你不想最终自己处理所有的数据。数据工程师可以优化查询,在最短的时间内获得综合结果。他们需要了解你需要什么数据。

业务分析师(BA)/领域专家—从业务角度来看,您的结果意味着什么?BAs 需要了解您的输入变量意味着什么&您的结果将对业务产生什么影响。从本质上理解这个领域。

既然我们已经确定了协作对于数据科学家的重要性,那么让我们来谈谈通过代码使协作变得有效的方法。这些是唾手可得的果实:

1.有意义的名字——你的团队成员不应该问你变量是什么意思。使用能清楚表达意图的名称。名字长是可以的。解决这个问题的方法是使用更好的编辑器(这样你就不必每次都输入完整的变量名)&不要缩短变量名从而使它变得晦涩难懂。还有,请不要神奇的数字

2.避免心理映射——你知道你的代码中的哪些参数需要改变以获得想要的结果。其他人没有。如果你必须记住所有需要同时改变的变量,那么你就是在浪费团队的大量时间。有人(包括你)会忘记改变其中一个变量而运行代码。这意味着运行是一种浪费&代码需要重新运行。考虑到一些算法需要的时间,这应该是一个

3.难道T5 对同一个东西有多个名字**。一旦你们团队决定了,就要坚持下去。**

4.使用商业域名名称。保持你的创造力来设计特征、分析、创建模型。不要发明名字。

5.评论很快就过时了。代码总是说真话。因此,通常不鼓励评论。这同样适用于数据科学代码。但是,我会在这里破例—添加一些评论,表明您使用/不使用某些型号/功能的意图。可以评论:“这将需要 5 个小时”或“使用径向基核 SVM 以加快收敛”

6.模块化你的代码。理解一个大斑点并不容易。不管它现在在你脑子里有多好。在以后的时间里,你会花时间去理解它。其他人需要时间来理解它。为什么?因为人们必须仔细阅读每一行代码才能理解它在做什么。当你创建的函数正如它的名字所说的那样,你不需要遍历它里面的每一行。读者仍然会理解正在做什么。

7.不要重复自己!不要复制和粘贴那些代码行,因为你在别的地方也需要完全相同的东西。在一个函数中提取出来&重用那个函数。这确保了一致性。

8.单元测试 —是的,它们与数据科学代码非常相关。数据科学代码还是代码!测试您的函数,这些函数根据将要采取的业务决策产生数字,这变得越来越重要。为什么你甚至没有想到测试你的函数会有这么多的反响。你所有的功能都应该被测试,以确保它们做你期望它们做的事情。写一个识别平稳信号的函数?用一个稳定的信号来测试它,确保你的函数返回这样的信号。

9.格式 —决定你们团队想要遵循的格式。这包括在缩进、目录结构、文件命名约定、输出结果格式等方面使用空格还是制表符。

我完全赞成以一种快速而肮脏的方式尝试各种事物/方法/模式。这对于理解一个人应该在哪个方向投入多少时间非常有效。但是,一旦你最终确定了你的方法,并将其融入到你的工作代码中,一定要清理干净。以上所有的概念都有助于人们作为一个团队工作。我发现它很有用,即使我独自工作。它帮助我在以后的某个时间点理解我的工作。它让我能够解释我的结果&让我能够快速地交叉询问令人惊讶(或震惊)的结果。

《干净的代码》一书很好地解释了上面提到的所有观点。所以,如果你是一名数据科学家&将在一个团队中工作,请阅读&实现干净的代码:)每个科学家都有自己的规则。但是在团队工作的时候,团队是有规则的。

使用无监督的机器学习清理您的数据

原文:towardsdatascience.com/clean-your-…

清理数据不一定是痛苦的!这篇文章是一个快速的例子,展示了如何使用无监督的机器学习来清理堆积如山的杂乱的文本数据,使用现实生活中的数据。

我们在对付什么?

在这个例子中,我们面对的是从 HMTL 和 PDF 文件中抓取的数千篇文本文章。返回文本的质量在很大程度上取决于抓取过程。从抽样检查的一些结果中,我们知道存在从坏链接、不可读的 pdf 到已经成功读入的项目的问题,但内容本身完全是垃圾。

与公司现代奴隶制相关的文章从这个数据库返回:www.modernslaveryregistry.org/

这些现在存在于 Pandas 数据框中,每一项都有“元数据”,如公司名称和出版年份,以及从回复中提取的文本:

This is the starting point — the text data is the last column in the data frame

快速题外话:错过没有

python Missingno 包超级有用。它可以用 4 行代码在数据框上安装和运行,如果数据框中有任何缺失信息,它会快速突出显示。它还能够对数据集中的行进行采样,因此可以轻松处理非常大的数据帧。

!conda install -c conda-forge missingno — y
import missingno as msno
%matplotlib inline
msno.matrix(combined.sample(250)) #combined is the df

在我们的数据框上运行这个程序,显示出除了一列之外,数据是完整的。由于我们不使用它进行分析,所以不需要做进一步的工作,但是如果在其他区域有缺口,我们必须考虑如何最好地处理这些缺口(例如删除这些行或尝试估算缺失值)。

The chart shows all but one column are complete — we can now focus on our text data

…回到清理文本数据

浏览数据框中的文本显然存在问题。例如,读取此项目中的 PDF 文件时出现问题:

CMR644311ABP 英国现代奴隶制声明 2017 年 9 月)ABP 英国现代奴隶制声明 2017 年 9 月 ABP 英国现代奴隶制声明 2017 年 9 月 AABP 英国现代奴隶制声明 2017 年 9 月 bABP…..

这个看起来更糟:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"#!)%!+!,(-&(#!。/&0#&-!!1!!2–34!5!5/6!!1!!7–8(&9%!!1!!7:;!<=>!.3–8(%&-($9!!!!!!!!!!!!!!学术界有限公司现代奴隶制合规状态。

这些显然是无法修复的——但是我们如何将它们从正确读取的文本文件中分离出来呢?

机器学习拯救世界

我们可能会花费大量时间试图从真实数据中分离出这些损坏的信息,但这正是机器学习的亮点。希望我们可以用它来发现数据中的模式,并自动将其聚类成干净和杂乱的数据,从而节省大量工作。使用 Python,只需三个步骤就能快速轻松地完成这项工作:

第一步。为算法创建特征:

以下代码将单词计数、字符计数和唯一单词数作为新列显示在我们的数据框中:

#The data frame is called 'combined'
def uniqueWords(X):
    X = X.split(' ')
    X = set(X)
    X = len(X)
    return Xcombined['charCount']   = combined['text'].str.len()
combined['wordCount']   = combined['text'].str.split(' ').str.len()
combined['uniqueWords'] = combined['text'].apply(uniqueWords)

第二步。将数据可视化:

使用 Spotify 真正优秀的图表库, **Chartify,**我们可以使用我们刚刚创建的新功能快速绘制数据图表:

ch = chartify.Chart(blank_labels=True)
ch.plot.scatter(
    data_frame=combined,
    x_column='wordCount',
    y_column='uniqueWords',
    size_column='charCount',
    alpha = 0.3)
ch.set_title("Text data quality")
ch.set_subtitle("Size is the character count")
ch.axes.set_yaxis_label('Unique words')
ch.axes.set_xaxis_label('Total words')
ch.show()

这个图表告诉我们大量关于数据集的信息。有明显的词、字、独字增多的趋势。这是意料之中的,但是在这下面还有一大串项目,在底部有一行项目,它们的字数很少,但是字符数很高:

第三步。创建集群:

通过使用机器学习对数据进行聚类,我们应该能够自动分割出我们在图表中看到的每个区域,并进一步研究这些区域。以下代码缩放数据,然后对其应用 K-Means 聚类:

from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler#The data frame is called 'combined'
X = combined[['charCount','wordCount','uniqueWords']]
scaler = StandardScaler()
X = scaler.fit_transform(X)
kmeans = KMeans(n_clusters=7, random_state=0).fit(X)
combined['Cluster'] = kmeans.labels_

再次运行我们的观想,我们得到以下结果:

# Overview
ch = chartify.Chart(blank_labels=True)
ch.plot.scatter(
    data_frame=combined,
    x_column='wordCount',
    y_column='uniqueWords',
    size_column='charCount',
    alpha = 0.3,
    color_column='Cluster')
ch.set_title("7 clusters help to split out issues")
ch.set_subtitle("Color represents each cluster, size is the character count")
ch.axes.set_yaxis_label('Unique words')
ch.axes.set_xaxis_label('Total words')
ch.show()

这在划分问题领域方面做得很好。看起来集群 1、4 和 5 需要一些进一步的调查。在此之前,让我们放大图表的左下方,以确保聚类仍在此处工作,因为在当前图中很难看到:

魔法;即使在点之间有重叠的地方,该算法也足够健壮,能够仅基于字符数来区分它们。

为什么我们决定选择 7 个集群?反复试验。7 是仍然以有效方式分割数据集的最小数字。

检查结果

这一切看起来很棒,但是我们真的实现了我们设定的目标吗?我们可以通过检查每个集群中的内容来检查这一点,特别是集群 1、4 和 5。

卡斯特 1:

#locate cluster 1 and return the text column as a list:
combined.loc[combined[‘Cluster’]==1].text.valuesreturns:
3M United Kingdom PLC: modern slavery statement. This statement has been published in accordance with the provisions of the Modern Slavery Act 2015\. It sets out the steps taken by 3M United Kingdom PLC ending 31 December 2016 to prevent modern slavery and human trafficking in its business and supply chains. Introduction from Christiane Gruen, Managing Director of 3M UK.  We, as an organisation, are proud of the steps we have taken, and continue to take, to combat slavery and human trafficking. Global Human Rights Policy was adopted in 2013...

这很有趣,文本在这里看起来完全没问题。上面的例子来自 3M,但其他返回区域也是干净的。因此,聚类 1 是从现代奴隶制陈述中获得的真实数据的一部分,而不是较差的数据质量。当我们进一步分析数据时,我们希望研究为什么这个集群存在

群组 4 和 5:

#locate cluster 4 and 5 and return the text column as a list:
combined.loc[(combined['Cluster']==4) | (combined['Cluster']==5)].text.valuesreturns:
...UK MODERNSLAVERY ACTStatement for the financial year ending 31 December 2016lUK MODERNSLAVERY ACTStatement for the financial year ending 31 December 2016oUK MODERNSLAVERY ACTStatement for the financial year ending 31 December 2016yUK MODERNSLAVERY ACTStatement for the financial year ending 31 December 2016eUK MODERNSLAVERY ACTStatement for the financial year ending 31 December 2016eUK MODERNSLAVERY ACTStatement for the financial year ending 31 December 2016sUK MODERNSLAVERY ACTStatement for the financial year ending 31 December 2016 UK MODERNSLAVERY ACTStatement for the financial year ending 31 December 2016aUK MODERNSLAVERY ACTStatement for the financial year ending 31 December 2016n...

这是我们杂乱的数据。令人印象深刻的是,即使单个单词有意义,该算法也足够智能,可以正确地对上面的例子进行聚类。

我们现在需要做的就是从数据集中排除这些聚类,然后继续分析一组漂亮、干净的数据。

在 Python 中清理和准备数据

原文:towardsdatascience.com/cleaning-an…

Photo by Artem Bali on Unsplash

每个数据科学家工作中无聊的部分

数据科学听起来很酷,很棒。它被描绘成很酷很棒的东西。众所周知,这是 21 世纪最性感的工作(我甚至不会把链接加到:D 那篇文章上)。所有很酷的术语都与这个领域相关——机器学习、深度学习、人工智能、神经网络、算法、模型……

但这一切只是冰山一角。我们 70–80%的工作是数据预处理、数据清理、数据转换、数据再处理——所有这些枯燥的步骤都是为了使我们的数据适合将创造一些现代奇迹的模型。

今天我想列出所有可以帮助我们清理和准备数据的方法和函数。

那么我们的数据会有什么问题呢?很多事情其实:

  • 不相关的列名
  • 极端值
  • 复制
  • 缺失数据
  • 必须处理的列
  • 意外的数据值

探索性分析

为了快速概述,我们可以使用数据帧的以下方法和属性:

df.head() # show first 5 rows
df.tail() # last 5 rows
df.columns # list all column names
df.shape # get number of rows and columns
df.info() # additional info about dataframe
df.describe() # statistical description, only for numeric values
df['col_name'].value_counts(dropna=False) # count unique values in a column

至少其中一个的输出将为我们提供第一手线索,告诉我们应该从哪里开始清理。

另一种快速检查数据的方法是将其可视化。我们使用条形图表示离散数据计数,直方图表示连续数据计数。

df['col_name'].plot('hist')
df.boxplot(column='col_name1', by='col_name2')

直方图和箱线图有助于直观地发现异常值。散点图显示了两个数值变量之间的关系。

df.plot(kind='scatter', x='col1', y='col2')

可视化数据可以带来一些意想不到的结果,因为它为您提供了数据集中正在发生的事情的视角。从上面看。

整洁的数据

整理数据是通过数据整理过程获得的数据。这是大数据处理过程中重要的清理过程之一,也是数据科学实践中公认的步骤。整齐的数据集有结构,使用它们很容易;它们易于操作、建模和可视化。整齐数据集的主要概念是以这样一种方式安排数据,即每个变量是一列,每个观察(或案例)是一行。

整齐的数据为数据清理提供了标准和概念,有了整齐的数据,就不需要从头开始,重新发明新的数据清理方法。

特点:

  • 您测量的每个变量应该在一列中。
  • 该变量的每个不同的观察值应该在不同的行中。
  • 每一种变量都应该有一个表。
  • 如果您有多个表,它们应该在表中包含一个允许它们被链接的列。
  • (以上均摘自维基百科)

为了转换我们的数据并使其整洁,我们可以使用熔化。

pd.melt() # transform columns to rows

有两个参数你要注意: id_varsvalue_varsid_vars 表示您不希望融合的数据列(即,保持其当前形状),而 value_vars 表示您希望融合为行的列。默认情况下,如果没有提供 value_vars ,所有没有在 id_vars 中设置的列都将被融化。

new_df = pd.melt(df, id_vars = 'do not melt')

与熔化相反的操作是旋转。这里,我们将唯一值转换为单独的列。当我们希望将数据从分析形式转换为报告形式,从机器可读形式转换为人类可读形式时,我们会使用它。

df.pivot(index='date', columns='element', values='value')

虽然,这个方法不能处理重复的值。在这种情况下,我们应该使用*。pivot_table()* 有一个额外的参数— aggfunc ,它将根据我们提供的函数(sum、count、mean、min、max 或用户定义的函数)处理这些重复项。

df.pivot_table(index='date', columns='element', values='value', aggfunc=np.mean)

解析数据

有时,我们可能会错误地存储数据。例如,存储为“m014”、“f014”、“m1528”、“f1528”的性别组的值。你不能说这是完全错误的,但是最好将这些值分成“性别”和“年龄”两列。为了做到这一点,我们使用 Python 通过访问。对象类型列的字符串属性。

df['gender'] = df.variable.str[0] 
df['age_group'] = df.variable.str[1:]

串联数据

此外,数据可能不会出现在一个巨大的文件中,而是被分成几个不同的块,所以我们必须能够连接所有的数据,并清理它或清理第一个样本,然后对其余部分应用相同的过程。为此,我们可以使用熊猫*。concat* 方法,它提供了一个数据帧列表,将所有数据帧连接起来。默认情况下,它将存储原始索引,这将导致重复的索引值。为了防止这种情况,我们必须通过传递附加参数 ignore_index=True 来重置新数据帧的索引。

concatenated = pd.concat([df1, df2], ignore_index=True)

但是如果我们有成千上万的文件呢?一个一个的导入,清洗,再重复,会很傻。我们不傻,我们知道 Python 中的循环。唯一缺少的部分是找到所有要导入的文件。我们可以通过 glob library 做到这一点。因此过程如下:编写一个模式,将所有文件保存到一个列表中,遍历 csv 文件,导入每个文件并将数据帧连接成一个。看起来并不困难,但是有了代码示例就好得多了:

# Import necessary modules
import glob
import pandas as pd # Write the pattern: pattern 
pattern = '*.csv' # Save all file matches: csv_files
csv_files = glob.glob(pattern) # Create an empty list: frames
frames = [] # Iterate over csv_files 
for csv in csv_files:     # Read csv into a DataFrame: df 
    df = pd.read_csv(csv)     # Append df to frames 
    frames.append(df)# Concatenate frames into a single DataFrame: final_df
final_df = pd.concat(frames)

合并数据

合并与 SQL join 操作相同。您可以通过每个表中都存在的键将两个或多个表合并成一个表。有三种类型的联接:一对一、一对多、多对多。在 SQL 中,这个过程是高级的,有许多选项和修改,您必须显式地指定想要加入什么以及如何加入。在这里,所有的工作都由一个函数来完成,连接的类型只取决于数据帧中的数据。如果两个数据帧中用作键的列名相同,则使用参数' on '。

merged = pd.merge(left=df1, right=df2, on=None, left_on='col1', right_on='col2')

转换数据类型

拥有正确数据类型的数据是非常重要的,因为以后它可能会跟你和你的分析开一个糟糕的玩笑。还记得有一次我没有将一个列转换为正确的数据类型,花了 1 个小时试图从 string :D 中减去 float:所以要小心:d .这是数据中的一个典型错误,可以用 pd.to_numeric() 和*errors = ' constrate '*修复,它会将所有的 err 值转换为 nan。

要转换数据,我们可以使用*。astype()* 方法对一系列。还要记住“category”类型——它减少了数据帧的大小,加快了计算速度。我们可以转换成任何可以用作类别的值——星期几、性别、洲缩写——取决于上下文。

df['column1'] = df['column1'].astype(str) 
df['column1'] = df['column1'].astype('category')
df['column1'] = pd.to_numeric(df['column1'], errors='coerce')

重复值和缺失值

我们最喜欢的部分,不是吗?要删除重复项,我们可以使用 druuuuuuuuums*drop _ duplicates()*方法。

df = df.drop_duplicates()

对于缺失值,情况稍微复杂一点。通常有三种方法来处理缺失数据:

  • 保持原样
  • 放下它们
  • 填充缺失值

要删除丢失的值,我们可以使用*。dropna()* ,但是要小心——它可能会删除你 50%的数据——这不是很好。但同样,这取决于背景。

为了填补缺失值,我们使用*。fillna()* ,也要小心——如果我们填充缺失的值,它们必须合理且有意义。

有一篇关于处理缺失数据的精彩文章,我真的没有什么要补充的。这是链接别忘了给作者一点掌声,因为那部作品太棒了。

维护

我们还可以使用 assert 语句以编程方式检查我们的数据。如果结果为真,则不返回任何内容,否则返回错误。

assert 1 == 1 # returns nothing 
assert 1 == 2 # returns error
assert df.notnull().all().all() # returns error if at least one column has one missing value

我跳过了正则表达式,因为它值得另写一篇文章,但是概括了我用于数据预处理的工具。请让我知道,如果有其他东西可以添加,有一个伟大的一天,并使用数据科学的好处🙂

原载于sergilehkyi.com

用 Python 清理金融时间序列数据

原文:towardsdatascience.com/cleaning-fi…

“Black and white photo of the street sign for Wall St in New York City” by Rick Tap on Unsplash

假设有一家公司, ABC 金融服务公司 根据公司的经济研究代表其客户做出金融投资决策。这些决策中有许多涉及对金融工具未来价格的投机。ABC 公司利用几个经济指标,但有一个指标在他们的分析中特别重要,那就是密歇根大学的消费者情绪调查 (CSI)。

唯一的问题是,他们必须等待这些数据的发布(每月发布一次),这削弱了 ABC 在市场上的一些优势。为了保持竞争力,他们希望能够提前预测这个数字。我建议使用一种机器学习(ML)的形式对尚未发布的最终消费者情绪数据进行时间序列预测。

为此,我们将使用在 CSI 之前发布的其他经济数据(作为 ML 算法的特征)。我们将使用这些数据构建最终数据集,为预测算法做好准备。

多个数据集

我们将使用的历史数据集如下所列,可从以下链接下载:

工具

我们将使用 Python 和 Pandas 库来处理我们的数据清理任务。我们将使用 Jupyter Notebook,这是一个开源的 web 应用程序,允许您创建和共享包含实时代码、等式、可视化和叙述性文本的文档。对于数据科学家来说,这是一个非常棒的工具。你可以前往Anaconda.org下载大多数数据科学库预装的最新版本。

我们将使用 pandas 将上述数据集合并到一个表中,然后进行必要的清理。上述部分数据集已经过季节性调整,以消除可预测的季节性模式的影响。在实际的预测学习/测试中,我们将对两种类型的数据集进行实验。

数据清理在很大程度上取决于数据的类型和您试图完成的任务。在我们的例子中,我们组合来自不同来源的数据,并清理产生的数据帧。在图像分类数据中,我们可能需要对图像进行整形和调整大小,并创建标签,而情感分析任务可能需要检查语法错误和关键词提取。

目视检查数据帧

为此,我们需要从 python 库中导入一些内容,如下所示。

*# Import necessary modules***import** **numpy** **as** **np**
**import** **pandas** **as** **pd**
**import** **matplotlib.pyplot** **as** **plt**
**import** **seaborn** **as** **sns**
%matplotlib inline
**from** **scipy** **import** stats
**from** **datetime** **import** datetime
**from** **functools** **import** reduce
**import** **datetime**

将数据表导入 Pandas 数据框架。

*# load all the datasets to pandas DataFrames*dow     = pd.read_csv('data/Dow Jones Industrial Average DJI.csv')
unemp   = pd.read_csv('data/Civilian Unemployment Rate UNRATE.csv')
oil     = pd.read_csv('data/Crude Oil Prices MCOILBRENTEU.csv')
hstarts = pd.read_csv('data/Housing Starts HOUST.csv')
cars    = pd.read_csv('data/Total Vehicle SalesTOTALSA .csv')
retail  = pd.read_csv('data/Advance Retail Sales_RSXFS.csv')
fedrate = pd.read_csv('data/Federal Interest Rates FEDFUNDS.csv')
umcsi   = pd.read_excel('data/consumer_sent_UMCH_tbmics.xls',header=3)

加载完数据后,我们要做的第一件事就是目视检查数据,了解数据的结构、内容,并注意任何异常情况。您将遇到的大多数数据至少有数千行长,所以我喜欢一次检查随机的行块。

我们使用 head()tail() 函数分别检查表格的顶部和底部。

# view the top of the dow jones tabledow.head()

# view the top of the umcsi tableumcsi.head()

# view the bottom of the data tableumcsi.tail()

我们还可以使用一个循环来遍历所有的表,并获取大小。从这一步开始,我们可以开始预测我们需要做的连接的种类,或者决定我们是否有足够的统计数据来开始。记住坏数据比没有数据更糟糕。

*# get the shape of the different datasets*

dflist = [dow, unemp, oil, hstarts, cars, retail, fedrate, umcsi]
**for** i, dfr **in** enumerate(dflist):
 print(dflist[i].shape)

当我们检查数据时,另一个有用的 pandas 工具是 describe() 函数,它给出了数据中所有数字列的一般统计信息的快照。

*# we look at the statistical charateristics of the datsets*

**for** i, dfr **in** enumerate(dflist):
    print(dflist[i].describe())

The table above contains more columns as indicated by the back slash at the top right

我们还想知道我们是否正在处理包含空值的数据,因为如果忽略,这可能会导致坏数据。获取空值的一种方法是使用 isnull() 函数来提取这些信息。我们使用下面的循环来迭代所有的数据表。

*# see which datasets have null values*

**for** i, dfr **in** enumerate(dflist):
    print(dflist[i].isnull().sum().sum())

对数据进行观察

  • 下面的一些观察结果在上面的图片中并不明显,但在我的 GitHub 库中的这里的原始笔记本中可以看到。
  • 在这种情况下,我们获得的数据对于数百个列来说并不太复杂,但是记住这一点是有好处的,因为情况并不总是如此,我们必须能够轻松处理非常大的杂乱数据。
  • 从上面的检查来看,在我们能够实现最终的干净数据集之前,有一些事情需要纠正。
  • 所有数据集的日期格式都需要转换成统一的格式。
  • 日期范围也很不一致。开始日期从 1947 年到 1992 年。
  • umcsi 中的日期在两列中(字符串浮点),很难与该列中的其他数据集合并。
  • umcsi 也有 3 个空值,因此我们必须删除存在空值的整行。
  • 出于我们的目的,道琼斯数据框架也有额外的列,所以我们需要去掉一些。
  • 这些只是我能观察到的一些修改,但很可能会有其他的并发症。
  • 注释你的代码也是必要的,这样你的同事就能理解你在做什么。
  • 在某些时候,我们还必须将日期格式从字符串更改为支持绘图的格式。

数据清理

道琼斯数据附带了许多我们在最终数据框架中不需要的额外列,因此我们将使用 pandas drop 函数来释放额外的列。

*# drop the unnecessary columns*

 *dow.drop(['Open','High','Low','Adj Close','Volume'],axis=1,inplace=True)*# view the final table after dropping unnecessary columnsdow.head()

*# rename columns to upper case to match other dfs*

dow.columns = ['DATE', 'OPEN', 'HIGH', 'LOW', 'CLOSE', 'ADJ CLOSE', 'VOLUME']# view result after renaming columns
dow.head()

这些步骤中的大部分可以合并成更少的步骤,但我将它们分解,这样我们就可以遵循,并且我们还可以确认我们正在实现预期的结果。接下来,我们从数据表中删除那些具有空值的列。有时候,我们可能需要组合这些空列,然后在以后删除它们,这样我们就可以填充其他表中的值或获得额外的列(信息)。

下面的原位标志永久删除被删除的行。

*# drop NaN Values*

umcsi.dropna(inplace=**True**)

umcsi 表包含数据类型为 float 的年份值,当我们开始获取年份的小数数字时,这可能会有问题。我创建了一个函数,它从 float 列创建一个新的 integer 列。然后我们可以将旧的 float year 列*放到()*中。有时日期列是字符串格式,我们必须使用内置函数来解析日期,或者我们可以为那些特殊的情况创建自己的列。当您清理数据时,会有很多这样的情况。

*# create 'Year' column with int values instead of float*# casting function
**def** to_int(x):
    **return** int(x)# use function to convert floats to int

umcsi['Year'] = umcsi['Unnamed: 1'].apply(to_int)
umcsi.head()

请注意,我们将月份和年份作为单独的列,需要将它们组合起来,以匹配其余数据表中的日期格式。为此,我们使用 pandas datetime 函数,它能够处理大多数日期和时间操作。事实证明,其他表的日期数据类型为 string,因此我们还必须将 umcsi 日期列更改为 string。这很有意义,因为作为一个时间序列,任何表连接都将在日期列上作为键。

*# combine year columns to one column format*

umcsi['DATE'] = umcsi.apply(**lambda** x: datetime.datetime.strptime("**{0}** **{1}**".format(x['Year'],x['DATE OF SURVEY']), "%Y %B"),axis=1)*# turn date format to string to match other DATE's. We'll merge the data on this column so this is a vital step.*

**def** to_str(x):
    **return** str(x)[:10]

umcsi['DATE'] = umcsi['DATE'].apply(to_str)
umcsi.head()

我们的 umcsi 表看起来很好,除了旧的浮动日期列和月份列,所以我们必须去掉它。为了保持条理,我们还应该把最后的日期列移到前面的列。

*# drop unneeded columns column*
umcsi.drop(['Unnamed: 1','Year','DATE OF SURVEY'], axis=1, inplace=**True**)

*# move 'DATE' column to the front*
cols = list(umcsi)
cols.insert(0, cols.pop(cols.index('DATE')))
umcsi = umcsi.reindex(columns = cols)
umcsi.head()

A more useful table than we started of with.

有了内聚格式的所有表,我们可以继续连接它们并做一些最后的清理步骤。我们将用日期列作为键来连接这些表。我们将使用强大的 lambda 函数来快速完成这个任务。实际上,我们将封装更多的函数来展示 pandas 在数据操作方面有多么强大。

*# concatenate all dataframes into one final dataframe* dfs = [dow,unemp,oil,hstarts,cars,retail,fedrate,umcsi] # we perform the joins on DATE column as key and drop null valuesdf = reduce(**lambda** left,right: pd.merge(left,right,on='DATE', how='outer'), dfs).dropna() df.head(5)

我们现在有了一个最终的熊猫数据框架,尽管它还需要更多的清理。接下来,我们必须从我们的最终表中删除异常值,因为这些异常值可能会在稍后的机器学习任务中引入大量噪声。

*# remove all rows with outliers in at least one row*

df = df[(np.abs(stats.zscore(df.drop(['DATE'], axis=1))) < 3).all(axis=1)]# show final size after removing outliers
df.shape

Final dataframe shape

Python 有一种专门的格式来处理时间列,这种格式非常有效。我们可以使用 strip() 函数从当前的字符串格式中提取出 datetime.datetime 格式。同样,我们将使用 lambda 函数动态地将其应用于所有行。

*# change the DATE column from String to python's 
# datetime.datetime format* df['DATE'] = df['DATE'].apply(**lambda** x: datetime.datetime.strptime(x,"%Y-%m-**%d**"))

最后一步是将这些列重命名为更便于用户使用的名称,以便那些继续使用这些数据的用户使用。

*# rename columns to more user friendly names*

df.columns = ['DATE', 'OPEN', 'HIGH', 'LOW', 'CLOSE', 'ADJ CLOSE', 'VOLUME', 'UNEMP %','OIL PRICE','NEW HOMES','NEW CARS SOLD',
                    'RETAIL SALES','FED INTRST %','CSI' ]# preview final table
df.head(20)

FINAL pandas dataframe

数据清理结论

  • 数据清理有各种形式和大小,没有一个模板可以处理所有情况。
  • 虽然我们不知道数据在预测 CSI 的任务中表现如何,但我们知道所提供的数据已经过处理,以便在 ML 环境中快速采用和测试。
  • 当然,我们可以设计出更多的功能,并对当前的功能进行更多的处理,但对于我们来说,ML 团队将如何进行就太放肆了。例如,我们可以将特征归一化到统一的比例,但没有这样做。
  • 总之,像数据科学领域的大多数任务一样,我们最多只能在合适的团队中不断提问,并根据这些问题进行更深入的实验。

清理债务:熊猫之道

原文:towardsdatascience.com/cleaning-up…

不良贷款(NPL)数据的数据争论和探索性数据分析

最近对东南亚信贷市场的分析揭示了这一特定地区信贷文化的一些细微差别。这些数据让我开始思考全球信贷健康状况和全球不良贷款率。鉴于我最近对数据分析的尝试,我认为一个笔记本是合适的。

但首先,什么是信贷市场,什么是不良贷款?

通过考察信贷市场,我们看到了个人、公司和政府向投资者借钱的市场。这种形式的借款可以采取许多不同的形式,从你的日常信用卡支出到你的下一个海滩房屋的抵押贷款。

不良贷款(NPL)是指借款人在一段时间内(通常超过 90 天)无法按期还款的贷款。

当不良贷款水平上升时,通常是信贷市场健康状况恶化的指标。简而言之,更多的人没有偿还他们所欠的债务。

我们将从世界银行数据库中调查不同国家的不良贷款水平。

首先,我们从导入必要的包开始…

因为有些行包含填充列信息,所以我用 islice 跳过前 4 行。

缺失数据

看一下数据框架,似乎表明有许多缺失的数据,尤其是前几年的数据。为了更好地了解通常缺失的数据,我们使用 missingno 来快速可视化。

但是,在使用 missingno 之前,空数据似乎是由 numpy 字符串表示的。因此,我们希望用 np.nan 替换所有这样的实例,以使 missingno 可视化工作。

Any white space indicates missing data

这种可视化似乎表明大量数据缺失,尤其是截至 2010 年的年度数据。相对于之前的 6 年,2016 年似乎缺少更多数据。缺少 2010-2015 年数据的国家因此被剔除。

此外,“指标名称”和“指标代码”这两列似乎也不是特别有用。

我们将创建一个新的数据框架,其中仅包含国家、国家代码和 2010 年至 2015 年的数据。我们还将设置列名,这些列名当前位于第一行。

No missing fields now

数据类型

好多了。剩下 144 个国家/地区的每一列都有值。一些行索引可能不是特定于国家的。但是首先,有数据类型的问题。

检查列的数据类型,所有数据看起来都是非空对象。出于分析代表百分比的 NPL 水平的目的,这些应该是浮动类型的。

将数据类型更改为 float 后,describe()函数再次工作,平均值似乎保持在一个相对较窄的范围内。2010 年和 2011 年的最低不良贷款似乎有一个特殊的异常值。不良贷款可以在 0%吗?似乎是一个幻想世界。

汤加似乎是个例外,2012 年不良贷款跃升至 14%。或许他们只是在 2012 年才开放信贷市场?谷歌快速搜索揭穿了这一说法。这可能是一个错误的条目,我们将从分析中删除汤加。

“过剩”数据

看一下“国家名称”一栏,发现有 143 个“国家”,但其中许多是指特定的地区和分类,如“南亚(IDA & IBRD)”。我们只想要纯国家数据,所以我们将从 country_list 导入一个已知国家名称的列表,并过滤掉它们。

有许多方法可以着手清理国家名单。更好的方法包括寻找最接近的匹配和按分数过滤。例如,ous ful给出了一个使用模糊集寻找近似匹配的很好的例子。

然而,鉴于这是一个相对较小的指数值集,我们可以简单地查看在与国家列表交叉引用时被过滤掉的国家。

在删除的 44 个值中,“波斯尼亚和黑塞哥维那”、“文莱达鲁萨兰国”、“刚果共和国”、“捷克共和国”、“冈比亚”、“中国香港特别行政区”、“吉尔吉斯共和国”、“中国澳门特别行政区”、“马其顿、FYR”、“斯洛伐克共和国”、“特里尼达和多巴哥”等国名似乎应该保留。

然后,我们继续使用列表理解来查找最终的过滤国家列表。

The wonders of list comprehension

现在,我们已经在数据框架中包含了我们想要的国家,让我们添加一些由世界银行提供的相同数据集的其他属性。在单独的 csv 中,他们提供了关于国家所在地区及其人口收入群体的信息。可以对国家代码(文件之间的公共列)进行合并。

融化的

太好了,现在我们有了一个包含相关信息的国家列表。然而,年度不良贷款数据的格式仍然反映了原始数据条目的格式。有了“整洁”的数据结构,EDA 和进一步的分析会更容易。从 2010 年到 2015 年的列名作为值可能比列名更有用。

因此,我们将“融化”数据集。这也被称为从宽格式到长格式。

Long form data for Argentina

添加类别

我们可能在一个数据帧中有了我们想要的数据,但是这是否意味着它已经可以进行分析了呢?快速浏览 info()会得到一个响亮的“不”。

如果我们要进行任何类型的时间序列分析,那么“year”列作为一个非空对象实际上是没有用的,因此它应该被转换为整数或日期时间对象。

此外,虽然你可以按收入群体对数据进行分组,但如果我们在数据上附加一个尺度,可能会更能说明问题。虽然这种标量转换不太适用于地区,但人们可以可靠地对收入群体进行加权。

现在数据集更清晰了,让我们看看数据告诉了我们什么。

不良贷款分布

首先看一下不良贷款水平的分布,就会发现它并不完全是正态分布,而是一种偏态分布。偏斜度和峰度值的计算似乎支持这一点,两者都偏离了“正常”范围。

注意这种偏斜度和峰值的值是很重要的,因为它们会极大地影响任何预测模型。

散点图和识别聚类

接下来,我们来看看这些不良贷款水平在不同收入群体中的分布。然后这些点用颜色编码来代表年份。

我最初预计低收入群体的不良贷款会高得多,因此最突出的是高收入群体国家的大量异常值。债务市场上的这些坏演员是谁?

“坏演员”名单似乎被少数几个国家所控制,如爱尔兰、希腊、圣马力诺和塞浦路斯。

尽管它们的收入水平相对较高,但它们拥有一些最高的不良贷款水平。

这些不良贷款水平很好地反映了现实生活中的事件,爱尔兰在 2012 年重新陷入衰退,塞浦路斯在 2012-2013 年发生金融危机,圣马力诺的金融部门受到欧元区危机的重创,希腊面临着自 2009 年以来的大规模债务危机。

我们还可以进一步了解不同地区的不良贷款水平。快速浏览一下过去几年按地区分组的不良贷款集群,就会发现欧洲、中亚和撒哈拉以南非洲的不良贷款率明显较高。

信用透明度

我们拥有的每个地区的数据量可以作为信贷市场透明度的指标吗?我们数据框架中的国家是近年来拥有充足的不良贷款信息的国家。我们来比较一下各个地区的相对代表性。

“欧洲&中亚”和“北美”地区似乎是不良贷款数据最透明的地区。大多数其他地区徘徊在 50%左右,而“中东和北非”在信贷透明度方面明显落后,只有 19%的国家有不良贷款数据。

后续步骤

对全球不良贷款数据的初步研究得出了一些非常有趣的结果。然而,鉴于这一过程的主要目的是整理世界银行的数据,仍有很大的探索空间。我希望将其他行的数据汇总到这个数据框架中,或许进行一个面板数据分析。

调查每个地区/国家的本地因素以更好地量化信贷文化肯定会很有意思。信贷文化可以是一个相对任意的术语,它的大多数定量测量是基于还款历史和其他贷款数据。将“软”指标纳入对信贷文化的审查是很有趣的。这些“软”指标可能包括对债务的文化观点、贷款积极性、社区信任以及自我概念和借贷或欠款中的“面子”的检查。

如果您对代码感兴趣,请查看 Jupyter 笔记本这里

感谢阅读!

澄清困惑:人工智能 vs 机器学习 vs 深度学习的差异

原文:towardsdatascience.com/clearing-th…

如果你陷入了区分人工智能(AI)与机器学习(ML)和深度学习(DL)的困惑,请举手…

把你的手放下来,伙计,我们看不见!

尽管这三个术语通常可以互换使用,但它们并不完全指同一事物。

德国计算机专家 Andrey Bulezyuk 在教授人工智能系统如何工作方面有超过五年的经验,他说“这个领域的从业者可以清楚地说出这三个密切相关的术语之间的区别。”

所以,人工智能、机器学习、深度学习有区别吗?

这是一张试图将它们之间的区别形象化的图片:

在上面三个同心圆的图像上可以看到,DL 是 ML 的子集,ML 也是 AI 的子集。

有意思?

因此,AI 是最初爆发的无所不包的概念,然后是后来蓬勃发展的 ML,最后是有希望将 AI 的进步提升到另一个水平的 DL。

让我们更深入地挖掘一下,这样你就能明白哪个更适合你的具体用例:人工智能,机器学习,还是深度学习。

什么是人工智能?

顾名思义,人工智能可以被松散地解释为将人类的智能融入到机器中。

人工智能是一个更广泛的概念,包括从优秀的老式人工智能 (GOFAI) 到深度学习等未来技术的一切。

每当机器根据一套规定的解决问题的规则(算法)完成任务时,这样的“智能”行为就是所谓的人工智能。

例如,这种机器可以移动和操纵物体,识别是否有人举手,或者解决其他问题。

人工智能驱动的机器通常分为两组——通用型和窄型。一般的人工智能 AI 机器都是可以智能解决问题的,像上面说的那些。

狭义智能人工智能机器可以很好地执行特定的任务,有时甚至比人类更好——尽管它们的范围有限。

Pinterest 上用于分类图像的技术就是狭义人工智能的一个例子。

什么是机器学习?

顾名思义,机器学习可以宽泛地解释为赋予计算机系统“学习”的能力。

ML 的目的是使机器能够使用提供的数据进行自我学习,并做出准确的预测。

ML 是人工智能的子集;其实简单来说就是一种实现 AI 的技术。

这是一种训练算法的方法,这样它们就可以学习如何做出决策。

机器学习中的训练需要向算法提供大量数据,并允许它学习更多关于处理过的信息。

例如,下面的表格根据水果的特征确定了水果的类型:

正如你在上面的表格中看到的,水果是根据它们的重量和质地来区分的。

然而,最后一行只给出了重量和质地,没有给出水果的类型。

而且,可以开发一种机器学习算法来尝试识别水果是橙子还是苹果。

在该算法获得训练数据后,它将学习橙子和苹果之间的不同特征。

因此,如果提供重量和质地的数据,它可以准确地预测具有这些特征的水果的类型。

什么是深度学习?

如前所述,深度学习是 ML 的子集;事实上,它只是一种实现机器学习的技术。换句话说,DL 是机器学习的下一次进化。

DL 算法大致受到人脑中发现的信息处理模式的启发。

就像我们用大脑来识别模式和分类各种类型的信息一样,深度学习算法可以被教会为机器完成同样的任务。

大脑通常试图解读它接收到的信息。它通过给物品贴上标签并将其归入不同的类别来实现这一点。

每当我们接收到新信息时,大脑都会试图在理解它之前将其与已知项目进行比较——这与深度学习算法采用的概念相同。

例如,人工神经网络(ann)是一种旨在模仿我们大脑决策方式的算法。

比较深度学习和机器学习可以帮助你理解它们的细微差异。

例如,DL 可以自动发现用于分类的特征,而 ML 需要手动提供这些特征。

此外,与 ML 相比,DL 需要高端机器和相当大量的训练数据来提供准确的结果。

收尾

你现在明白 AI vs ML vs DL 的区别了吗?

然后,举起你的手…

我们承诺开发一种人工智能算法,当有人举手时,它会告诉我们。

使用 TensorFlow.js 进行客户端预测

原文:towardsdatascience.com/client-side…

大家好,我叫 Matvii,是一名数据科学家。我的工作包括数据预处理、开发/训练和部署模型。所以今天我将尝试分享我的知识,并展示如何部署一个模型,一些计算将由客户端完成**。下面的帖子是为那些创建了一个模型,并想通过将预测部分委托给客户端来减少服务器负载的人准备的。尤其是对于日常使用 Python 并且对 JavaScript 一知半解的数据科学家来说。可以跳过这个帖子,直接进入我的Github资源库。**

指标 0。简介 1。创建模型 2。设置烧瓶服务器 3。正在创建index.html 4。正在创建main . js5。更新烧瓶服务器****

0。简介 让我们想象你已经创建了一些深刻而令人敬畏的模型,它做了一些伟大的事情** 并且帮助人们。例如,该模型通过人们杯子的照片来预测他们最喜欢的表情符号。你把这个模型放在网上,每天的使用量大约是 1000 次查询,不是很多。简单的服务器可以处理它,但是有一天这个模型被公众发现了,你开始每天接收 10 万个查询,同一个服务器可能会死掉。因此,现在您可以扩展服务器并添加越来越多的内存,或者尝试在客户端重写预测。如果你选择第二个选项,这里有一个教程给你。**

为了实现目标,我们将拥有以下组件**。 后端 : Flask,任何你想在 python 中对一个图像进行预处理的库 前端 : tensorflowjs 最近 tensorflowjs 增加了对 node.js 的支持,不过,我们将使用 Flask ,这是一个 python 库。通常,一些经过训练的模型需要数据预处理才能正确执行。到目前为止,预处理在 python 中比在 javascript 中更方便。(我希望有一天也能在客户端进行预处理)**

1。创建模型 你可以通过运行train_model.py为 MNIST 训练模型,或者你可以创建和训练任何你想要的模型。这里重要的一点是保存模型的拓扑和权重。如果你的模型是用 keras 写的,简单的加上这个。

保存模型后,您将拥有一个包含以下内容的文件夹。

其中* — 的group \ -shard \ 是二进制权重文件的集合, model.json — 是模型拓扑和配置。**

2。设置 Flask 服务器 是因为我们希望用户访问我们的模型。

简单的服务器到目前为止,没有什么复杂的,只是一个路径返回我们的静态页面index.html。** 还有,系统的一般架构会是这样的。**

3。创建 index.html 我们需要一些入口点,用户将与它交互,我们将在那里运行我们的预测。因此,让我们设置index.html。****

我们的第一个版本将是这样的。这里唯一重要的是在第 6 行上,它从 cdn 添加了 tensorflowjs。 下一步是添加一些 HTML 主体以便用户能够上传图像和点击按钮。:)在这里。

我们的 HTML 部分的下一步也是最后一步,是给我们的页面添加一些样式,从而给 HTML 元素带来类,同时创建 main.js 文件,该文件将包含我们的神奇预测部分**。现在让我们看看**index.html 的最终版本。****

您的index.html可能与我的不同,您也可以添加或删除一些部分,但是,这里重要的是: — 第 6 行(在头部添加来自 CDN 的脚本——对于生产版本的代码来说是一个不好的做法,但是,我不想麻烦任何人解释什么是 npmnode _ modules**) —第 13 行 如果你想让用户上传一张图片,你也可以使用不同类型的输入) — 第 20 行(我们的脚本做客户端预测)**

4。Creating main.js 现在是带来魔力的时候了。首先我们需要初始化按钮、输入、模型和预测的功能。

第 3 行我们有我们模型的 URL,到目前为止它在我的本地机器上,但是一般来说它可以部署在任何地方。此外,稍后我们将在 Flask 中为该模型创建一条路线。 现在让我们添加将下载我们的模型的部分,然后拍摄用户上传的图像并将其发送到服务器进行预处理

我们将图像发送到 /api/prepare/ 我们稍后将添加的路线。我们还将来自服务器的响应从字段图像放到tf.tensor2d。 现在是时候为我们的张量添加预测,然后将预测和图像渲染到用户的视图中。最后就是添加一些按钮例程和函数调用。

所以带有客户端预测的神奇脚本的最后一个版本看起来会像这样。

请随意重写获取部分,以便在一个帖子中发送完整的批文件。 不要忘记根据用于训练模型的形状对返回的数组进行整形!

5。更新 Flask 服务器 现在我们必须更新我们的服务器,这样它就可以为 /api/prepare 对图像进行预处理,并且还可以为 /model 的 model 提供前端服务。服务器的最终版本将类似于此。

对于的预处理部分,我们有两个函数: — 准备(调用**/API/prepare**) —预处理(拍摄一幅图像,将调整后的图像返回到 **numpy 数组,**这个函数可以做任何你喜欢的预处理,只要它返回 numpy 数组,一切都会正常工作) 模型部分:— —

为什么我们需要两个函数和两个独立的 API 来服务一个模型,而不是一个?

tensorflowjs 的下一个版本中,当我们为某个 API model = await tf.loadModel(modelURL); 加载模型时,它首先从modelURL加载模型,这是一个 JSON 文件,然后它自动向域名根发送几个帖子,以便加载碎片**(在服务器日志中的演示中查看这些帖子)。因为我不想把我的模型放在服务器旁边的根目录中,所以我需要两个函数,一个用于 model.json ,另一个用于 shards 。**

就是这样!现在,你可以将预测人们最喜欢的表情符号(根据他们杯子的照片)发送到客户端,或者像我一样,只发送 MNIST!此外,如果一切正常,您将会看到类似这样的内容。

感谢您的阅读!随意添加/重写你喜欢的任何部分!尽情享受吧! Github

克隆人类驾驶员的行为,并将其应用于自动驾驶汽车

原文:towardsdatascience.com/clone-a-hum…

如何克隆人类司机的行为?嗯,首先,我们需要去兜兜风,同时采集一些数据。听起来不错。让我们开始吧。没那么快。你会问为什么?因为我车里没有设备来完成这件事。好吧,我会退而求其次:一个由 Udacity 创建的模拟环境,它服务于我的目的:在模拟环境中驾驶汽车并捕捉数据。听起来像是轻而易举的事,但我不知道我的游戏技能充其量也就是一般水平。我试了 20 多次才让这辆车在跑道上行驶而不撞车。现在我有了一些数据,我需要建立一个卷积神经网络(CNN),并训练它模仿我捕捉的数据。如果一切顺利,CNN 模型将学习模仿驾驶行为,并克隆学习自己驾驶。如果你只对最终结果感兴趣,就跳到这个 视频 。关于详细的讨论,请继续阅读。

希望一切顺利,我建立了模型,训练了它,并在模拟器上焦急地测试它,以查看结果:当我的车可以自主游泳和越野时,谁想模仿我的驾驶!看看下面的视频,你就会明白我在说什么了。在那一瞬间,我觉得我的冒险车是最酷的!它可以越野行驶,也可以游泳。直到它翻转过来的那一刻😒。回到基础,我去了。

第一步:收集和探索数据

我最初捕捉到的训练数据是在赛道上跑一圈多一点。我需要更多的数据和更好的模型。为了获取更多的数据,我没有重新使用我糟糕的视频游戏技能,而是选择用 Udacity 提供的额外数据来扩充我的数据。模拟器有一辆带有三个捕捉图像的前置摄像头的汽车:左视图、中间视图和右视图各一个。它还输出一个包含以下六列数据的 CSV 文件:第 1 列:中间图像的图像路径,第 2 列:左侧图像的图像路径,第 3 列:右侧图像的图像路径,第 4 列:转向角度,第 5 列:油门,第 6 列:刹车

我在专栏 1-3 中使用了所有三张图片,因为它们提供了道路的不同视角。然而,左和右相机图像的转向角需要通过校正因子来调整,以考虑相机位置。我绘制了转向角的直方图(图 1)以探索数据的分布,并发现许多数据集中在零附近,即直线行驶。这是有意义的,因为赛道上有很多直线行驶,这将导致模型中直线行驶的偏差。

Fig 1: Histogram of Steering Angles distribution

第二步:处理和扩充数据

为了解决驾驶偏向直线的问题,我删除了一些接近零转向角的数据点,并使它们下降,以便分布均匀。当我绘制这些数据的直方图(图 2)时,它看起来确实更加一致。

Fig 2: Histogram of Steering Angles distribution after removing biases

图像大小为 160x320x3(图 3)。然而,顶部图像的三分之一是与模型无关的数据:地平线以上的天空和树木等。底部的 25 个像素也无关紧要,因为它有汽车的引擎盖。我裁剪了图像,去掉了这些区域,使图像尺寸缩小到 70x320x3。

Fig 3: Sample image of the input dataset

由于树木的原因,图像中似乎有阴影,我想确保汽车可以在不同的照明条件下行驶。所以,我用随机的阴影和亮度增强来处理一些受这篇帖子启发的图片。随机亮度&阴影增强的结果如图 4 & 5 所示。

Fig 4: Images with varying brightness

Fig 5: Images with random shadows

模拟器轨道也有许多左转,这些数据会导致模型偏向于向左行驶。为了解决这个问题,我将一半的图像随着转向角度翻转,以生成向右行驶的图像。现在,我相信我已经有了一个平衡的数据集,可以将模型推广到各种情况下的驾驶,图 2 中的直方图证实了这一点。

第三步:建立一个 CNN 模型

我在这个项目中使用了英伟达的 CNN 模型的改编版,因为它是为自动驾驶而设计的。我用 Keras 建立了这个模型。经过实验(步骤 4),我用 L2 正则化和 ELU 激活对模型进行了微调,得到了图 6 中的架构。

Fig 6: Network Architecture Details

第四步:训练和微调模型

我以 85/15 的比例将输入数据集分成训练和验证数据集,并训练 CNN 模型。与交通标志分类问题不同,该项目的目标是预测转向角,这可以通过线性回归实现。我使用 Adam 优化器来获得预测转向角的最佳均方误差(MSE)值。我用 10 个历元进行训练,批量为 64 个。为了提高内存效率,我没有将预处理过的数据一次性存储在内存中,而是使用了生成器函数来提取数据片段,并根据需要动态处理它们。模型训练的结果总结以及训练和验证损失如图 7 所示。由于 AWS 的处理能力,这些训练运行非常快(大约 7 分钟)。我不认为如果这些运行需要很长时间,我会用不同的设置做很多实验,因为如果我在我的本地计算机上运行,他们会这样做。

Fig 7: Model training results

第五步:在模拟器上测试模型

我拿着经过训练的模型,启动模拟器来测试我的模型,看看它在自主模式下表现如何。经过多次实验,我终于能够让汽车在稳定的基础上自动驾驶。

Results Video of a car driving autonomously

总结:

这是一个非常有趣和令人兴奋的项目。从一辆会游泳的车,到一辆能在赛道上自主驾驶的车,我走过了漫长的道路。在许多领域都有改进的空间,我想在时间允许的情况下重新审视这个项目,让这个模型很好地推广到不同的赛道,在有车道的赛道上驾驶,最终在车流中驾驶。多亏了论坛、其他学生的建议和 Udacity 的资源,我能够测试许多想法,并挑选出最适合我的项目的想法。

这个项目的代码可以在我的 GitHub 库中找到。