Python 物联网入门指南(二)(1)https://developer.aliyun.com/article/1507121
还有更多…
我们之前创建了Photo
类。现在我们可以向我们的模块中添加一些测试代码,以确保它按我们的预期运行。我们可以使用__name__ ="__main__"
属性
与之前一样,以检测模块是否直接运行。
我们可以在photohandler.py
脚本的末尾添加以下代码段,以生成以下测试应用程序,其外观如下:
照片查看演示应用程序
在photohandler.py
的末尾添加以下代码:
#Module test code def dispPreview(aPhoto): """Create a test GUI""" import tkinter as TK #Define the app window app = TK.Tk() app.title("Photo View Demo") #Define TK objects # create an empty canvas object the same size as the image canvas = TK.Canvas(app, width=previewsize[0], height=previewsize[1]) canvas.grid(row=0,rowspan=2) # Add list box to display the photo data #(including xyscroll bars) photoInfo=TK.Variable() lbPhotoInfo=TK.Listbox(app,listvariable=photoInfo, height=18,width=45, font=("monospace",10)) yscroll=TK.Scrollbar(command=lbPhotoInfo.yview, orient=TK.VERTICAL) xscroll=TK.Scrollbar(command=lbPhotoInfo.xview, orient=TK.HORIZONTAL) lbPhotoInfo.configure(xscrollcommand=xscroll.set, yscrollcommand=yscroll.set) lbPhotoInfo.grid(row=0,column=1,sticky=TK.N+TK.S) yscroll.grid(row=0,column=2,sticky=TK.N+TK.S) xscroll.grid(row=1,column=1,sticky=TK.N+TK.E+TK.W) # Generate the preview image preview_filename = aPhoto.previewPhoto() photoImg = TK.PhotoImage(file=preview_filename) # anchor image to NW corner canvas.create_image(0,0, anchor=TK.NW, image=photoImg) # Populate infoList with dates and exif data infoList=[] for key,value in aPhoto.filedates.items(): infoList.append(key.ljust(25) + value) if aPhoto.exifvalid: for key,value in aPhoto.exif_info.items(): infoList.append(key.ljust(25) + str(value)) # Set listvariable with the infoList photoInfo.set(tuple(infoList)) app.mainloop() def main(): """called only when run directly, allowing module testing""" import sys #Check the arguments if len(sys.argv) == ARG_LENGTH: print ("Command: %s" %(sys.argv)) #Create an instance of the Photo class viewPhoto = Photo(sys.argv[ARG_IMAGEFILE]) #Test the module by running a GUI if viewPhoto.filevalid==True: dispPreview(viewPhoto) else: print ("Usage: photohandler.py imagefile") if __name__=='__main__': main() #End
之前的测试代码将运行main()
函数,该函数获取要使用的照片的文件名,并创建一个名为viewPhoto
的新Photo
对象。如果viewPhoto
成功打开,我们将调用dispPreview()
来显示图像及其详细信息。
dispPreview()
函数创建四个 Tkinter 小部件以显示:一个Canvas
加载缩略图图像,一个Listbox
小部件显示照片信息,以及两个滚动条来控制Listbox
。首先,我们创建一个Canvas
小部件,大小与缩略图图像(previewsize
)相同。
接下来,我们创建photoInfo
,它将是我们与Listbox
小部件关联的listvariable
参数。由于 Tkinter 没有提供ListVar()
函数来创建合适的项目,我们使用通用类型TK.Variable()
,然后确保在设置值之前将其转换为元组类型。添加Listbox
小部件;我们需要确保listvariable
参数设置为photoInfo
,并且将字体设置为monospace
。这将允许我们使用空格对齐我们的数据值,因为monospace
是等宽字体,所以每个字符占用的宽度都相同。
我们通过将Scrollbar
命令参数设置为lbPhotoInfo.yview
和lbPhotoInfo.xview
来定义两个滚动条,并将它们链接到Listbox
小部件。然后,我们使用以下命令调整Listbox
的参数:
lbPhotoInfo.configure(xscrollcommand=xscroll.set, yscrollcommand=yscroll.set)
configure
命令允许我们在创建小部件后添加或更改小部件的参数,在这种情况下,链接两个滚动条,以便Listbox
小部件在用户在列表中滚动时也可以控制它们。
与以前一样,我们利用网格布局来确保Listbox
小部件旁边正确放置了两个滚动条,Canvas
小部件位于Listbox
小部件的左侧。
我们现在使用Photo
对象创建preview.ppm
缩略图文件(使用aPhoto.previewPhoto()
函数),并创建一个TK.PhotoImage
对象,然后可以使用以下命令将其添加到Canvas
小部件中:
canvas.create_image(0,0, anchor=TK.NW, image=photoImg)
最后,我们使用Photo
类收集的日期信息和 EXIF 信息(确保它首先是有效的)来填充Listbox
小部件。我们通过将每个项目转换为一系列使用.ljust(25)
间隔的字符串来实现这一点——它添加左对齐到名称,并填充它使字符串宽度为 25 个字符。一旦我们有了列表,我们将其转换为元组类型并设置listvariable
(photoInfo
)参数。
像往常一样,我们调用app.mainloop()
来开始监视事件以做出响应。
自动整理您的照片
现在我们有了一个允许我们收集照片信息的类,我们可以将这些信息应用于执行有用的任务。在这种情况下,我们将使用文件信息自动将一个充满照片的文件夹组织成基于照片拍摄日期的子文件夹的子集。
以下屏幕截图显示了脚本的输出:
脚本输出以整理文件夹中的照片
准备工作
您需要在树莓派上的一个文件夹中放置一些照片。或者,您可以插入一个带有照片的 USB 存储设备或读卡器——它们将位于/mnt/
中。但是,请确保您首先使用照片的副本测试脚本,以防出现任何问题。
如何做…
创建以下脚本filehandler.py
以自动整理您的照片:
#!/usr/bin/python3 #filehandler.py import os import shutil import photohandler as PH from operator import itemgetter FOLDERSONLY=True DEBUG=True defaultpath="" NAME=0 DATE=1 class FileList: def __init__(self,folder): """Class constructor""" self.folder=folder self.listFileDates() def getPhotoNamedates(self): """returns the list of filenames and dates""" return self.photo_namedates def listFileDates(self): """Generate list of filenames and dates""" self.photo_namedates = list() if os.path.isdir(self.folder): for filename in os.listdir(self.folder): if filename.lower().endswith(".jpg"): aPhoto = PH.Photo(os.path.join(self.folder,filename)) if aPhoto.filevalid: if (DEBUG):print("NameDate: %s %s"% (filename,aPhoto.getDate())) self.photo_namedates.append((filename, aPhoto.getDate())) self.photo_namedates = sorted(self.photo_namedates, key=lambda date: date[DATE]) def genFolders(self): """function to generate folders""" for i,namedate in enumerate(self.getPhotoNamedates()): #Remove the - from the date format new_folder=namedate[DATE].replace("-","") newpath = os.path.join(self.folder,new_folder) #If path does not exist create folder if not os.path.exists(newpath): if (DEBUG):print ("New Path: %s" % newpath) os.makedirs(newpath) if (DEBUG):print ("Found file: %s move to %s" % (namedate[NAME],newpath)) src_file = os.path.join(self.folder,namedate[NAME]) dst_file = os.path.join(newpath,namedate[NAME]) try: if (DEBUG):print ("File moved %s to %s" % (src_file, dst_file)) if (FOLDERSONLY==False):shutil.move(src_file, dst_file) except IOError: print ("Skipped: File not found") def main(): """called only when run directly, allowing module testing""" import tkinter as TK from tkinter import filedialog app = TK.Tk() app.withdraw() dirname = TK.filedialog.askdirectory(parent=app, initialdir=defaultpath, title='Select your pictures folder') if dirname != "": ourFileList=FileList(dirname) ourFileList.genFolders() if __name__=="__main__": main() #End
它是如何工作的…
我们将创建一个名为FileList
的类;它将使用Photo
类来管理
特定文件夹中的照片。这有两个主要步骤:首先需要找到文件夹中的所有图像,然后生成一个包含文件名和照片日期的列表。我们将使用这些信息生成新的子文件夹,并将照片移动到这些文件夹中。
当我们创建FileList
对象时,我们将使用listFileDates()
创建列表。然后,我们将确认提供的文件夹是有效的,并使用os.listdir
获取目录中的所有文件的完整列表。我们将检查每个文件是否是 JPEG 文件,并获取每张照片的日期(使用Photo
类中定义的函数)。接下来,我们将文件名和日期作为元组添加到self.photo_namedates
列表中。
最后,我们将使用内置的 sorted
函数按日期顺序放置所有文件。虽然我们在这里不需要这样做,但如果我们在其他地方使用这个模块,这个函数将更容易删除重复的日期。
sorted
函数需要对列表进行排序,在这种情况下,我们希望按 date values:
进行排序。
sorted(self.photo_namedates,key=lambda date: date[DATE])
我们将用 lambda date:
替换 date[DATE]
作为排序的数值。
一旦 FileList
对象被初始化,我们可以通过调用 genFolders()
来使用它。首先,我们将日期文本转换为适合我们文件夹的格式(YYYYMMDD),使我们的文件夹可以轻松按日期顺序排序。接下来,它将在当前目录内创建文件夹(如果尚不存在)。最后,它将把每个文件移动到所需的子文件夹中。
我们最终得到了准备测试的 FileList
类:
操作 | 描述 |
__init__(self,folder) |
这是对象初始化程序。 |
getPhotoNamedates(self) |
这将返回一个包含照片文件名和日期的列表。 |
listFileDates(self) |
这将创建一个包含文件夹中照片文件名和日期的列表。 |
genFolders(self) |
这将根据照片的日期创建新文件夹并将文件移动到其中。 |
属性列如下:
属性 | 描述 |
self.folder |
我们正在处理的文件夹。 |
self.photo_namedates |
这包含文件名和日期的列表。 |
FileList
类将所有函数和相关数据封装在一起,将所有内容放在一个逻辑位置:
Tkinter filediaglog.askdirectory() 用于选择照片目录
为了测试这个,我们使用 Tkinter 的 filedialog.askdirectory()
小部件来选择照片的目标文件夹。我们使用 app.withdrawn()
来隐藏主 Tkinter 窗口,因为这次不需要它。我们只需要创建一个新的 FileList
对象,然后调用 genFolders()
将所有照片移动到新的位置!
在这个脚本中定义了两个额外的标志,为测试提供了额外的控制。DEBUG
允许我们通过将其设置为 True
或 False
来启用或禁用额外的调试消息。此外,FOLDERSONLY
当设置为 True
时,只生成文件夹而不移动文件(这对于测试新的子文件夹是否正确非常有帮助)。
运行脚本后,您可以检查所有文件夹是否已正确创建。最后,将 FOLDERSONLY
更改为 True
,下次您的程序将根据日期自动移动和组织照片。建议您只在照片的副本上运行此操作,以防出现错误。
第四章:预测词语中的情感
本章介绍以下主题:
- 构建朴素贝叶斯分类器
- 逻辑回归分类器
- 将数据集分割为训练集和测试集
- 使用交叉验证评估准确性
- 分析一个句子的情感
- 使用主题建模识别文本中的模式
- 情感分析的应用
构建朴素贝叶斯分类器
朴素贝叶斯分类器使用贝叶斯定理构建监督模型。
如何做…
- 导入以下软件包:
from sklearn.naive_bayes import GaussianNB import numpy as np import matplotlib.pyplot as plt
- 使用以下包含逗号分隔的算术数据的数据文件:
in_file = 'data_multivar.txt' a = [] b = [] with open(in_file, 'r') as f: for line in f.readlines(): data = [float(x) for x in line.split(',')] a.append(data[:-1]) b.append(data[-1]) a = np.array(a) b = np.array(b)
- 构建朴素贝叶斯分类器:
classification_gaussiannb = GaussianNB() classification_gaussiannb.fit(a, b) b_pred = classification_gaussiannb.predict(a)
- 计算朴素贝叶斯的准确性:
correctness = 100.0 * (b == b_pred).sum() / a.shape[0] print "correctness of the classification =", round(correctness, 2), "%"
- 绘制分类器结果:
def plot_classification(classification_gaussiannb, a , b): a_min, a_max = min(a[:, 0]) - 1.0, max(a[:, 0]) + 1.0 b_min, b_max = min(a[:, 1]) - 1.0, max(a[:, 1]) + 1.0 step_size = 0.01 a_values, b_values = np.meshgrid(np.arange(a_min, a_max, step_size), np.arange(b_min, b_max, step_size)) mesh_output1 = classification_gaussiannb.predict(np.c_[a_values.ravel(), b_values.ravel()]) mesh_output2 = mesh_output1.reshape(a_values.shape) plt.figure() plt.pcolormesh(a_values, b_values, mesh_output2, cmap=plt.cm.gray) plt.scatter(a[:, 0], a[:, 1], c=b , s=80, edgecolors='black', linewidth=1,cmap=plt.cm.Paired)
- 指定图的边界:
plt.xlim(a_values.min(), a_values.max()) plt.ylim(b_values.min(), b_values.max()) *# specify the ticks on the X and Y axes* plt.xticks((np.arange(int(min(a[:, 0])-1), int(max(a[:, 0])+1), 1.0))) plt.yticks((np.arange(int(min(a[:, 1])-1), int(max(a[:, 1])+1), 1.0))) plt.show() plot_classification(classification_gaussiannb, a, b)
执行朴素贝叶斯分类器后获得的准确性如下截图所示:
另请参阅
请参考以下文章:
- 要了解分类器如何工作的示例,请参考以下链接:
en.wikipedia.org/wiki/Naive_Bayes_classifier
- 要了解更多关于使用提议的分类器进行文本分类的信息,请参考以下链接:
sebastianraschka.com/Articles/2014_naive_bayes_1.html
- 要了解更多关于朴素贝叶斯分类算法的信息,请参考以下链接:
software.ucv.ro/~cmihaescu/ro/teaching/AIR/docs/Lab4-NaiveBayes.pdf
逻辑回归分类器
可以选择这种方法,其中输出只能取两个值,0 或 1,通过/失败,赢/输,活着/死亡,健康/生病等。在因变量有两个以上的结果类别的情况下,可以使用多项逻辑回归进行分析。
如何做…
- 安装必要的软件包后,让我们构建一些训练标签:
import numpy as np from sklearn import linear_model import matplotlib.pyplot as plt a = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]]) b = np.array([1, 1, 1, 2, 2, 2])
- 初始化分类器:
classification = linear_model.LogisticRegression(solver='liblinear', C=100) classification.fit(a, b)
- 绘制数据点和边界:
def plot_classification(classification, a , b): a_min, a_max = min(a[:, 0]) - 1.0, max(a[:, 0]) + 1.0 b_min, b_max = min(a[:, 1]) - 1.0, max(a[:, 1]) + 1.0 step_size = 0.01 a_values, b_values = np.meshgrid(np.arange(a_min, a_max, step_size), np.arange(b_min, b_max, step_size)) mesh_output1 = classification.predict(np.c_[a_values.ravel(), b_values.ravel()]) mesh_output2 = mesh_output1.reshape(a_values.shape) plt.figure() plt.pcolormesh(a_values, b_values, mesh_output2, cmap=plt.cm.gray) plt.scatter(a[:, 0], a[:, 1], c=b , s=80, edgecolors='black',linewidth=1,cmap=plt.cm.Paired) # specify the boundaries of the figure plt.xlim(a_values.min(), a_values.max()) plt.ylim(b_values.min(), b_values.max()) # specify the ticks on the X and Y axes plt.xticks((np.arange(int(min(a[:, 0])-1), int(max(a[:, 0])+1), 1.0))) plt.yticks((np.arange(int(min(a[:, 1])-1), int(max(a[:, 1])+1), 1.0))) plt.show() plot_classification(classification, a, b)
执行逻辑回归的命令如下截图所示:
将数据集分割为训练集和测试集
分割有助于将数据集分割为训练和测试序列。
如何做…
- 将以下代码片段添加到同一个 Python 文件中:
from sklearn import cross_validation from sklearn.naive_bayes import GaussianNB import numpy as np import matplotlib.pyplot as plt in_file = 'data_multivar.txt' a = [] b = [] with open(in_file, 'r') as f: for line in f.readlines(): data = [float(x) for x in line.split(',')] a.append(data[:-1]) b.append(data[-1]) a = np.array(a) b = np.array(b)
- 将 75%的数据用于训练,25%的数据用于测试:
a_training, a_testing, b_training, b_testing = cross_validation.train_test_split(a, b, test_size=0.25, random_state=5) classification_gaussiannb_new = GaussianNB() classification_gaussiannb_new.fit(a_training, b_training)
- 在测试数据上评估分类器的性能:
b_test_pred = classification_gaussiannb_new.predict(a_testing)
- 计算分类器系统的准确性:
correctness = 100.0 * (b_testing == b_test_pred).sum() / a_testing.shape[0] print "correctness of the classification =", round(correctness, 2), "%"
- 绘制测试数据的数据点和边界:
def plot_classification(classification_gaussiannb_new, a_testing , b_testing): a_min, a_max = min(a_testing[:, 0]) - 1.0, max(a_testing[:, 0]) + 1.0 b_min, b_max = min(a_testing[:, 1]) - 1.0, max(a_testing[:, 1]) + 1.0 step_size = 0.01 a_values, b_values = np.meshgrid(np.arange(a_min, a_max, step_size), np.arange(b_min, b_max, step_size)) mesh_output = classification_gaussiannb_new.predict(np.c_[a_values.ravel(), b_values.ravel()]) mesh_output = mesh_output.reshape(a_values.shape) plt.figure() plt.pcolormesh(a_values, b_values, mesh_output, cmap=plt.cm.gray) plt.scatter(a_testing[:, 0], a_testing[:, 1], c=b_testing , s=80, edgecolors='black', linewidth=1,cmap=plt.cm.Paired) # specify the boundaries of the figure plt.xlim(a_values.min(), a_values.max()) plt.ylim(b_values.min(), b_values.max()) # specify the ticks on the X and Y axes plt.xticks((np.arange(int(min(a_testing[:, 0])-1), int(max(a_testing[:, 0])+1), 1.0))) plt.yticks((np.arange(int(min(a_testing[:, 1])-1), int(max(a_testing[:, 1])+1), 1.0))) plt.show() plot_classification(classification_gaussiannb_new, a_testing, b_testing)
在以下截图中显示了数据集分割时获得的准确性:
使用交叉验证评估准确性
交叉验证在机器学习中是必不可少的。最初,我们将数据集分割为训练集和测试集。接下来,为了构建一个健壮的分类器,我们重复这个过程,但需要避免过度拟合模型。过度拟合表示我们对训练集获得了很好的预测结果,但对测试集获得了非常糟糕的结果。过度拟合导致模型的泛化能力差。
如何做…
- 导入软件包:
from sklearn import cross_validation from sklearn.naive_bayes import GaussianNB import numpy as np in_file = 'cross_validation_multivar.txt' a = [] b = [] with open(in_file, 'r') as f: for line in f.readlines(): data = [float(x) for x in line.split(',')] a.append(data[:-1]) b.append(data[-1]) a = np.array(a) b = np.array(b) classification_gaussiannb = GaussianNB()
- 计算分类器的准确性:
num_of_validations = 5 accuracy = cross_validation.cross_val_score(classification_gaussiannb, a, b, scoring='accuracy', cv=num_of_validations) print "Accuracy: " + str(round(100* accuracy.mean(), 2)) + "%" f1 = cross_validation.cross_val_score(classification_gaussiannb, a, b, scoring='f1_weighted', cv=num_of_validations) print "f1: " + str(round(100*f1.mean(), 2)) + "%" precision = cross_validation.cross_val_score(classification_gaussiannb,a, b, scoring='precision_weighted', cv=num_of_validations) print "Precision: " + str(round(100*precision.mean(), 2)) + "%" recall = cross_validation.cross_val_score(classification_gaussiannb, a, b, scoring='recall_weighted', cv=num_of_validations) print "Recall: " + str(round(100*recall.mean(), 2)) + "%"
- 执行交叉验证后获得的结果如下所示:
为了了解它在给定的句子数据集上的工作情况,请参考以下链接:
- 逻辑回归简介:
machinelearningmastery.com/logistic-regression-for-machine-learning/
分析一个句子的情感
情感分析是指找出特定文本部分是积极的、消极的还是中性的过程。这种技术经常被用来了解人们对特定情况的看法。它评估了消费者在不同形式中的情感,比如广告活动、社交媒体和电子商务客户。
如何做…
- 创建一个新文件并导入所选的包:
import nltk.classify.util from nltk.classify import NaiveBayesClassifier from nltk.corpus import movie_reviews
- 描述一个提取特征的函数:
def collect_features(word_list): word = [] return dict ([(word, True) for word in word_list])
- 采用 NLTK 中的电影评论作为训练数据:
if __name__=='__main__': plus_filenum = movie_reviews.fileids('pos') minus_filenum = movie_reviews.fileids('neg')
- 将数据分成积极和消极的评论:
feature_pluspts = [(collect_features(movie_reviews.words(fileids=[f])), 'Positive') for f in plus_filenum] feature_minuspts = [(collect_features(movie_reviews.words(fileids=[f])), 'Negative') for f in minus_filenum]
- 将数据分成训练和测试数据集:
threshold_fact = 0.8 threshold_pluspts = int(threshold_fact * len(feature_pluspts)) threshold_minuspts = int(threshold_fact * len(feature_minuspts))
- 提取特征:
feature_training = feature_pluspts[:threshold_pluspts] + feature_minuspts[:threshold_minuspts] feature_testing = feature_pluspts[threshold_pluspts:] + feature_minuspts[threshold_minuspts:] print "nNumber of training datapoints:", len(feature_training) print "Number of test datapoints:", len(feature_testing)
- 考虑朴素贝叶斯分类器,并用指定的目标进行训练:
# Train a Naive Bayes classifiers classifiers = NaiveBayesClassifier.train(feature_training) print "nAccuracy of the classifiers:",nltk.classify.util.accuracy(classifiers,feature_testing) print "nTop 10 most informative words:" for item in classifiers.most_informative_features()[:10]:print item[0] # Sample input reviews in_reviews = [ "The Movie was amazing", "the movie was dull. I would never recommend it to anyone.", "The cinematography is pretty great in the movie", "The direction was horrible and the story was all over the place" ] print "nPredictions:" for review in in_reviews: print "nReview:", review probdist = classifiers.prob_classify(collect_features(review.split())) predict_sentiment = probdist.max() print "Predicted sentiment:", predict_sentiment print "Probability:", round(probdist.prob(predict_sentiment), 2)
- 情感分析的结果如下所示:
Python 物联网入门指南(二)(3)https://developer.aliyun.com/article/1507160