Churn or Not

Sparkify is a digital music service similar to Netease Cloud Music or QQ Music. Many of the users stream their favorite songs in Sparkify service everyday, either using free tier that places advertisements in between the songs, or using the premium subscription model where they stream music as free, but pay a monthly flat rate. User can upgrade, downgrade or cancel their service at anytime. This is a Customer Churn Prediction Problem , there are so many similar projects, such as WSDM - KKBox’s Churn Prediction Challenge competition from Kaggle, and a few helpful links are follows: Customer Churn Prediction using Machine Learning (How To) Prediction of Customer Churn with Machine Learning Customer Churn Prediction and Prevention Hands-on: Predict Customer Churn So, our job is deep mining the customers’ data and implement appropriate model to predict customer churn as follow steps: Clean data: fill the nan values , correct the data types, drop the outliers. EDA: exploratory data to look features’ distributions and correlation with key label (churn). Feature engineering: extract and found customer-features and customer-behavior-features; Implement standscaler on numerical features. Train and measure models: I choose logistic regression, linear svm classifier, decision tree and random forest classifier to train a baseline model and tuning a better model from best of them. It is worth mentioning that this data is unbalanced because of less churn customers, so we choose f1 score as a metrics to measure models’ performance. Quick Facts A mini subset of size 125 MB of the original 12 GB customer log json data file will be used for creating the prediction model. The small dataset has 286’500 log entries with 18 unique columns. The schema and info of dataset is given below: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 root |-- artist: string (nullable = true) |-- auth: string (nullable = true) |-- firstName: string (nullable = true) |-- gender: string (nullable = true) |-- itemInSession: long (nullable = true) |-- lastName: string (nullable = true) |-- length: double (nullable = true) |-- level: string (nullable = true) |-- location: string (nullable = true) |-- method: string (nullable = true) |-- page: string (nullable = true) |-- registration: long (nullable = true) |-- sessionId: long (nullable = true) |-- song: string (nullable = true) |-- status: long (nullable = true) |-- ts: long (nullable = true) |-- userAgent: string (nullable = true) |-- userId: string (nullable = true) Column’s NameDescription artistThe artist being listened to authWhether or not the user is logged in firstName/lastNameName of the user genderGender of the user itemInSessionItem number in session lengthLength of time for current row of specific log levelFree or Paid user locationPhysical location of user, including City and State methodGet or Put requests pageWhich page are user on in current row registrationUsers registration number sessionIdSession ID songSong currently being played statusWeb status tsTimestamp of current row userAgentUseragent of post or get in browser of users userIdUser ID Exploratory Data Analysis We use the Cancellation Confirmation events of page column to define the customer churn, and perform some exploratory data analysis to observe the behavior for users who stayed vs users who churned. churn So, there are 52 users have churned events in the dataset, it’s about 23.1% churned rate. The rate of churn and not churn is roughly 1:3, so this is an unbalanced dataset. gender Can we say the gender has effect on Churn or not ? We calculate the p-value and result is 0.20 over 0.05, so, we can’t say like that. page We count each item in page column of different group and normalized data. Obviously, NextSong has accounted for most of customers’ events. Thumbs Up ,Thumbs Down , Home and Add to Playlist have effect on churn too. userAgent We extract the browser and platform of customers from userAgent column. Customers using safari and iPad have more proportion in churn. time We extract day-of-month, day-of-week and hour from ts column. Customers from churn group have more events after 15th in one month, and have less events in weekend. Feature Engineering On the basis of the above EDA, we can create features as follows: Categorical Features gender level browser platform Numerical Features mean,max,min,std of length of users numbers of each item in page (ThumbsUp … number of unique songs and total songs of users number of unique artists of users percentage of operations after 15th in a month percentage of operations in workday We implement label encoding on categorical features and standard scaler on numerical features. Modeling We split the full dataset into train and test sets. Test out the baseline of four machine learning methods: Logistic Regression, Linear SVC, Decision Tree Classifier and Random Forest Classifier. Though the LinearSVC spent more training time, but it can get the highest f1 score 0.702. And the LogisticRegression has a medium training time and f1 score, maybe I can tuning it to get a higher score. So I’ll choose LinearSVC and LogisticRegression to tuning in next section, the result is as follows: Linear SVC Training time: F-1 Score: LogisticRegression Training time: F-1 Score: As we can see in above, the logistic regression (0.7021) can get a nearly f1 score as the linear svm classifier(0.7045). But the logistic regression saves 83.3% time spending than the latter, considering this is only a quit mini dataset and our purpose is scaling this up to the total 12G dataset, so, the logistic regression is the best model from now on in this project. Conclusion Reflection In this project I set out to predict customers’ churn problem with the dataset of a music streaming service named Sparkify. This is a binary classification problem , so I choose four supervised learning algorithm to found a model. After evaluated and tuning, I find out the logistic regression is the suitable model for this project because of its balanced and high f1-score (0.7021) and time spending. By the way, I once fell into the trap of data leakage ,so that all of the models can achieve a performance that seems too good (1 for f1-score) to be true. I had to go back to check my feature engineering, and found I put the cancellation confirmation which is the flag of churn in the features, what a awkward thing! And that teach us you must be careful and patient when you are working. Improvement There are only about 76 samples in the mini dataset above, so the model could be improved by being trained on a bigger dataset and tuning hyper parameters based on it. Another improvement could be to try out more features or deep learning models. Github Repo Hope you find this interesting and for further details on this analysis like code and process followed would be available here.

2019/9/27
articleCard.readMore

利用Flask与pyecharts搭建Dashboard

概述 当处理一些较为灵活的数据时,团队内不同角色的同事会有自己对数据的关注点,所以,这就要求数据分析师不能只出一个“死”报告了事儿,而需要的是一个可以让同事们去探索,去解决自己关注问题的”活“报告——Dashboard。本文就一起来探讨下,利用Flask和Pyecharts搭建局域网内Dashboard的方法,其中Flask用来提供Web应用框架,Pyecharts用来解决交互式可视化的需求。 功能需求 可视化图像可交互 可以根据用户需求,从数据库中筛选不同的数据进行可视化 Dashboard框架 如上图所示,我们依据数据的流向确定了Dashboard的框架,并列出了在不同过程中的所需知识: 依据Dashboard中用户的需求(可选),从数据库中提取数据,并对数据进行预处理,以方便后续进行可视化; 利用Pyecharts对提取的数据进行可视化; 利用Flask将Pyecharts生成的可视化图像嵌入到HTML模板中,并利用Javascript丰富前端的动作、处理事件,利用Ajax实现前后端交互等。 两个关键点 在Flask框架中使用Pyecharts 这在Pyecharts的官方文档中写的非常详细,可以戳Flask 模板渲染查看示例。 如何处理Jinja2 和 JavaScript 语法的冲突 为了快速搭建Dashboard,免去一些前端配色、布局等烦恼,我们一般会挑选一个HTML模板,而Jinja2就是一个模板渲染引擎,它的语法中,使用一对双大括号标记变量,这与JavaScript的语法标记会有冲突,所以,如果你使用Jinja2进行模板渲染的同时使用了JavaScript,就要进行语法冲突处理。 最终效果 致谢&参考 Pyecharts给了我丰富的交互式可视化选择,详细的文档上手就会,强烈推荐! 李辉的HelloFlask站点,轻松入门Flask。 Data visualization using D3.js and Flask flask框架中jinja2传递参数和html,js文件接收参数 Echarts Demo - 多图联动 源码 Github链接:Flask+Pyecharts定制Dashboard 除以上两点之外,在源码中,还实现了以下功能: 多个可视化图像的联动 多级菜单联动选择 前后端交互 表格数据排序与搜索 希望能对有相同需求的你有所帮助,欢迎留言,一起讨论! 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

2019/8/15
articleCard.readMore

Python中查找字符串中第n次出现某字符的位置

概述 在处理字符串时,有时需要从字符串中提取出第n次出现某字符的位置,比如说想在字符串'abcdabdcsas'中找到第2次出现'ab'的索引,但Python String提供的find函数只能Return the lowest index in S where substring sub is found,所以,自己动手,丰衣足食:joy: 本文分为两部分: 解决上述问题的两种方法及运行效率对比 延伸: 出现某字符的全部索引 最后一次出现某字符的索引 两种方法 常规思路 先用find函数查找得到第一次出现的索引,然后将字符串在该索引处做切片,再进行查找,以此类推,直到查询到第n次。 1 2 3 4 5 6 7 8 9 10 11 def finding_nemo_1(String,Substr,times): ''' 在String中查找Substr出现第times次的索引。 ''' s = time.time() nemo = 0 for i in range(1,times+1): nemo = String.find(Substr,nemo) + 1 if nemo == 0: return -1 return (nemo-1, time.time()-s) 利用split切分和列表 将String按照Substr切分times次,代码如下所示,计算很简单。 1 2 3 4 5 def finding_nemo_2(String,Substr,times): s = time.time() String_list = String.split(Substr,times) nemo = len(String) - len(String_list[-1]) - 1 return (nemo, time.time()-s) 我们对以上两种方法进行了对比,如下图所示,第二种方法的优势随着字符串长度的增长而更加明显。 第二种方法,巧就巧在将运行效率低的for循环替换成了split,在对长度为250e6的字符串进行查找时,运算时间缩短了近77%。 延伸 很容易将以上两种方法改写成获取某字符出现的全部索引函数。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #方法一 def finding_all_nemo_1(String,Substr): start = 0 end = len(String) - 1 nemo = 0 nemo_list = [] while nemo != -1: nemo = String.find(Substr,start,end) nemo_list.append(nemo) start = nemo + 1 nemo_list.remove(-1) return nemo_list #方法二 def finding_all_nemo_2(String,Substr): count = 0 nemo_list = [] String_list = String.split(Substr) for i in range(len(String_list)-1): element = String_list[i] count += len(element) nemo = i + count nemo_list.append(nemo) return nemo_list 那获取某字符串最后一次出现的位置,有没有更便捷的方法呢? 注意:find可以很快的找到第一次出现的位置 所以,我们将字符串反转,再用find就可以很容易求得索引了。 1 last_index = -(String[::-1].find(Substr) + 1) 如果你也有其他的方法,欢迎留言,一起讨论~ 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

2019/7/23
articleCard.readMore

基于OpenCV的表格识别

概述 上一篇博客中,我们把图片中的水印去除掉,并且加深了字体的颜色,之后我对图片的大小进行了统一,甚至我还专门给他们都加上了参照字段,分别尝试了百度AIP的表格识别服务和Face++的自定义模板文字识别服务,可能是因为图片的分辨率较低,而且文字较密集的缘故,最终得到的结果都不尽如人意,错误率非常高,所以准备尝试下先将图片按照行列进行分割,之后再逐个去识别的方法,结果却出乎我的意料。 识别表格 要想对图片中的表格进行精准切分,就必须要先对表格进行识别,然后再根据行列相交点的位置进行切分。 读取中文路径的图片 1 2 3 def cv_imread(filepath): cv_img = cv2.imdecode(np.fromfile(filepath,dtype=np.uint8),-1) return cv_img 将图片转为黑底白字 因为后续的膨胀是对高亮部分(白色)进行处理,所以就需要把我们感兴趣的部分——表格线转为白色 1 2 3 4 #转为二值图,矩阵中只有0和255 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #似曾相识?和上一篇中去水印的函数一样,只不过这里的Thresh方法选择的是THRESH_BINARY_INV,与THRESH_BINARY效果刚好相反,200以上转为0(黑色),200以下转为255(白色) img_thresh = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY_INV)[1] 查看效果 1 2 cv2.imshow("Image",img_thresh) cv2.waitKey(0) 识别 1 2 3 4 5 6 7 8 9 10 11 12 13 14 rows,cols=img_thresh.shape #可以把这个变量理解为精度,数值越大,识别的就越精细(下面会有示例图) precision = 20 #识别横线 #膨胀和腐蚀用的卷积核,值为1,shape为cols//precision列,1行 kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(cols//precision,1)) #腐蚀 eroded = cv2.erode(img_thresh,kernel,iterations = 1) #膨胀 row_lines = cv2.dilate(eroded,kernel,iterations = 1) #识别竖线 kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(1,rows//precision)) eroded = cv2.erode(img_thresh,kernel,iterations = 1) col_lines = cv2.dilate(eroded,kernel,iterations = 1) 识别的关键就在于腐蚀与膨胀函数。腐蚀即为让卷积核在二值化的图片上滑动并进行卷积计算,只有在卷积核范围内图片中的所有值均为255时才会得到255的结果,其余情况均得到0;而膨胀刚好相反,在卷积核范围内只要有一个值为255,那么就会得到255的结果。 所以,在我们进行表格中的行识别时,就需要选择尽可能长(很多列)和矮(一行)这种形状的卷积核,才能契合长长的横线,然后把比较短的文字腐蚀掉。看下面的示例: 示例图片的shape为(369,1000) precision=20时,卷积核的shape为(50,1),识别得到的结果: 这时候已经把所有行都识别出来了,因为不会有任何一个字的长度可以超过50个像素,那么现在我们把卷积核的shape调整到(5,1)再来看下效果。 precision=200时,识别得到的结果: 可以发现,很多字中的横都没有被腐蚀掉。 筛选交点位置坐标 我们筛选出那些在行和列都等于255的点,就可以得到所有交点了。 1 intersections = cv2.bitwise_and(row_lines,col_lines) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #筛选出白点的索引(坐标) ys,xs = np.where(bitwiseAnd>0) #为了避免在一个交点位置存在多个连续像素为255的值,所以我们需要按照距离对这些点进行筛选 x_list,y_list=[],[] #先排序 xs=np.sort(xs) #筛选出距离大于20像素的点 for i in range(len(xs)-1): if(xs[i+1]-xs[i]>20): x_list.append(xs[i]) #添加上最后一个位置的点 x_list.append(xs[i]) #y_list的处理方式相同 这样我们就把所有交点的坐标都筛选出来了。 截取图片并识别 按照交点坐标截取单元格后,再转换为jpg或者是png格式的二进制编码,利用百度aip的通用文字识别API进行识别,获取结果。 1 2 3 4 5 6 7 8 9 #按照交点坐标截取单元格 i = 1 #加减int的原因是将表格线隐藏 ROI = img_thresh[y_list[i]+3:y_list[i+1]-3,x_list[0]+3:x_list[1]-3] #必须要先用 jpg或者png转码,再转化为二进制,要不然百度aip识别不了 _,encoded_img = cv2.imencode('.jpg',ROI) img_bytes = encoded_img.tobytes() result = client.basicGeneral(img_bytes) result['words_result'][0]['words'] 最后再利用Pandas将得到的结果以此储存到DataFrame中,导出Excel,收工! 总结 识别方法很笨,虽然正确率较高,但是识别速度较慢; 依赖百度文字识别服务。 下一步尝试: Google开源OCRtesseract-ocr 基于yolo3 与crnn 实现中文自然场景文字检测及识别的chineseocr 基于tensorflow、keras/pytorch的OCR中文文字识别CHINESE-OCR 参考 Image Thresholding OpenCV学习笔记-腐蚀和膨胀 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

2019/5/31
articleCard.readMore

一个简单的去水印小工具

概述 今年阳光高考公示的自主招生名单变成了图片格式,还加了水印,(洪主编说“今年阳光高考变坏了”:joy:),确实是变坏了,无形中给我增添了不少工作:angry:,那么要转为Excel,就要进行文字识别,就需要先把烦人的水印去除掉。 本文分为两部分: 基于OpenCV的图片水印去除 将python脚本封装为可执行exe程序 去除水印 先放原图: 观察上图,可以得到如下结论: 图片本身就是灰度图,也就是各个像素的RGB是相等的; 水印的位置并不固定,没办法针对某一位置单独处理; 水印颜色统一; 水印颜色与文字颜色相差较多,水印颜色要比文字颜色浅; 让我做PS是不可能的,因为还有上百张这样的图片。 所以,我们可以从颜色上入手,直接用OpenCV中的Image Thresholding函数,选择介于文字与水印灰度中间的某一值作为阈值,然后将大于该阈值的值替换为255(白色),小于该阈值的值替换为0(黑色),这样便可以把图片中所有水印(包括表头的阴影)都去除掉了。 颜色拾取 为了选择阈值,我们得先看一下文字和水印的RGB,我是用的Colors Pro(随便下一个颜色识别器或者用Office/PS等都可以)。 识别结果如上: 文字的灰度介于50~140之间;水印及阴影的灰度介于220-240之间,所以我们可以选择200作为阈值。 关键代码 1 cv2.threshold(img, 200, 255, cv2.THRESH_BINARY)[1] 去除水印后的效果: 去水印的速度非常快(不到一秒一张图),效果也很不错,不仅去除了水印,还把原来偏灰色的文字变成了黑色,更方便下一步的文字识别工作。 但,同事也有这种需求,就索性封装一个可执行文件exe给他备用,本来以为很简单的事儿,折腾了我一整个晚上:joy:,下面分享下我封装python脚本时踩的坑。 程序封装 参考stackoverflow上a-good-python-to-exe-compiler的答案,大家都在推荐Pyinstaller,所以就是它了。 Pyinstaller的使用方法非常简单,只需 1 2 #安装 pip install pyinstaller 然后在命令行中进入到目标脚本的文件夹下,输入 1 2 #-F为附加的参数,效果为只输出单个的exe文件,拷给基友用更方便 pyinstaller -F your-script-name.py 就可以在生成的hist文件夹下找到封装好的exe文件了:smile:。 然而事情的真相是,各种Permission Denied,网上的解决方法是用管理员模式运行,对于我这电脑来说然并卵。折腾了一晚上,终于通过安装了下面两个库解决了: 重新安装pywin32,参考:如何下载和安装pywin32(亲测有效) 下载安装了vc++2018运行库的合集(因为以前大学打游戏,常被这个问题困扰,这次死马当活马医,居然医活了。。。) 总结 这个去水印小工具,只能针对类似文中的这种灰度图进行水印处理,如果你想去除彩色图片的水印,请打开PS,然后用Shift+F5盘它! 最后附上这个去水印小工具:链接, 密码:r38ev8 使用方法: 自行搜索安装vc++2018运行库合集 把exe复制到你要处理图片的文件夹 打开,输入阈值灰度 回车,处理好的图片会自动储存在removed文件夹下 运行效果: 参考 Image Thresholding a-good-python-to-exe-compiler Pyinstaller 如何下载和安装pywin32(亲测有效) 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

2019/5/30
articleCard.readMore

Airbnb in Beijing isn't as Cool Enough as it's Advertised

Shortly after moving to San Francisco in October 2007, roommates and former schoolmates Brian Chesky and Joe Gebbia could not afford the rent for their loft apartment. Chesky and Gebbia came up with the idea of putting an air mattress in their living room and turning it into a bed and breakfast. The goal at first was just “to make a few bucks”. ​ —— Airbnb Wiki A‌i‌r‌b‌n‌b‌,‌ ‌I‌n‌c‌.‌, is an online marketplace and hospitality service brokerage company, It has a cool brand story, with hosts sharing their extra living space, guests living for a fee, and allowing guests to experience real local life instead of booking a hotel. It sounds really cool, but what is the real situation in Beijing? Let’s check it out from two parts: Listings in Beijing Hosts in Beijing In this blog, the data is provided by Inside Airbnb, and it contains all informations of 25921 listings in Beijing. Listings in Beijing In this part ,we will focus on prices and numbers of listings in different times and different locations to learn about Airbnb’s development in Beijing. How does the price of Airbnb change over time? Overall, prices of listings in Beijing are gradually stabilizing. In general, prices will rise in May and October each year which corresponds to Labor Day and National Day vocation. What’s the difference in listings prices in all districts of Beijing? Huairou District has the most expensive middle price and the maximum variance. It’s really surprising that the first chair of price is not Dongcheng District where Tiananmen Square located. Fangshan District has the most cheap middle price and Tongzhou District has the minimum variance. How does the number of Airbnb change over time and districts? As we can see in the figure above, the number of listings in Beijing has been keeping increase from 2010, and the increasing speed is getting more and more fast. So, Airbnb business in Beijing is seems good. The increasing speed will be slow down in the first half of the year, and will speed up in the second half of the year. Chaoyang District(朝阳区) is far ahead in total number and growth rate. As of January 2019, the total number of listings in Chaoyang District accounted for 40% of the total number in Beijing. Hosts in Beijing In this part , we will focus on host introduction ,type and service to look deep inside the hosts of Airbnb in Beijing. What’s the favorite word of hosts to describe themselves ? I made a word cloud with host_about. As we can see, most hosts like to put a label “like to make friends” ,” welcome friends all over the word” or “like to travel” on themselves. It seems to be a good match for Airbnb’s slogan. Now that the hosts are describing themselves so enthusiastic, what are they actually like? Are they all personal hosts? In the box plot, I set outliers when it’s over 1.5 times of IQR. Almost a half of hosts have more than 2 listings, some of them are apartment companies, some of them are sublessors , so we can see that there are some people investing or starting a business in Airbnb with listings. Maybe we should call hosts with 2-5 listings sublessors, and more than 5 listings should be called professional hosts, and the others are called personal host. There are 56% of hosts are personal hosts, but they only account for 19.5% of listings. Conversely, 14.5% of hosts are professional hosts, but they account for nearly 55% of listings. I have no idea what is the difference between this kind of listings and hotels, except for not safe maybe. How’s the hosts’ service? We chose Proportion of within an hour,Host Response Rate and Average Score to judge the pros and cons of service. As shown in the plot above, the personal host has the lowest Proportion of within an hour and Host Response Rate, but has the highest Average Score. Meanwhile, the professional hosts has the exact opposite characteristics. Maybe a personal host need to work or do something else which makes he doesn’t have enough time to response guests timely, but he can help guests experience a real local life which makes he get a high review score. Can We Predict the Price? I made some attempts, but the results were not satisfactory. Although the following characteristics have the greatest impact on the price. Top five importances of features are shown in the plot above, and we can say the more guests a listing can accommodate, the higher price it can be.(It’s like crap.) Conclusion If you have any plans to travel to Beijing recently and you want to book a listing through Airbnb, please note these suggestions: Please avoid the May and October; Maybe you can choose the listing in Chaoyang District, which has the most number of listings and relatively fair prices; If you want to experience a real local life in Beijing ,please choose the personal host. Finally, I hope you’ll be welcomed home by Airbnb :).

2019/5/27
articleCard.readMore

机器学习中不平衡数据的预处理

概述 最近在处理自主招生的数据,对于某一个确定的高校来说,录取的人数远远小于未录取的人数,换言之,就是录取类的数据量远小于未录取类的数据量,这就是不平衡数据,虽然在机器学习中不平衡数据的处理不是难点,但这也是我们不得不去考虑的问题,那在本篇文章中,我们便来一起探讨下有哪些处理不平衡数据的技巧。 什么是不平衡数据 不平衡数据,顾名思义,就是指在收集到的数据中各个分类之比并非为1:1,在对不平衡数据的研究中,普遍认为不平衡意味着少数类所占比例在10%到20%之间,但实际上,这种现象可能会更严重,比如说: 每年有大约2%的信用卡用户存在欺诈; 某种情况的医学筛查,比如说美国的艾滋病得病率约为0.4%; 磁盘驱动器的故障率每年约1%; 在线广告的转化率约在10-3至10-6之间; 文章开头提到的高校录取率,比如某985院校的自主招生审核通过率在0.2%左右。 对于这种不平衡的数据来说,如果不进行数据预处理就应用机器学习算法进行训练,那么得到的模型只需要把所有的结果都预测为多数类那边,就能获得很高的准确率(比如说,对所有的学生都判定为审核未通过,那么准确率会达到1-0.2%=99.8%),但是这其实一点用都没有。 平衡数据大概像是这样: 不平衡数据大概像是这样: 处理不平衡数据 处理不平衡数据的思路比较简单,那就是想办法让数据平衡,我们可以简单得分为以下几类: 更改数据集中各分类数据的量,使他们比例匹配——常用方法有采样、数据合成; 更改数据集中各分类数据的权重,使他们的量与权重之积匹配——常用方法为加权; 不修改数据集,而是在思路上将不平衡数据训练问题转化为一分类问题或者异常检测问题(少数类就像是存在于多数类中的异常值)。 更多更详细研究范畴的分类可以查看这篇论文A Survey of Predictive Modelling under Imbalanced Distributions 那接下来,我们分别看一下各个方法在python中的具体实施。 采样 采样就是通过减少多数类数量的下采样(Undersampling)或增加少数类数量的上采样(Oversampling)方式,实现各类别平衡。针对两种采样方式,依赖不同的方法,比如说 随机、模型融合等,就会生成很多解决方案,可以看这篇综述Learning from Imbalanced Data的总结。 代码实现 有一个叫做imbalanced-learn的库,是专门针对不平衡数据设计的,其中包含很多上采样和下采样的函数,官方文档在这里。 示例: 1 2 3 4 5 6 7 8 9 10 from collections import Counter from sklearn.datasets import make_classification from imblearn.under_sampling import RandomUnderSampler from imblearn.over_sampling import RandomOverSampler #生成不平衡数据 X, y = make_classification(n_classes=2, class_sep=2, weights=[0.1, 0.9], n_informative=3, n_redundant=1, flip_y=0, n_features=20, n_clusters_per_class=1, n_samples=1000, random_state=10) print('Original dataset shape %s' % Counter(y)) Original dataset shape Counter({1: 900, 0: 100}) 1 2 3 4 #随机下采样 rus = RandomUnderSampler(random_state=42) X_res, y_res = rus.fit_resample(X, y) print('Resampled dataset shape %s' % Counter(y_res)) Resampled dataset shape Counter({0: 100, 1: 100}) 1 2 3 4 #随机上采样 ros = RandomOverSampler(random_state=42) X_res, y_res = ros.fit_resample(X, y) print('Resampled dataset shape %s' % Counter(y_res)) Resampled dataset shape Counter({0: 900, 1: 900}) 数据合成 随机上采样会反复出现一些样本,而导致过拟合;随机下采样则会造成一定程度的特征丢失,虽然这种方式比较简单,但现在计算机的计算能力越来越高,可接受的算法复杂度也越来越高,所以我们应该主要考虑模型训练的效果。 数据合成则是利用已有样本生成更多样本,其中常用的包括: SMOTE,利用KNN生成新数据; SMOTEC,可以合成分类数据,但数据集中至少要包含一条连续数据; 如果数据集中全是分类数据的话,可以增加一列全为1的intercept列作为连续数据,合成数据之后,再将该列删除即可。 BorderlineSMOTE,与SMOTE的区别是,只为那些周围大部分是大众样本的小众样本生成新样本(因为这些样本往往是边界样本); 代码实现 1 2 3 4 5 6 from imblearn.over_sampling import SMOTE #SMOTE合成 sm = SMOTE(random_state=42) X_res, y_res = sm.fit_resample(X, y) print('Resampled dataset shape %s' % Counter(y_res)) Resampled dataset shape Counter({0: 900, 1: 900}) 更改权重 更改权重就是针对不同类别的数据设置不同的分错代价,即提高少数类分错的代价或降低多数类分错的代价,最终使各类别平衡。 常用的机器学习训练方法中,很多都提供了权重设置参数class_weight,可以手动设置该参数,但一般情况下只需要将其设置为balanced即可,模型会自动按照如下公式更新权重: 代码实现 1 2 3 4 5 6 7 from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier #逻辑回归平衡权重 clf_A = LogisticRegression(random_state=0, class_weight='balanced') #随机森林平衡权重 clf_B = RandomForestClassifier(random_state=0, n_jobs=-1, class_weight="balanced") 一分类 这种方法比较适合极不平衡数据,或数据量比较小的数据集。 主要方法为OneClassSVM,官方文档在这里 代码实现 1 2 from sklearn import svm clf = svm.OneClassSVM(nu=0.2, kernel="rbf", gamma=0.1) 异常检测我没怎么用过,所以就不赘述了,感兴趣可以戳这个链接Novelty and Outlier Detection 总结 我们可以依据数据量的大小和是否平衡将数据集分为四类,即平衡的大数据集,不平衡的大数据集,平衡的小数据集,不平衡的小数据集。最简单的就是平衡的大数据集,能达到非常高的准确率,最难的就是不平衡的小数据集,除了在平衡上下功夫之外,还需要很多诸如收集数据、特征工程之类的工作,但这并不是本篇文章的重点。 下面根据个人经验谈下针对如上几种数据集,如何选择文中涉及的这些方法: 数据量较小的情况考虑用数据合成的方法,依据特征的类型(分类&连续数值)选择合适的方法。 数据量还可以,但类别之间数量相差悬殊的时候考虑用一分类或者异常检测的方法。 数据量还可以,而且类别之间数量相差不是特别悬殊的情况,考虑用采样或者更改权重的方法。 具体数据量的大小可以参考下图: 参考 Learning from Imbalanced Classes A Survey of Predictive Modelling under Imbalanced Distributions 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

2019/4/19
articleCard.readMore

selenium爬取新榜公众号信息

这两天需要对公众号的信息进行爬取,原以为只是爬取信息,而不需要怕公众号,会比较简单,所以尝试了: littlecodersh的ItChat 可以获取公众号的名称、功能描述以及地区,但并没有把公众号的ID以及认证公司等信息集成进去,而且必须要本人关注之后才能处理; 搜狗微信 搜狗微信的信息倒是齐全,完全可以满足要求,但是尝试了request+BeatifulSoup还有Selenium之后发现,这个网址真的太小气了,我加了延时,用了代理,依然各种被封,或者是要求输入验证码; 新榜 只能获取已经收录的公众号信息,好在收录的数量也很多,用request会出现搜索失败,但是用Selenium还是稳的,加了延时,顺利获取了几千条数据。而且,这里还可以查到各个行业时下最热文章、阅读量等等信息。 用selenium爬取代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from selenium import webdriver # 引入Keys类包 发起键盘操作 from selenium.webdriver.common.keys import Keys import time import csv def store_data(name,description,company): #储存信息 writer.writerow((name,description,company)) def get_id(name): #传入搜索关键词 并进行搜索 driver.find_element_by_id('txt_account').clear() time.sleep(3) driver.find_element_by_id('txt_account').send_keys(name) driver.find_element_by_id('txt_account').send_keys(Keys.ENTER) time.sleep(10) #获取信息并储存 description = driver.find_element_by_class_name('wx-description-info').text company = driver.find_element_by_class_name('auth-span').text store_data(name,description,company) time.sleep(30) #打开浏览器 driver = webdriver.Firefox() #打开网址 driver.get('https://www.newrank.cn/') #爬取 error_name = [] csvfile = open('公众号信息.csv','a+') writer = csv.writer(csvfile) for name in id_list: idx = id_list.index(name) lenght = len(id_list) try: if idx%10 == 0: print(f'{idx+1}/{lenght} is working...') get_id(name) except: error_name.append(name) csvfile.close() 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

2019/4/5
articleCard.readMore

利用python批量出报告

概述 最近单位需要批量输出报告,好在这些报告的整体模板相同,只有一些跟用户相关的信息需要替换。几千份的重复工作,还是交给Python去处理吧。 本文的技术路径为:利用docxtpl对word模板文件进行变量替换,然后利用 将word转换为pdf。 本文代码应用环境如下: 1 2 3 4 * Windows 7 * Python 3.7 * docxtpl-0.5.17 Word文档处理 安装 主要用docxtpl库实现。官方文档 直接pip install docxtpl即可,会自动安装依赖库:docx和jinja2。 模板文档准备 如下所示,将需要进行变量替换的位置用两对大括号括起来,并在其中添加变量名,这是后续能通过python识别替换的关键。 表格 表格的变量设置比较麻烦,可以查看官方github,里面有很多示例代码,随用随取。 设置表格变量的时候,有两个关键,一个是行 ,一个是列,其中行用字段tr(row)表示,列用字段tc(column)表示。 如下表中所示,我们通过构建列表循环 和 调用字典key的方式,对表格中的各个项进行填充。 使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from docxtpl import DocxTemplate,InlineImage from docx.shared import Mm import jinja2 #读取模板文档 tpl = DocxTemplate('自主招生大数据报告模板.docx') #替换word中的变量 #字典中的key为变量名,value为要替换的值 context = { 'stu_id':123, 'stu_phone':13612341234, 'stu_province':'河北', 'stu_grade':'高二', 'stu_wenli':'理科', 'stu_school':'南宫中学', 'stu_university':'西安交通大学', 'stu_prize_1':'化学省一', 'image_1':InlineImage(tpl,'E:/wallpapers/1.jpg',width=Mm(120)), 'items' : [ {'university' : '西安交通大学', 'major' : '电气工程,能源动力','year':2018, 'prize' : '数学省一','nums':200 }, {'university' : '复旦大学', 'major' : '金融学', 'year':2018,'prize' : '数学省三','nums':20 }, {'university' : '北京理工大学', 'major' : '兵器学', 'year':2018,'prize' : '物理省二','nums':2 }, ], } #输出 tpl.render(context) tpl.save('output/自主招生报告.docx') Word转PDF 通过Windows Com组件(win32com),调用Word服务(Word.Application),实现Word到PDF文件的转换。因此,要求该Python程序需要在有Word服务(可能至少要求2007版本)的Windows机器上运行。 参考:批量转换Word文件为PDF文件 1 2 3 4 5 6 7 8 9 10 11 12 13 import win32com.client #WdSaveFormat指令,17表示转为PDF #更多信息可以查看:https://docs.microsoft.com/zh-cn/office/vba/api/word.wdsaveformat wdFormatPDF = 17 word = win32com.client.Dispatch('Word.Application') #打开文档,绝对地址 doc = word.Documents.Open('F:\\0 zizhuzhaosheng\\docs\\test.docx') #输出文档路径,绝对地址 doc.SaveAs('F:\\0 zizhuzhaosheng\\docs\\test.pdf', FileFormat=wdFormatPDF) #退出 doc.Close() word.Quit() 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

2019/4/4
articleCard.readMore

第三周-Numpy和Pandas基础

A positive attitude causes a chain reaction of positive thoughts,events and outcomes. Hi,同学们,上周我们主要对python的基础知识进行了学习,从完全不懂到写出第一段代码,从畏惧发怵到解决第一个代码问题,大家已经从小白迈出了python入门的第一步!你们都是最棒的!那请继续保持着这样的学习动力,趁热打铁,继续我们的课程吧! 本周开始,我们就进入到了项目二(P2)阶段的第二周,需要针对数据分析来学习两个重要的第三方库Numpy和Pandas,它们是python实现科学计算和数据处理的重要库,在以后的数据分析路上会经常用到,所以一定要掌握,并且还要熟练! 时间学习重点对应课程 第1周Python基础内容数据类型和运算符、控制流、函数、脚本编写 第2周Python数据处理内容Numpy & Pandas 第3周完成项目项目:探索美国共享单车数据 第4周项目修改与通过修改项目、查缺补漏、休息调整 对于非小白同学来说,本阶段内容不是很难,希望你们能在三周内完成并通过项目; 对于小白来说,本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决: 先自行查找问题答案(注意提取关键词),参考:谷歌/百度搜索、菜鸟教程、CSDN、stackoverflow、Python for Data Analysis, 2nd Edition 、Python Cookbook 若问题未解决,请将问题及其所在课程章节发送至微信群,并@助教即可 饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧! 注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索! 本周目标 学完课程Numpy&Pandas。 (可选)项目环境准备。 知识清单 Numpy NumPy 简介 NumPy 是 Numerical Python 的简称,它是 Python 中的科学计算基本软件包。NumPy 为 Python 提供了大量数学库,使我们能够高效地进行数字计算。更多可点击Numpy官网查看。 关于Numpy需要知道的几点: NumPy 数组在创建时有固定的大小,不同于Python列表(可以动态增长)。更改ndarray的大小将创建一个新的数组并删除原始数据。 NumPy 数组中的元素都需要具有相同的数据类型,因此在存储器中将具有相同的大小。数组的元素如果也是数组(可以是 Python 的原生 array,也可以是 ndarray)的情况下,则构成了多维数组。 NumPy 数组便于对大量数据进行高级数学和其他类型的操作。通常,这样的操作比使用Python的内置序列可能更有效和更少的代码执行。 所以,Numpy 的核心是ndarray对象,这个对象封装了同质数据类型的n维数组。起名 ndarray 的原因就是因为是 n-dimension-array 的简写。接下来本节所有的课程都是围绕着ndarray来讲的,理论知识较少,代码量较多,所以大家在学习的时候,多自己动动手,尝试自己去运行一下代码。 创建ndarray 课程中所说的,创建一个秩为2的ndarray,实际上指的是创建一个2维的ndarray,并不是矩阵的秩。 由python list创建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 a = np.array([1, 2, 3]) # 1维数组 print(type(a), a.shape, a[0], a[1], a[2]) out: <class 'numpy.ndarray'> (3,) 1 2 3 a[0] = 5 # 重新赋值 print(a) out: [5 2 3] b = np.array([[1,2,3],[4,5,6]]) # 2维数组 print(b) out: [[1 2 3] [4 5 6]] print(b[0, 0], b[0, 1], b[1, 0]) out: 1 2 4 由numpy内置函数创建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 a = np.zeros((2,2)) # 创建2x2的全0数组 print(a) [[ 0. 0.] [ 0. 0.]] b = np.ones((1,2)) # 创建1x2的全1数组 print(b) [[ 1. 1.]] c = np.full((2,2), 7) # 创建2x2定值为7的数组 print(c) [[7 7] [7 7]] d = np.eye(2) # 创建2x2的单位矩阵(对角元素为1) print(d) [[ 1. 0.] [ 0. 1.]] d_1 = np.diag([10,20,30,50]) #创建一个对角线为10,20,30,50的对角矩阵 print(d_1) [[10 0 0 0] [ 0 20 0 0] [ 0 0 30 0] [ 0 0 0 50]] e = np.arange(15) #创建一个一维的0-14的数组 print(e) [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] e_1 = np.arange(4,10) #创建一个一维的4-9的数组 print(e_1) [4 5 6 7 8 9] e_2 = np.arange(1,14,3) #创建一个一维的1-13且以间隔为3的数组 print(e_2) [ 1 4 7 10 13] f = np.linspace(0,10,6) #创建一个一维的范围在0-10,长度为6的数组 print(f) [ 0., 2., 4., 6., 8., 10.] #各个元素的间隔相等,为(10-0)/(6-1) = 2,若不想包含末尾的10,可以添加参数endpoint = False g = np.arange(12).reshape(3,4) #把arange创建的一维数组转换为3行4列的二维数组 print(g) #同样方法也适用于linspace等 [[ 0, 1, 2, 3], #注意:使用reshape转换前后的数据量应该相同,12 = 3x4 [ 4, 5, 6, 7], [ 8, 9, 10, 11]] h = np.random.random((2,2)) # 2x2的随机数组(矩阵),取值范围在[0.0,1.0)(包含0,不包含1) print(e) [[ 0.72776966 0.94164821] [ 0.04652655 0.2316599 ]] i = np.random.randint(4,15,size = (2,2)) #创建一个取值范围在[4,15),2行2列的随机整数矩阵 print(i) [[6, 5], [5, 9]] j = np.random.normal(0,0.1,size = (3,3)) #创建一个从均值为0,标准差为0.1的正态分布中随机抽样的3x3矩阵 print(j) [[-0.20783767, -0.12406401, -0.11775284], [ 0.02037018, 0.02898423, -0.02548213], [-0.0149878 , 0.05277648, 0.08332239]] 访问、删除、增加ndarray中的元素 这里主要是提供了一些访问、更改或增加ndarray中某一元素的基础方法。 访问&更改 类似于访问python list中元素的方式,按照元素的index进行访问或更改。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #访问某一元素,这里可以自己多尝试,摸索 print(np.arange(6)[3]) #访问一维数组的某一元素,中括号内填写index 3 print(np.arange(6).reshape(3,2)[1,1]) #访问二维数组的某一元素,中括号内填写[行,列] 3 print(np.arange(12).reshape(2,3,2)[0,1,1]) #访问三位数组中的某一元素,中括号内[组,行,列] 3 #更改某一元素,用 = 进行赋值和替换即可 a = np.arange(6) a[3] = 7 #先访问,再重新赋值 print(a) [0 1 2 7 4 5] 删除 可使用np.delete(ndarray, elements, axis)函数进行删除操作。 这里需要注意的是axis这个参数,课程中只讲到了2维数据中,axis = 0表示选择行,axis = 1表示选择列,但不能机械的认为0就表示行,1就表示列,注意前提2维数据中。 在三维数据中,axis = 0表示组,1表示行,2表示列。这是为什么呢?提示一下,三位数组的shape中组、行和列是怎样排序的? 所以,axis的赋值一定要考虑数组的shape。 1 2 a = np.arange(12).reshape(2,2,3) print(np.delete(a,[0],axis = 0)) #思考下,这里删除axis = 0下的第0个,会是什么结果呢?自己试一下 再有一点需要注意的是,如果你想让原数据保留删除后的结果,需要重新替换一下才可以。 1 2 3 4 5 6 7 8 9 10 11 a = np.arange(6).reshape(2,3) np.delete(a,[0],axis = 0) print(a) array([[0, 1, 2], [3, 4, 5]]) #原数据并未更改 a = np.delete(a,[0],axis = 0) #重新替换 print(a) array([[3, 4, 5]]) #原数据已更改 增加 往ndarray中增加元素的办法跟python list也很类似,常用的有两种: 一种是添加(append),就是将新增的元素添加到ndarray的尾部 语法为:np.append(ndarray, elements, axis) 参数和delete函数一致,用法也一致,这里不再赘述 一种是插入(insert),可以让新增元素插入到指定位置 语法为:np.insert(ndarray, index, elements, axis) 参数中就多了一个index,指示的是插入新元素的位置。 这里值得注意的是,不论是append还是insert,在往多维数组中插入元素时,一定要注意对应axis上的shape要一致。再一个就是,和delete一样,如果你想要更改原数据,需要用a = np.append(a,elements,axis)。 ndarray切片 前面学了选择ndarray中的某个元素的方法,这里我们学习选择ndarray子集的方法——切片。 对于切片大家并不陌生,在list里面我们也接触过切片,一维的ndarray切片与list无异。需要注意的是,就是理解2维及多维ndarray切片。 2维矩阵切片 1 2 3 4 5 6 7 8 9 10 11 12 13 a = np.arange(4*4).reshape(4,4) print(a) out: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15]]) a[:,:-1] out: array([[ 0, 1, 2], [ 4, 5, 6], [ 8, 9, 10], [12, 13, 14]]) 这里可以看出,我们筛选了a矩阵中前三列的所有行,这是如何实现的呢? 切片的第一个元素:表示的是选择所有行,第二个元素:-1表示的是从第0列至最后一列(不包含),所以结果如上所示。 再看一个例子: 1 2 3 4 a[1:3,:] out: array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) 筛选的是第2-3行的所有列。 一个常用的切片 以列的形式获取最后一列数据: 1 2 3 4 5 6 a[:,3:] out: array([[ 3], [ 7], [11], [15]]) 以一维数组的形式获取最后一列数据: 1 2 3 a[:,-1] out: array([ 3, 7, 11, 15]) 上面两种方法经常会用到,前者的shape为(4,1),后者为(4,)。 ndarray筛选 选择ndarray的对角线 所用函数为np.diag(ndarray, k=N),其中参数k的取值决定了按照哪一条对角线选择数据。 默认k = 0,取主对角线; k = 1时,取主对角线上面1行的元素; k = -1时,取主对角线下面1行的元素。 思考:这个函数只能选择主对角线上的元素,那如果想要获取副对角线上的元素呢? 尝试自己搜索一下关键词numpy opposite diagonal寻找答案。 不建议你直接点getting the opposite diagonal of a numpy array。 提取ndarray中的唯一值 所用函数为np.unique(ndarray),注意unique也可以添加参数axis来控制评判唯一值的轴方向,不好理解可以看示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 a = [[0,1,2], [3,4,5], [0,1,2]] print(np.unique(a)) #查看二维数组a中的唯一值 array([0, 1, 2, 3, 4, 5]) print(np.unique(a,axis = 0)) #查看a中的唯一行(也就是没有重复的行) array([[0, 1, 2], [3, 4, 5]]) print(np.unique(a,axis = 1)) #查看a中的唯一列 array([[0, 1, 2], [3, 4, 5], [0, 1, 2]]) print(np.unique(a[0])) #查看a中第一行的唯一值 array([0, 1, 2]) 通过布尔运算筛选 这里在中括号中添加筛选条件,当该条件的结果为True时(即满足条件时),返回该值。 1 X[X > 10] #筛选数组X中大于10的数据 这里需要注意的是,当输入多个筛选条件时,&表示与,|表示或,~表示非。 ndarray运算 集合运算 1 2 3 np.intersect1d(x,y) #取x与y的交集 np.setdiff1d(x,y) #取x与y的差集,返回的是在x中且没在y中的元素 np.union1d(x,y) #取x与y的并集 算术运算 我们可以通过+、-、*、/或np.add、np.substract、 np.multiply 、np.divide来对两个矩阵进行元素级的加减乘除运算,因为是元素级的运算,所以两个矩阵的shape必须要严格一致。 上面涉及到的乘法是元素对应相乘,也就是点乘,那矩阵的叉乘呢?可以了解下numpy.matmul函数。 这里需要注意的是,课程中讲的“可广播”,其实指的就是A和B两个矩阵shape可能不一致,但是A可以拆分为整数个与B具有相同shape的矩阵,这样在进行元素级别的运算时,就会先将A进行拆分,然后与B进行运算,结果再组合一起就可以。这里的A就是“可广播”矩阵。 ndarray排序 我们使用np.sort()和ndarray.sort()来对ndarray进行排序。 相同的是: 二者都可以使用参数axis来决定依照哪个轴进行排序,axis = 0时按照列排序,axis = 1时按照行排序; 不同的是: np.sort()不会更改原数组;ndarray.sort()会更改原数组。 numpy迷你项目 这里涉及到一个概念,叫做数据标准化。 数据的标准化(normalization)是将数据按比例缩放,使之落入一个小的特定区间。在某些比较和评价的指标处理中经常会用到,去除数据的单位限制,将其转化为无量纲的纯数值,便于不同单位或量级的指标能够进行比较和加权。 有很多种对数据进行标准化处理的方法,我们课程中选择的是利用数据均值和标准差进行标准化: 对某一列中某一值进行标准化就是将该值减去该列的平均值,然后除以该列的标准差。标准化后的序列,均值为0,标准差为1,且无量纲。 标准化后的数据,没有量纲,方便计算和比较,在机器学习中的很多算法都需要将数据进行标准化。 但是基于本章的要求,我们主要是学习numpy的基本操作即可,具体的数据标准化还有算法可以之后在机器学习课程中学习。 这里需要注意的是: np.random.permutation() np.random.permutation(N) 函数会创建一个从 0 到 N - 1的随机排列的整数集。这个整数集也是ndarray类型。 1 2 np.random.permutation(5) array([3, 1, 2, 4, 0]) 将数据集切分为训练集、测试集和交叉集。 这里的切分有两点隐形要求: 1.随机性,三个数据集中的数据必须是随机分配的; 2.三个数据集的合集必须为数据集。 考虑到上面学到的`np.random.permutation()` 函数,所以我们的思路可以是这样的:1. 使用`permutation()`函数,将数据集的行数当作N,这样就可以得到一个随机排列的行索引序列;2. 使用切片,将刚才的随机行索引序列,按照训练集、测试集和交叉集的比例`6:2:2`进行切分;3. 使用索引访问,获取切分后的数据,即`ndarray[index]`的方式。 Pandas Pandas简介 Pandas 是 Python 中的数据操纵和分析软件包,它是基于Numpy去开发的,所以Pandas的数据处理速度也很快,而且Numpy中的有些函数在Pandas中也能使用,方法也类似。 Pandas 为 Python 带来了两个新的数据结构,即 Pandas Series(可类比于表格中的某一列)和 Pandas DataFrame(可类比于表格)。借助这两个数据结构,我们能够轻松直观地处理带标签数据和关系数据。 Series中各个元素的数据类型可以不一致,DataFrame也是如此,这与numpy的ndarray不同。 创建Pandas Series 可以使用 pd.Series(data, index) 命令创建 Pandas Series,其中data表示输入数据, index 为对应数据的索引,除此之外,我们还可以添加参数dtype来设置该列的数据类型。 示例: 1 2 3 4 5 6 7 8 9 import pandas as pd pd.Series(data = [30, 6, 7, 5], index = ['eggs', 'apples', 'milk', 'bread'],dtype=float) out: eggs 30.0 apples 6.0 milk 7.0 bread 5.0 dtype: float64 data除了可以输入列表之外,还可以输入字典,或者是直接一个标量。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #data输入字典 pd.Series(data = {'eggs':30,'apples': 6, 'milk':7, 'bread':5},dtype=float) out: apples 6.0 bread 5.0 eggs 30.0 milk 7.0 dtype: float64 #data输入某一标量 pd.Series(data = 7, index = ['eggs', 'apples', 'milk', 'bread']) out: eggs 7 apples 7 milk 7 bread 7 dtype: int64 访问和删除Series中的元素 访问 访问Series中的元素有两种方法: 一种类似于从列表中按照索引访问数据,一种类似于从字典中按照key来访问value。 下面看示例: 从上面代码里也能发现,Pandas提供的iloc与loc分别对应着按索引访问和按key访问。 修改 因为Series是可更改类型,若想更改其中某一项,只需访问它然后重新赋值即可。 删除 可以使用 .drop() 方法删除 Pandas Series 中的条目。Series.drop(label) 方法会从给定 Series 中删除给定的 label。这个label可以是单个label或这是label组成的list。 但需要注意的是,.drop()函数并不会修改原来的数据,如果你想要修改原数据的话,可以选择添加参数inplace = True或者是用原数据替换s = s.drop(label) Series运算 和ndarray一样,Series也可以进行元素级的算术运算,也可以使用np中提供的各种运算函数,如sqrt()等等。 这里可以想一下,如果Series中包含字符串,然后再进行乘法会是什么结果? 可以回想下字符串的知识'*'*10的结果是什么? 创建DataFrame 我们使用pd.DataFrame(data, index, columns)来创建一个DataFrame。 其中: data是数据,可以输入ndarray,或者是字典(字典中可以包含Series或arrays或),或者是DataFrame; index是索引,输入列表,如果没有设置该参数,会默认以0开始往下计数; columns是列名,输入列表,如果没有设置该参数,会默认以0开始往右计数; 示例: 从上述代码中可以看出,字典d中的key被当作列名,value被当作dataframe中的数据。 思考:如果在上述代码中添加一个columns列,如df = pd.DataFrame(data=d,index = ['a','b'],columns = ['col_1','col_2']),会返回什么结果呢? 访问DataFrame中的元素 与访问Series中的元素类似,我们可以通过列表式索引访问,也可以通过字典式Key值访问。 创建一个DataFrame 访问某一行 访问多行 访问某一列 访问多列 使用df.iloc[:,0:2]这种方法只能筛选出连续的列,那如果想要筛选的列分别在1,3,5,10:17怎么办呢?可以搜一下np.r_的用法。 访问某一行列的元素 删除、增加元素 删除元素 我们使用.drop函数删除元素,默认为删除行,添加参数axis = 1来删除列。 值得注意的是,drop函数不会修改原数据,如果想直接对原数据进行修改的话,可以选择添加参数inplace = True或用原变量名重新赋值替换。 增加元素 这里介绍了两种方法,一种是append(),另外一种是insert(),这两种方法都比较简单,可类比于python list中的两种方法进行学习。 此外,Pandas还提供了其他更为复杂的做DataFrame融合的函数,比如说concat()、merge()、join()等等,相对难理解一些,我会单独出一份导学详细介绍这几个数据融合函数。 更改行列标签 使用函数rename()即可。具体用法如下: 除此之外,还可以使用隐匿函数lambda来对行列标签进行统一处理,比如: 需要注意的是,rename()函数同样不会更改原数据,如果想直接对原数据进行修改的话,可以选择添加参数inplace = True或用原变量名重新赋值替换。 更改索引 可以使用函数set_index(index_label),将数据集的index设置为index_label。 除此之外,还可以使用函数reset_index()重置数据集的index为0开始计数的数列。 缺失值(NaN)处理 NaN就是Not a Number的缩写,表示这里有数据缺失。 查找NaN 我们可以使用isnull()和notnull()函数来查看数据集中是否存在缺失数据,在该函数后面添加sum()函数来对缺失数量进行统计。除此之外,还可以使用count()函数对非NaN数据进行统计计数。 删除NaN 使用dropna(axis)函数可以删除包含NaN的行或列。 dropna()函数还有一个参数是how,当how = all时,只会删除全部数据都为NaN的列或行。 同样,该函数也不会修改原数据集。 替换NaN 使用fillna()函数可以替换NaN为某一值。其参数如下: value:用来替换NaN的值 method:常用有两种,一种是ffill前向填充,一种是backfill后向填充 axis:0为行,1为列 inplace:是否替换原数据,默认为False limit:接受int类型的输入,可以限定替换前多少个NaN 一般来说,我们常用均值去替换NaN。 还可以使用interpolate()函数按照某一方法来替换NaN,课程中介绍了method为linear时的用法,即忽略索引并将值视为相等间距,这是该函数的默认方法。更多method及解读请戳pandas.DataFrame.interpolate 在Pandas中处理数据 1 2 3 4 5 6 7 8 9 df = pd.read_csv(filename) #读取csv文件 df.info() #查看数据集信息 df.head() #查看前五行 df.tail() #查看后五行 df.sample() #查看随机一行 df.describe() #查看数据类型的基本统计信息 df.corr() #查看各列之间的相关系数 df.groupby() #将数据按照某一列进行聚类,后续接数据统计函数,如mean(),sum()等 项目内容 本首是Python项目的第2周,主要还是理解项目和准备项目文件,请大家做到以下几点: Project2/week1的项目要求:(应该已经做完) 完成/项目:探索美国共享单车数据/的1-3节内容 搭建本地anaconda环境(Python3版本)确保Spyder可以使用 下载bikeshare-new-2.zip项目文件。如果教室里面不能下载,请尝试下载下面的链接:https://github.com/mengfanchun2017/DAND-Basic/blob/master/Project1/Project1Files/bikeshare-new-2.zip Project2/week2的项目要求 (本周要求和,做完了画第二个勾勾) 用spyder打开项目文件浏览 了解项目文件中有几个函数,函数名和输入是什么(不用看明白和尝试做)

2018/12/12
articleCard.readMore

Anaconda&Jupyter Notebook配置

很多同学对Anaconda和Jupyter Notebook的安装与配置有疑惑,这里对课程中的选修:配置Anaconda和Jupyter Notebook作为一个补充。 Anaconda 安装 点击下载链接,先选择你的操作系统,然后选择Python 3.7 version版本下载。 安装过程中,记得这里的两个框,都勾选上。 常用软件 安装完Anaconda之后,Windows用户可以通过开始-所有程序找到Anaconda的文件夹,在文件夹下有三个程序是你经常会用到的,分别是: Anaconda Prompt:这里就是Anaconda的控制台,你进行第三方包的管理和编程环境的管理都是在这里进行。但是现阶段用不到。 Jupyter Notebook:使用非常非常频繁的web文档,在项目三和项目四中都会用到。 Spyder:python的IDE(集成开发环境),在项目二中会用到。 Jupter Notebook notebook的使用技巧在教室内说得很详细了,这里只补充一点,那就是如何在你工作的文件夹下使用notebook。 1. 进入到工作文件夹 2.按住Shift键,然后右击,选择“在此处打开命令窗口” 3.输入jupyter notebook,回车 4.notebook即会在你的默认浏览器中弹出,目录即为该路径下的文件 注意:不要关掉弹出notebook的命令窗口,这是将notebook与你电脑内的python链接的纽带。 Spyder 我们将会在项目二中用到Spyder这个软件,这个软件也没什么操作难度,所以课程内没有讲解。 我在这里给大家具体讲一下吧。 打开 Windows用户依次点击开始-所有程序-Anaconda-Spyder即可。 界面 如上,我们可以把Spyder的界面划分为5个部分,分别为: 菜单栏:就是一些新建、打开、运行、终止等等操作,自行摸索 选择工作区:这里可以选择工作区路径 代码编辑区:这里就是你写代码的地方 程序变量/文件路径查看区:通过选择箭头标注的选项卡,可以显示代码中的变量,或者是当前路径下的文件 控制台:这里就是显示你代码运行结果的地方,如果代码运行卡住了,可以通过点该区域右上角的■终止运行。 使用流程 先确定工作路径,然后新建脚本,开始编写代码、运行(快捷键F5)、调试。 做完项目二,大家就能熟练操作啦,不要担心~

2018/12/2
articleCard.readMore

Python Code of Mini-Batch Gradient Descent

概述 Mini-Batch Gradient Descent是介于batch gradient descent(BGD)和stochastic gradient descent(SGD)之间的一种线性回归优化算法,它是将数据分为多个小的数据集(batches),每个数据集具有大致相同的点数,然后在每个数据集中应用Absolute Trick或者是Square Trick算法,来更新回归系数。 它的运算速度比BSD快,比SGD慢;精度比BSD低,比SGD高。 代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 import numpy as np import matplotlib.pyplot as plt np.random.seed(42) def MSEStep(X, y, W, b, learn_rate = 0.001): """ This function implements the gradient descent step for squared error as a performance metric. Parameters X : array of predictor features y : array of outcome values W : predictor feature coefficients b : regression function intercept learn_rate : learning rate Returns W_new : predictor feature coefficients following gradient descent step b_new : intercept following gradient descent step """ # compute errors # the squared trick formula y_pred = np.matmul(X, W) + b #Attention:the order of X and W error = y - y_pred #y_pred is a 1-D array,so is the error # compute steps W_new = W + learn_rate * np.matmul(error, X) #Attention:the order of X and error b_new = b + learn_rate * error.sum() return (W_new, b_new) def miniBatchGD(X, y, batch_size = 20, learn_rate = 0.005, num_iter = 25): """ This function performs mini-batch gradient descent on a given dataset. Parameters X : array of predictor features y : array of outcome values batch_size : how many data points will be sampled for each iteration learn_rate : learning rate num_iter : number of batches used Returns regression_coef : array of slopes and intercepts generated by gradient descent procedure """ n_points = X.shape[0] W = np.zeros(X.shape[1]) # coefficients b = 0 # intercept # run iterations #hstack为水平堆叠函数 为什么要堆叠呢? #类似zip,可以实现for W,b in regression_coef:print W,b来提取W和b regression_coef = [np.hstack((W,b))] for _ in range(num_iter): #从0-100中随机选择batch_size个数,作为batch batch = np.random.choice(range(n_points), batch_size) #按照batch从X中选出数据 X_batch = X[batch,:]#为2-D矩阵 y_batch = y[batch]#为1-D数组 W, b = MSEStep(X_batch, y_batch, W, b, learn_rate) regression_coef.append(np.hstack((W,b))) return (regression_coef) if __name__ == "__main__": # perform gradient descent data = np.loadtxt('data.csv', delimiter = ',') X = data[:,:-1]#提取第一列,为2-D矩阵 y = data[:,-1]#提取第二列,为1-D数组 regression_coef = miniBatchGD(X, y) # plot the results plt.figure() X_min = X.min() X_max = X.max() counter = len(regression_coef) for W, b in regression_coef: counter -= 1 #color为[R,G,B]的列表,范围都在0-1之间,[0,0,0]为黑色,[1,1,1]为白色 color = [1 - 0.92 ** counter for _ in range(3)] #绘制一条点(X_min,X_min * W + b)与点(X_max, X_max * W + b)之间的一条直线 plt.plot([X_min, X_max],[X_min * W + b, X_max * W + b], color = color) plt.scatter(X, y, zorder = 3) plt.show() 结果 在结果中,颜色最浅的是最开始的回归线,最深的则为最终的回归线。 详解 理论知识参见Linear Regression 总结,这里只对代码中出现的新函数或新用法进行讲解。 numpy.matmul(a,b) 该函数用来计算两个arrays的乘积。 需要注意的是,由于a和b维度的不同,会使得函数的结果计算方式不同,一共三种: 如果a和b都是2维的,则做普通矩阵乘法 1 2 3 a = [[1, 0], [0, 1]] b = [[4, 1], [2, 2]] np.matmul(a, b) 1 2 3 out: array([[4, 1], [2, 2]]) 如果a和b中有一个是大于2维的,则会将其理解为多个矩阵stack后的结果,进行计算时也会进行相应的拆分运算 1 2 3 a = np.arange(2*2*4).reshape((2,2,4)) b = np.arange(2*2*4).reshape((2,4,2)) np.matmul(a,b).shape 1 2 out: (2, 2, 2) a被理解为2个2x4矩阵的stack 1 2 3 4 5 array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7]], [[ 8, 9, 10, 11], [12, 13, 14, 15]]]) b被理解为2个4x2矩阵的stack 1 2 3 4 5 6 7 8 9 array([[[ 0, 1], [ 2, 3], [ 4, 5], [ 6, 7]], [[ 8, 9], [10, 11], [12, 13], [14, 15]]]) np.matmul(a,b)会将a中的两个矩阵与b中的两个矩阵对应相乘,每对相乘的结果都是一个2x2的矩阵,所以结果就是一个2x2x2的矩阵。 如果a或b有一个是一维的,那么就会为该一维数组补充1列或1行,进而提升为二维矩阵,然后用非补充行或列去和另外一个二维矩阵进行运算,得到的结果再将补充的1去掉。(这个是最难理解的,可以多测试下,用代码结果理解) 1 2 3 a = [[1, 0], [0, 1]] b = [1, 2] np.matmul(a, b) 1 2 out: array([1, 2]) a是一个2x2的矩阵,b是一个shape为(2,)的一维数组,那么matmul的计算步骤如下: 计算中,矩阵a在前,数组b在后,所以需要让a的列数与升维之后b矩阵的行数相等 所以,升维后b矩阵的shape应为(2,1),这个1添加到了列上 进行矩阵乘法计算,得到shape为(2,1),这时候再将这个1去掉 最终结果的shape为(2,),变为一维数组 我们试着将a与b的顺序对调,看一下matmul是怎么计算的: 对调后,数组b在前,矩阵a在后,需要将升维后b矩阵的列数与矩阵a的行数相等 所以,升维后b矩阵的shape应该为(1,2),这个1添加到了行上 进行矩阵乘法,得到的shape为(1,2),将这个1去掉 最终结果的shape为(2,),变为一维数组 numpy.hstack() 我们先来看看numpy.stack()函数。 函数用法为:numpy.stack(arrays,axis = 0) 第一个参数为arrays,可以输入多维数组或者列表,也可以输入由多个一维数组或列表组成的元组 第二个参数为axis,输入数字,决定了按照arrays的哪个维度进行stack。比如说,输入的arrays的shape为(3,4,3),那么axis = 0/1/2就分别对应arrays的组/行/列。 这个函数中的axis有些抽象,我们看具体示例: 定义了一个列表 结果的排版有点问题,为了方便后面对照,把结果对齐如下: 1 2 3 4 5 [ array([[0,1,2],[3,4,5]]), array([[0,1,2],[3,4,5]]), array([[0,1,2],[3,4,5]]) ] axis = 0,则按照第0个维度组进行堆叠,即: 结果为: axis = 1,则按照第1个维度行进行堆叠,即: 结果为: axis = 2,则按照第二个维度列进行堆叠,即: 结果为: 这个基本很少用到。 **numpy.hstack()**函数就是horizontal(水平)方向的堆叠,示例: **numpy.vstack()**函数就是在垂直方向堆叠。 ndarray的切片 一维ndarray的切片方式和list无异,这里主要讲一下二维矩阵的切片方法。 矩阵切片 1 2 a = np.arange(4*4).reshape(4,4) print(a) 1 2 3 4 5 out: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15]]) 1 a[:,:-1] 1 2 3 4 5 out: array([[ 0, 1, 2], [ 4, 5, 6], [ 8, 9, 10], [12, 13, 14]]) 这里可以看出,我们筛选了a矩阵中前三列的所有行,这是如何实现的呢? 切片的第一个元素:表示的是选择所有行,第二个元素:-1表示的是从第0列至最后一列(不包含),所以结果如上所示。 再看一个例子: 1 a[1:3,:] 1 2 3 out: array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) 筛选的是第2-3行的所有列。 一个常用的切片 以列的形式获取最后一列数据: 1 a[:,3:] 1 2 3 4 5 out: array([[ 3], [ 7], [11], [15]]) 以一维数组的形式获取最后一列数据: 1 a[:,-1] 1 2 out: array([ 3, 7, 11, 15]) 上面两种方法经常会用到,前者的shape为(4,1),后者为(4,)。 matplotlib相关 color 代码中涉及到的语句为: 1 color = [1 - 0.92 ** counter for _ in range(3)] matplotlib中的color可以输入RGB格式,即[R,G,B],这里值得注意的是它们的取值范围都在0到1之间,其中[0,0,0]为黑色,[1,1,1]为白色。 在如上语句中,列表由三个相等的数值元素组成,保证了颜色为白-灰-黑,数值随着counter的减小,由1趋近于0,反映在可视化上就是颜色由白逐渐变黑。 这真是一个画渐变过程的好方法呀!!! plot([x_1,x_2],[y_1,y_2]) 这里就是两点式绘图,根据点(x_1,y_1)和点(x_2,y_2)画一条直线。 zorder 也就是z-order,类似于PS里面的图层顺序,下面的图层会被上面的图层遮挡。 参考Zorder Demo中队zorder的介绍,可以知道,zorder越大,图层越靠上,所以在上面的代码中,我们在scatter中设定zorder为3,也就是最上层,这样就可以保证渐变的回归线不会压在散点图上面了。

2018/12/2
articleCard.readMore

SQL应知应会

If you want your life to be a magnificent story, then begin by realising that you are the author. 本文就Udacity数据分析入门课程中的SQL入门(P1阶段)和SQL进阶(P3阶段)的知识点进行总结。SQL的主要功能不外乎增、删、改、查四个,对于数据分析师来说,只需要掌握查就可以了。(因为增删改往往超出了数据分析师的职能范围) 注意:本文是总结性质的,只能提供复习或者速查的功能,讲解得不会很详细,若想学习,还是要在教室内逐章学习。 SQL简介 SQL是Structured Query Language的简写,也就是结构化查询语言。SQL 最受欢迎的功能是与数据库交互。 使用传统关系数据库与 SQL 交互有一些主要优点。最明显的 5 个优点是: SQL 很容易理解。 传统的数据库允许我们直接访问数据。 传统的数据库可使我们审核和复制数据。 SQL 是一个可一次分析多个表的很好工具。 相对于 Google Analytics 等仪表板工具,SQL 可使我们分析更复杂的问题。 为什么企业喜欢使用数据库 只有输入了需要输入的数据,以及只有某些用户能够将数据输入数据库,才能保证数据的完整性。 可以快速访问数据 - SQL 可使我们从数据库中快速获取结果。 可以优化代码,快速获取结果。 可以很容易共享数据 - 多个人可以访问存储在数据库中的数据,所有访问数据库的用户获得的数据都是一样。 SQL 与 NoSQL 你可能听说过 NoSQL,它表示 Not only SQL(不仅仅是 SQL)。使用 NoSQL 的数据库时,你编写的数据交互代码会与本节课所介绍的方式有所不同。NoSQL 更适用于基于网络数据的环境,而不太适用于我们现在要介绍的基于电子表格的数据分析。最常用的 NoSQL 语言之一是 MongoDB。 SQL入门 SQL书写规则 SQL语句不区分大小写,因此SELECT与select甚至是SeLect的效果是相同的,但是要对命令和变量进行区分,所以默认命令需要大写,其他内容如变量等则需要小写; 表和变量名中不要出现空格,可使用下划线_替代。 查询语句中,使用单一空格隔开命令和变量 为提高代码的可移植性,请在查询语句结尾添加一个分号; SQL中的注释 行内注释 使用两个连字符-,添加注释。 1 2 SELECT col_name -- 这是一条注释 FROM table_name; 多行注释 多行注释以/*起始,以*/结尾。 1 2 3 4 /*SELECT col_name FROM table_name;*/ SELECT col_2 FROM table_name; 检索数据(SELECT FROM LIMIT ) 检索数据主要用的语句为:SELECT。 检索单列 1 2 SELECT col_name FROM table_name; 从table_name表中检索col_name列。 检索多列 1 2 SELECT col_1,col_2,col_3 FROM table_name; 从table_name表中检索col_1,col_2和col_3列。 检索所有列 1 2 SELECT * FROM table_name; 使用通配符*,返回table_name表中的所有列; 检索某列中不同的值 1 2 SELECT DISTINCT col_1 FROM table_name; 检索col_1中具有唯一性的行,即唯一值。 限制检索的结果 使用LIMIT语句可以限制返回的行数。 1 2 3 SELECT col_1 FROM table_name LIMIT 10; 返回前10行(即第0-第9行)。 也可以添加OFFSET语句,设置返回数据的起始行: 1 2 3 SELECT col_1 FROM table_name LIMIT 10 OFFSET 5; 从第五行之后,返回十行数据(即第5-第14行)。 排序检索数据(ORDER BY) ORDER BY 语句用于根据指定的单列或多列对结果集进行排序。 ORDER BY 语句默认按照升序对记录进行排序。(从小到大,从a到z) 如果您希望按照降序对记录进行排序,可以使用 DESC 关键字。 在指定一条ORDER BY子句时,应该保证它是SELECT语句中的最后一条子句。 按列排序 1 2 3 SELECT col_name FROM table_name ORDER BY col_name; 返回的数据会按照col_name列进行升序排序,这里col_name可以是单列也可以是多列,当然也可以使用非检索的列进行排序。 降序排序 1 2 3 SELECT col_1,col_2 FROM table_name ORDER BY col_2 DESC,col_3; 返回的数据会按照col_2列降序,col_3列升序对col_1和col_2两列进行排序。 这里可以看出,DESC关键字的用法:只对跟在语句前面的变量有效。所以,想要对多列进行降序排序时,需要对每一列都指定DESC关键字。 过滤数据(WHERE) WHERE子句应该在表名(即FROM子句)之后给出。 WHERE子句应在ORDER BY子句之前。 在过滤条件中的value是区分大小写的。 使用方法 1 2 3 SELECT col_1 FROM table_1 WHERE col_1 运算符 value; 运算符 运算符描述 =等于 <>不等于 >大于 <小于 >=大于等于 <=小于等于 BETWEEN…AND…在指定的两值之间 IS NULL为NULL值 AND逻辑运算符:与 OR逻辑运算符:或 IN制定条件范围筛选,可以简化OR的工作 NOT逻辑运算符:非 注意: SQL的版本不同,可能导致某些运算符不同(如不等于可以用!=表示),具体要查阅数据库文档。 在同时输入AND和OR时,SQL会优先处理AND语句,你可以使用小括号来进行分组操作。 用通配符进行过滤(LIKE) 通配符是用来匹配值的一部分的特殊字符,跟在LIKE关键字后面进行数据过滤 通配符描述 %表示任何字符出现任意次数 _表示任何字符出现一次 []指定一个字符集,它必须匹配该位置的一个字符 ^在[]中使用,表示否定 示例: 1 2 3 4 SELECT col_1 FROM table_1 WHERE col_1 LIKE '_[^JM]%' ORDER BY col_1; 如上筛选出的是,第二个字符为非J或M的数据。 创建计算字段 其实就是在检索数据的同时进行计算,并使用关键字AS将结果保存为某一列。 数值类型的计算 1 2 3 SELECT prod_id,quantity,item_price,quantity*item_price AS expanded_price FROM orderitems WHERE order_num = 200008; 输出: 1 2 3 4 prod_id quantity item_price expanded_price -------------------------------------------------------------- RGAN0154.990024.9500 BR03511.990059.9500 这里实现的就是使用quantity*item_price创建一个名为expanded_price的计算字段,也就是一个新列。 同样适用于计算的操作符有+(加),-(减)和/(除)。 字符类型的拼接 1 2 3 SELECT RTRIM(col_name) + '('+RTRIM(col_country)+')' AS col_title FROM table_name ORDER BY col_name; 输出: 1 2 3 4 5 col_title ------------------------ Bear Emporium(USA) Bears R Us(USA) Jouets et ours(France) 这里实现的就是将col_name列与col_country列进行了拼接,新列的名字叫做col_title。 RTRIM()函数是去掉右边的所有空格,LTRIM()是去掉左边的所有空格,TRIM()是去掉两边的所有空格。 使用别名 在上一节中我们使用AS来为变量设置别名,你可能也见过如下所示的语句: 1 SELECT col1 + col2 AS total, col3 当然没有 AS 的语句也可以实现使用别名: 1 FROM tablename t1 以及 1 SELECT col1 + col2 total, col3 将col1+col2的结果设置名为total的列。 代码总结 语句使用方法其他详细信息 SELECTSELECT Col1, Col2, …提供你需要的列 FROMFROM Table提供列所在的表格 LIMITLIMIT 10限制返回的行数 ORDER BYORDER BY Col根据列命令表格。与 DESC 一起使用。 WHEREWHERE Col > 5用于过滤结果的一个条件语句 LIKEWHERE Col LIKE ‘%me%’仅提取出列文本中具有 ‘me’ 的行 INWHERE Col IN (‘Y’, ‘N’)仅过滤行对应的列为 ‘Y’ 或 ‘N’ NOTWHERE Col NOT IN (‘Y’, “N’)NOT 经常与 LIKE 和 IN 一起使用。 ANDWHERE Col1 > 5 AND Col2 < 3过滤两个或多个条件必须为真的行 ORWHERE Col1 > 5 OR Col2 < 3过滤一个条件必须为真的行 BETWEENWHERE Col BETWEEN 3 AND 5一般情况下,语法比使用 AND 简单一些 SQL进阶 链接表 基本链接(JOIN) SQL最强大的功能之一就是能在数据查询的执行中进行表的链接(JOIN)。 在关系数据库中,将数据分解为多个表能更有效地存储,更方便地处理,但这些数据储存在多个表中,怎样用一条SELECT语句就检索出数据呢?那就要使用链接。 创建链接的方式很简单,如下便是使用WHERE创建链接: 1 2 3 SELECT col_1,col_2,col_3 FROM table_1,table_2 WHERE table_1.id = table2.id; 如上,col_1和col_2属于table_1表中,col_3属于table_2表中,而这两个表使用相同的id列进行匹配。这种方法被称为等值链接,也就是内链接,我们可以使用如下的语句,更直观地实现内连接: 1 2 3 SELECT col_1,col_2,col_3 FROM table_1 INNER JOIN table_2 ON table_1.id = table2.id; 当然你也可以使用别名,简化输入,并且标明各列与表的隶属关系: 1 2 3 SELECT t1.col_1,t1.col_2,t2.col_3 FROM table_1 t1 INNER JOIN table_2 t2 ON t1.id = t2.id; 如上代码同样适用于左链接、右链接和外链接: LEFT JOIN - 用于获取 FROM 中的表格中的所有行,即使它们不存在于 JOIN 语句中。 RIGHT JOIN - 用于获取 JOIN 中的表格中的所有行,即使它们不存在于 FROM 语句中。 FULL JOIN: 只要其中一个表中存在匹配,就返回行。 自链接 自链接经常用于对子查询的简化,如下示例: 假如要给Jim同一公司的所有顾客发送一封邮件,需要你先筛选出Jim的公司,然后再根据该公司筛选出所有的顾客。使用子查询的方式如下: 1 2 3 4 5 SELECT cust_id,cust_name,cust_contact FROM customers WHERE cust_name = (SELECT cust_name FROM customers WHERE cust_contact = 'Jim') 如果改为自链接的方式如下: 1 2 3 4 SELECT c1.cust_id,c1.cust_name,c1.cust_contact FROM customers c1,customers c2 WHERE c1.cust_name = c2.cust_name AND c2.cust_name = 'Jim'; 结果是一样的,但是使用自链接的处理速度比子查询要快得多。 组合查询(UNION) UNION 操作符用于合并两个或多个 SELECT 语句的结果集,使用方法也很简单,只要在多条SELECT语句中添加UNION关键字即可。 多数情况下,组合相同表的多个查询所完成的任务与具有多个WHERE子句的一个查询是一样的。 注意:UNION 内部的 SELECT 语句必须拥有相同数量的列,列也必须拥有相似的数据类型。而且UNION返回的结果只会选取不同的值(即唯一值)。 使用UNION的场合情况: 在一个查询中从不同的表返回结果; 对一个表执行多个查询返回结果。 示例:如下三个语句的结果是一致的。 原始语句 1 2 3 4 5 6 7 8 9 -- 查询一 SELECT cust_name,cust_email FROM customers WHERE cust_state IN ('str1','str2'); --查询二 SELECT cust_name,cust_email FROM customers WHERE cust_name = 'str3'; 使用UNION链接 1 2 3 4 5 6 7 8 SELECT cust_name,cust_email FROM customers WHERE cust_state IN ('str1','str2') UNION SELECT cust_name,cust_email FROM customers WHERE cust_name = 'str3' ORDER BY cust_name; 在最后添加了ORDER BY对所有SELECT语句进行排序,这里只是为了示例在使用UNION时如何进行排序。 使用WHERE 1 2 3 4 SELECT cust_name,cust_email FROM customers WHERE cust_state IN ('str1','str2') OR cust_name = 'str3'; 这里看起来使用UNION比WHERE更复杂,但对于较复杂的筛选条件,或者从多个表中检索数据时,使用UNION更简单一些。 UNION ALL 命令和 UNION 命令几乎是等效的,不过 UNION ALL 命令会列出所有的值。 SQL聚合 有时候我们只是需要获取数据的汇总信息,比如说行数啊、平均值啊这种,并不需要吧所有数据都检索出来,为此,SQL提供了专门的函数,这也是SQL最强大功能之一。 聚合函数 SQL的聚合函数如下所示: 函数说明 AVG()返回某列的均值 COUNT()返回某列的行数 MAX()返回某列的最大值 MIN()返回某列的最小值 SUM()返回某列的和 使用示例: 1 2 SELECT AVG(col_1) AS avg_col_1 FROM table_1; 注意:聚合函数都会忽略列中的NULL值,但是COUNT(*)也就是统计全部数据的行数时,不会忽略NULL值。 聚合不同值 当添加DISTINCT参数时,就可以只对不同值(也就是某列中的唯一值)进行函数操作。 使用示例: 1 2 SELECT AVG(DISTINCT col_1) AS avg_col_1 FROM table_1; 数据分组 创建分组(GROUP BY) 前面的函数操作都是基于整个表去进行的,那如果想要依据某列中的不同类别(比如说不同品牌 不同性别等等)进行分类统计时,就要用到数据分组,在SQL中数据分组是使用GROUP BY子句建立的。 在使用GROUP BY时需要注意的几点: GROUP BY子句可以包含任意数量的列,因而可以对分组进行多重嵌套,类似于Pandas中的多重索引; GROUP BY子句必须出现在WHERE子句之后,ORDER BY之前。 使用示例: 1 2 3 SELECT col_1,COUNT(*) AS num_col FROM table_1 GROUP BY col_1; 以上即可实现按col_1列中的不同类目进行行数统计。 过滤分组(HAVING) 在SQL入门中我们学过WHERE,它是对行数据进行筛选过滤的,那么,如果我想对创建的分组数据进行筛选过滤呢?这时候,你就要用到HAVING子句了,它与WHERE的操作符一致,只是换了关键字而已。 使用示例: 1 2 3 4 SELECT col_1,COUNT(*) AS num_col FROM table_1 GROUP BY col_1 HAVING COUNT(*) >= 2; 这里我们就筛选出了具有两个以上类别的分组。 注意:使用HAVING时应该结合GROUP BY子句。 时间序列的处理(DATE) 在SQL中有一套专门的内置函数,用来处理时间序列,那就是DATE函数。 SQL Date 数据类型 先了解一下在不同的数据库中的时间序列的表示。(了解即可) MySQL 使用下列数据类型在数据库中存储日期或日期/时间值: DATE - 格式:YYYY-MM-DD DATETIME - 格式:YYYY-MM-DD HH:MM:SS TIMESTAMP - 格式:YYYY-MM-DD HH:MM:SS YEAR - 格式:YYYY 或 YY SQL Server 使用下列数据类型在数据库中存储日期或日期/时间值: DATE - 格式:YYYY-MM-DD DATETIME - 格式:YYYY-MM-DD HH:MM:SS SMALLDATETIME - 格式:YYYY-MM-DD HH:MM:SS TIMESTAMP - 格式:唯一的数字 DATE_TRUNC函数 DATE_TRUNC 使你能够将日期截取到日期时间列的特定部分。常见的截取依据包括日期、月份 和 年份。 语法: 1 DATE_TRUNC('datepart', timestamp) 其中datepart即为你的截取依据,后面的timestamp类型可以参考上面的Date数据类型。 我总结了一份SQL的datepart速查表放在了下面。 使用示例: 1 2 3 4 5 SELECT DATE_TRUNC('y',col_date) col_year FROM table_1 GROUP BY 1 ORDER BY 1 DESC LIMIT 10; 如上,我们将col_date列按照年(’y’)进行了分组,并按由大至小的顺序排序,取前10组数据。 DATE_PART函数 DATE_PART 可以用来获取日期的特定部分,如获取日期2018-10-6的月份,只会获得一个结果6,这是它与DATE_TRUNC的最大区别。 语法: 1 DATE_PART ('datepart', date或timestamp) 其中datepart即为你的截取依据,后面的timestamp类型可以参考上面的Date数据类型。 使用示例: 1 2 3 SELECT DATE_PART('y',col_date) col_year FROM table_1 GROUP BY 1; 如上,我们筛选了col_date列的年份,并依据它做了分组。 想了解更多DATE函数,可以戳SQL日期和时间函数参考 datepart总结 如下给了很多的缩写,只记住最简单的即可。 日期部分或时间部分缩写 世纪c、cent、cents 十年dec、decs 年y、yr、yrs 季度qtr、qtrs 月mon、mons 周w,与 DATE_TRUNC一起使用时将返回离时间戳最近的一个星期一的日期。 一周中的日 ( DATE_PART支持)dayofweek、dow、dw、weekday 返回 0–6 的整数(星期日是0,星期六是6)。 一年中的日 ( DATE_PART支持)dayofyear、doy、dy、yearday 日d 小时h、hr、hrs 分钟m、min、mins 秒s、sec、secs 毫秒ms、msec、msecs、msecond、mseconds、millisec、millisecs、millisecon CASE语句 CASE语句其实就相当于python中的if语句,是用来做条件的。 需要注意的几点: CASE 语句始终位于 SELECT 条件中。 CASE 必须包含以下几个部分:WHEN、THEN 和 END。ELSE 是可选组成部分,用来包含不符合上述任一 CASE 条件的情况。 你可以在 WHEN 和 THEN 之间使用任何条件运算符编写任何条件语句(例如 WHERE),包括使用 AND 和 OR 连接多个条件语句。 你可以再次包含多个 WHEN 语句以及 ELSE 语句,以便处理任何未处理的条件。 使用示例: 1 2 3 4 SELECT account_id, CASE WHEN standard_qty = 0 OR standard_qty IS NULL THEN 0 ELSE standard_amt_usd/standard_qty END AS unit_price FROM orders LIMIT 10; 如上,我们使用CASE WHEN.(条件一).THEN.(条件一的结果).ELSE.(其他不符合条件一的结果).END语句,设立的两个条件,即当standard_qty为0或者不存在时我们返回0,当standard_qty不为0时进行计算,并储存为新列unit_price。 子查询与临时表格 我们之前所涉及到的都是从数据库表中检索数据的单条语句,但当我们想要检索的数据并不能直接从数据库表中获取,而是需要从筛选后的表格中再度去查询时,就要用到子查询和临时表格了。 子查询与临时表格所完成的任务是一致的,只不过子查询是通过嵌套查询完成,而另一种是通过WITH创建临时表格进行查询。 构建子查询 构建子查询十分简单,只需将被查询的语句放在小括号里,进行嵌套即可,但在使用时一定要注意格式要清晰。 使用示例: 1 2 3 4 5 6 7 SELECT * FROM (SELECT DATE_TRUNC('day',occurred_at) AS day,channel, COUNT(*) AS events FROM web_events GROUP BY 1,2 ORDER BY 3 DESC) sub GROUP BY channel ORDER BY 2 DESC; 如上,我们创建了一个子查询,放在小括号里,并将其命名为sub。在子查询中也注意到了各个子句上下对齐,这样条例更清晰。 临时表格(WITH) 这种方法,就是使用WITH将子查询的部分创建为一个临时表格,然后再进行查询即可。 我们还是使用上面子查询的例子,这次用临时表格的形式实现: 1 2 3 4 5 6 7 8 9 10 WITH sub AS( SELECT DATE_TRUNC('day',occurred_at) AS day,channel, COUNT(*) AS events FROM web_events GROUP BY 1,2 ORDER BY 3 DESC) SELECT * FROM sub GROUP BY channel ORDER BY 2 DESC; 如上,我们将被嵌套的子查询单独拎出来,用WITH创建了一个临时表格,再之后又使用SELECT根据该表格进行查询。 SQL数据清理 这一节主要针对数据清理讲解了几个SQL中的常用函数,一般来说,也都是用在筛选阶段,更详尽的数据清理还是要放在python中去进行。 字符串函数 LEFT、RIGHT、LENGTH LEFT和RIGHT相当于是字符串截取,LEFT 是从左侧起点开始,从特定列中的每行获取一定数量的字符,而RIGHT是从右侧。 LENGTH就是获取字符串的长度,相当于python中的len()。 语法: 1 2 3 LEFT(phone_number, 3) -- 返回从左侧数,前三个字符 RIGHT(phone_number, 8) LENGTH(phone_number) POSITION、STRPOS、SUBSTR 这三个函数都是与位置相关的函数。 POSITION 和STRPOS 可以获取某一字符在字符串中的位置,这个位置是从左开始计数,最左侧第一个字符位置为1,但他俩的语法稍有不同。 SUBSTR可以筛选出指定位置后指定数量的字符。 语法: 1 2 3 POSITION(',' IN city_state) STRPOS(city_state, ‘,’) --跟上面的语句等价 SUBSTR(city_state,4,5) -- 返回city_state字符串中,以第4个字符开头的5个字符。 字符串拼接(CONCAT) 顾名思义,就是将两个字符串进行拼接。 语法: 1 2 3 CONCAT(first_name, ' ', last_name) -- 结果为:first_name last_name --或者你也可以使用双竖线来实现上述任务 first_name || ' ' || last_name 更改数据格式 TO_DATE函数 TO_DATE函数可以将某列转为DATE格式,主要是将单独的月份或者年份等等转换为SQL可以读懂的DATE类型数据。 语法: 1 2 TO_DATE(col_name,'datepart') TO_DATE('02 Oct 2001', 'DD Mon YYYY'); 这里是将col_name这列按照datepart转化为DATE类型的数据,datepart可以参考之前的总结。 CAST函数 CAST函数是SQL中进行数据类型转换的函数,但经常用于将字符串类型转换为时间类型。 语法: 1 2 3 CAST(date_column AS DATE) -- 你也可以写成这样 date_column::DATE 这里是将date_column转换为DATE格式的数据,其他时间相关的数据类型与样式对照可以参考上面写过的SQL Date数据类型,确保你想转换的数据样式与数据类型对应。 缺失值的处理 之前有提到过如何筛选出缺失值,即使用WHERE加上IS NULL或者IS NOT NULL。 那么如何对缺失值进行处理呢?(其实这里可以直接无视,筛选出来后在python中再进行处理) SQL中提供了一个替换NULL值的函数COALESCE。 使用示例: 1 2 COALESCE(col_1,0) -- 将col_1中的NULL值替换为0 COALESCE(col_2,'no DATA') -- 将col_2中的NULL值替换为no DATA 总结 好啦,至此课程中的所有SQL知识点已经总结完了,并且也给大家做了适当的补充,希望大家能够用得上。未来的数据分析师之路,还要继续加油呀! 附:SELECT子句顺序 下表中列出了全文中涉及到的子句,在进行使用时,应严格遵循下表中从上至下的顺序。 子句说明是否必须使用 SELECT要返回的列或表达式是 FROM用于检索数据的表仅在从表中选择数据时使用 JOIN…ON…用于链接表仅在需要链接表时使用 WHERE过滤行数据否 GROUP BY分组数据仅在按组计算时使用 HAVING过滤分组否 ORDER BY对输出进行排序否 LIMIT限制输出的行数否

2018/10/6
articleCard.readMore

每周导学-第十二周-项目四

Better together . —— Udacity Hi,同学们,经过前两周的学习,我们掌握了描述统计学基础、概率论基础、推论统计学中的置信区间、假设检验以及机器学习入门知识——回归,本章的内容偏理论性更多一些,需要更多得去实操来加强自己的理解能力,这周呢我们就来个实打实的项目来检验前两周的所学。项目为分析A/B测试结果,在开始项目前,请一定要把前面的几个小测试做了,这样做项目更好上手一些。大家加油!通过这个项目,就可以拿到入门的毕业证啦!!! 项目四(P4)阶段总共包含三周,在这三周内,我们要对统计学进行学习,掌握基础的描述统计学理论、基本的概率知识、二项分布和贝叶斯公式,并学会使用 Python 来实践;学习正态分布、抽样分布、置信区间以及假设检验的概念和计算方式;学习线性回归以及逻辑回归,在真实场景中应用,比如分析 A/B 测试结果,搭建简单的监督机器学习模型。可谓是时间紧任务重,但是也别怕,统计学的基础知识还是非常简单的,跟着课程内容一步步来,自己多做笔记多查资料,一定没问题的! 那么我们的课程安排: 时间学习重点对应课程 第1周统计学基础描述统计学 - 抽样分布与中心极限定理 第2周统计学进阶置信区间 - 逻辑回归 第3周完成项目项目:分析A/B测试结果 本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决: 先自行查找问题答案(注意提取关键词),参考:谷歌/必应搜索、CSDN、stackoverflow 额外参考资料: 可汗学院概率论与统计课程 机会的数学-陈希孺 条件概率及全概率公式及贝叶斯公式 statistics for data science 若问题未解决,请将问题及其所在课程章节发送至微信群,并@助教即可 饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧! 注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索! 本周目标 完成并通过项目四! 学习计划 时间学习资源学习内容 周二微信群 - 每周导学预览每周导学 周三、周四Udacity - Classroom项目四 周五微信/Classin - 1V1课程难点 周六Classin - 优达日本周学习总结、答疑 周日笔记本总结沉淀 周一自主学习查漏补缺 项目指南 项目详情 数据分析师和数据学家经常使用 A/B 测试。在这个项目中,你将会理解电子商务网站运营 A/B 测试的结果。你的目标是通过课程中给的Jupyter Notebook,帮助公司理解他们是否应该设计新页面、保留原有网页或延长测试时间以便做出决定。 项目前面的几个小测试,需要大家针对项目提供的数据进行操作并回答,你可以打开两个网页,也可以在本地进行操作。 当然还是建议大家下载到本地进行操作,如果文件下载失败,请微信联系我。 关于A/B-test: AB 测试就是为了验证在先验条件的存在的情况下,进行新的变更是否合理和可行以达到优化的目的。使用 AB 测试的方式能能够度量变更对某些指标的变化,是变更更具有合理性依据更充分。 AB 测试也存在 不适用的场景:1)对没有明确参照的试验,AB 测试是基于先验条件的优化,如果没有一个参照对比是无法进行测试。2)数据获取时间长,AB 测试一般都是进行小规模快速的试验,所以对于数据获取的单周期较长的试验不太适用。 影响测试效果的因素:1)新奇效应:即Novelty Effect 指老用户可能会觉得变化很新鲜,受变化吸引而偏爱新版本,哪怕从长远看来新版本并无益处。2)抗拒改变心理:即 Change Aversion 老用户可能会因为纯粹不喜欢改变而偏爱旧版本,哪怕从长远来看新版本更好。 在课程项目中,我们分成了三块涵盖了本章的所有知识点,这三块分别为: 概率 A/B测试 回归 如果在项目进行中,有知识点遗漏或忘记的地方,可以去查看相关课程视频或者导学,之后,记在你的小本本上。 I - 概率 本节的问题都相对比较简单,所以在导学中不过多赘述了。 测试1-理解数据集 这里没什么难度,基本的pandas知识,如果这节有什么问题的话,请查看第六周导学并面壁十分钟-。- 如果非要提醒一下的话,那就是在问题e. new_page 与 treatment 不一致的次数中,不要忘了也看看old_page与control的不一致次数,二者相加才是结果。 测试3-更新后的数据集 a问题中,因为要将处理后的数据集保存为新的变量,所以使用drop函数时,可以不用使用inplace = True参数。 d问题中,因为两个重复值除了时间戳不一致外,其他信息都是一致的,所以随便删除一个重复即可。 II - A/B测试 1.零假设与备择假设 这里只说一点,就是如何在Jupyter Notebook中使用公式的问题,其实也就是如何在Markdown中使用公式的问题,你只需要按照如下步骤即可: 打开Latex公式在线转换,输入好公式后,复制代码 将你想要输入公式的代码框,转为Markdown格式; 输入两个美元符号,即$$; 将刚复制的公式代码粘贴到两个美元符号中间,然后运行该代码框即可。 录了一个gif在下面,可以参考下: 2.进行假设检验 a、b 注意题干中给的要求是:假定在零假设中,不管是新页面还是旧页面, pnew 和 pold 都具有等于 转化 成功率的“真”成功率,也就是说, pnew 与 pold是相等的。此外,假设它们都等于ab_data.csv 中的 转化 率,新旧页面都是如此。 也就是:p_new = p_old = p_ab_data 注意:这并不意味着零假设就是p_new = p_old,可以从后续的c-g步骤能看出,零假设为p_new - p_old ≤ 0 c、d 这里的n_new与n_old就是对ab_data中使用新旧页面的用户数量进行统计。 e、f、g 使用numpy.random.choice函数,将零假设中的p_new与p_old作为抽样概率,n_new与n_old作为抽样次数,用1表示‘转化成功’,0表示‘未转化成功’,并将结果储存在一个新变量当中。 示例: 1 new_page_converted = np.random.choice([0,1],n_new,p = [1-p_new,p_new]) 以上获得的这个新变量,就是我们按照零假设中的n_new抽样n_new次的转化与否的分布模拟,那如何看模拟后的转化率呢?很简单,一个函数就搞定了,这里自己想。 h、i、j 这三步是使用for循环,将上面的过程不断重复10000次,获得一个抽样分布直方图,这个图会是正态分布吗? 关于实际观测值,即为你利用ab_data.csv直接计算得来的new_page与old_page转化率之差。 j中得到的值是什么呢?是不是在零假设的条件下,观察到实际观测值甚至更极端(更支持备择假设)的概率?那这个值的学名叫什么? 【这里实际上进行的是单尾检验,也就是对备择假设为p_new - p_old > 0来进行的】 i、m 使用了statsmodels中的proportions_ztest函数进行检验。实现的功能和上述a-j是一致的。 为什么要选择这个函数,以及这个函数的用法可以参考课程中给的链接proportions_ztest。 不过值得注意的是,在链接的列子中,使用的是双尾检验,也就是针对备择假设为p_new ≠ p_old去做的;但是在课程项目中,我们的备择假设为p_new > p_old,也就是单尾检验,所以函数中的某个参数要改一下。 使用内置函数方法获得的p值应该与前面获得的p值相近,如果差太多,那肯定是有地方需要再琢磨琢磨。 III - 回归 a 要想知道执行哪种类型的回归,就应该先看变量是属于数值变量还是分类变量,那题设中的变量是什么类型的变量呢? b 要求是:创建一个 ab_page 列,当用户接收 treatment 时为1, control 时为0。所以在对group列使用get_dummies函数时,应该把生成的treatment列保存为ab_page列,而control列则应该被删掉。 c、d 注意的一点是:不要忘了添加截距。在进行结果解释的时候,我们并不关注截距,只是关注变量的coef系数和p值,先看p值是否具有显著性,若有再看coef系数,若没有,则该变量对因变量没有影响。 e 在思考零假设与备择假设之前,注意看结果中标红框的位置,想想这是什么意思,这说明在回归计算中,采用的是单尾检验还是双尾?单尾和双尾又分别对应的假设是什么? g 数据集融合问题,之前单独出过一篇导学,如果忘了,请戳:Pandas数据融合,提醒下,合并时采用内连接,可以省去一些麻烦; get_dummies,注意该函数生成数据的顺序是按照字典顺序来的,所以,你在进行操作时,为了确保顺序不乱,最好能先看一下生成的结果,再进行重命名。 总结 大家能坚持到最后一个项目,十分不易,不过对于数据分析生涯来说,这只是你的开始,请继续保持这段时间的学习状态,如果非要给这个保持加一个期限的话,我希望是一辈子!大家加油!等你们的好消息!!

2018/9/26
articleCard.readMore

每周导学-第十一周-统计学进阶

Everything is difficult until you know how to do it. Hi,同学们,上周我们学习了统计学基础知识,包括概率基础、描述统计学和推论统计学的基础知识,本周我们将会进一步学习推论统计学——置信区间&假设检验以及它们的应用之一A/B-test,在这之后,我们还会讲解一部分机器学习入门——线性回归&逻辑回归,与上周相比,这周我们会接触较深的理论知识,更多的代码,你可能会觉得学起来有些吃力,但请一定保持信心,你可以多次暂停观看课程中的讲解视频,跟着一起多动手,或者你也可以按照下面我给出的额外资料去查漏补缺,相信你们一定可以的! 项目四(P4)阶段总共包含三周,在这三周内,我们要对统计学进行学习,掌握基础的描述统计学理论、基本的概率知识、二项分布和贝叶斯公式,并学会使用 Python 来实践;学习正态分布、抽样分布、置信区间以及假设检验的概念和计算方式;学习线性回归以及逻辑回归,在真实场景中应用,比如分析 A/B 测试结果,搭建简单的监督机器学习模型。可谓是时间紧任务重,但是也别怕,统计学的基础知识还是非常简单的,跟着课程内容一步步来,自己多做笔记多查资料,一定没问题的! 那么我们的课程安排: 时间学习重点对应课程 第1周统计学基础描述统计学 - 抽样分布与中心极限定理 第2周统计学进阶置信区间 - 逻辑回归 第3周完成项目项目:分析A/B测试结果 本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决: 先自行查找问题答案(注意提取关键词),参考:谷歌/必应搜索、CSDN、stackoverflow 额外参考资料: 可汗学院概率论与统计课程 机会的数学-陈希孺 条件概率及全概率公式及贝叶斯公式 statistics for data science 若问题未解决,请将问题及其所在课程章节发送至微信群,并@助教即可 饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧! 注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索! 本周目标 学习课程中的置信区间 - 逻辑回归课程,掌握统计学进阶知识。 学习计划 时间学习资源学习内容 周二微信群 - 每周导学预览每周导学 周三、周四Udacity - Classroom置信区间 - 逻辑回归 周五微信/Classin - 1V1课程难点 周六Classin - 优达日本周学习总结、答疑 周日笔记本总结沉淀 周一自主学习查漏补缺 知识清单 置信区间 学习之前可以先回顾一下正态分布、抽样分布和中心极限定理的相关知识。 是什么 还记得上周用到的优达学生喝咖啡的数据吗?我们同样以此为例来探讨下置信区间是什么。 假设,优达的学生有数十万个(总体),而我们能获得的学生数据只有几百个(样本),我们通过做样本均值进行抽样分布,得到了一个近似正态分布的图形,但这也仅仅是样本的均值分布,也就是样本统计量。我们利用样本统计量的分布去构造总体均值(总体参数)的估计区间,就叫做置信区间。 有什么 置信区间的两种应用 刚才的举例中我们用得是“均值”,这算是利用抽样分布建立单个参数的置信区间,可以应用在单变量估计等方面; 你还可以计算两种分类之间均值的差,这就是两个参数的置信区间,可以用在两变量的对比(A/B-Test)上,比如说医学上不同药物的治疗效果,不同广告的吸金率,不同网页的点击率等等。 置信区间的显著性 统计显著性:即我们通过理论分析得到的结果。在统计学上用α表示,叫做显著性水平,它表达的是区间估计的不可靠概率。比如说,我们获取了95%的置信区间,那么显著性水平α = 1 - P = 5%。 一般的,显著性水平都要求达到5%即可,这在之后的假设检验中会学习到。 实际显著性:即我们除了理论分析得到的结果外,还要考虑实际情况,比如说你能有多少资金用于投资,或者你的网站承载力能达到多少等。 与传统置信区间方法的对比 传统的置信区间/假设检验方法有很多,比如说t-检验、双边t-检验等等,但是我们所掌握的自助取样法可以代替他们全部,当然有一个前提条件,那就是你的样本容量一定要足够大,如果你的样本容量实在是少,那就只能选择传统方法去处理了。 获取传统方法python代码的方法,请自行去Stackoverflow搜索。 准确性&可靠性 这里课程中翻译的有点儿晦涩,这里着重讲一下,我们以候选人A为例(在95%可靠性下具有34%±3%的支持率),大概分布可以如下所示:字丑就将就着点看吧。。。 在上图中我们能发现,置信区间的置信概率(可靠性)越高,置信区间的宽度也就越宽,误差范围(准确性)也就会越大;那么当我们缩小误差范围时,置信区间的宽度和可靠性也就随之降低。 结论:置信区间的准确性和可靠性是一对相互矛盾的标准,所以在实际工作中,只能提出其中一个条件,然后推求另一条件的变动情况,如果所推求的另一条件不能满足要求,就应该考虑增加样本容量,重新进行抽样,直至符合要求为止。 怎么用 课程中已经给出了很好的示例、问题及解答,在这里只是拎出一些面生的代码进行讲解。 1 2 3 4 5 6 #设置随机种子,能保证结果之后可以复现 np.random.seed(7) #按百分比取值 np.percentile(array,q)#q介于0到100,取的是array中的q%位置的数。(从小至大排序) #拓展——按分位数取值,其实效果和上面按百分比取值一样,只是q值的范围变了 np.quantile(array,q)#q介于0到1,取的是array中的q位置的数。 注意:置信区间和假设检验只关注的是总体参数,而不能对某一个体下结论。 假设检验 是什么 基本概念 刚才我们讲解了什么是置信区间——为了得到总体指标,使用样本统计量去估计总体参数——这是一个从样本出发去研究总体的过程。 我们现在换一个角度,在实际分析问题中,能否去假定总体参数,然后根据样本数据,去检验这种假定是否正确,从而实现对总体指标的分析?其实这种从总体出发,用样本尺度去检验实现对总体参数分析的过程,就叫做假设检验。 置信区间与假设检验的关系:从上面的表述可以看出,假设检验和置信区间在本质上是一致的。如果使用样本数据对总体参数进行估计,在一定的置信区间下,总体参数就应该落在这个区间,如果假设的总体参数不在该区间中,则就有理由拒绝该假设,这其实就是从置信区间的角度去完成了假设检验的工作内容。 名词解释 零假设H0:一般的,零假设就是你不想要的结果,总包含等号。我们的目的就是要证明零假设是不成立的,是可拒绝的。比如说,你更新了网页设计,不想看到的是更不更新对你网站的流量没什么影响,那么零假设就可以这样设置。 备择假设H1:一般的,这就是你想要的结果。注意,备择假设应该是零假设的对立。 一类错误:原假设H0为真,却被拒绝。也叫拒真概率,一类错误是更为严重的错误。 二类错误:原假设H0为假,却被接受。也叫受伪概率。 在实际工作中,我们不可能要求一个检验方法永远不出错,但可以要求尽可能地减少犯错误的概率。但在样本容量给定的条件下,两种错误发生的概率必是此消彼长,因此,我们通常是控制第一类错误的概率,使它不超过某一给定的值(一般的取0.05),这样加以控制第一类错误,以此来制约犯第二类错误的概率。 p值:当零假设为真时,我们以零假设的参数建立正态分布(根据中心极限定理,当样本数量和抽样次数足够大时,抽样分布趋于正态分布),在该正态分布中观察到样本统计量甚至是更极端值(也就是偏向备则假设)的概率。 若这个概率很大,比如说p = 1,那么就表示样本统计量在按照零假设模拟的正态分布内,我们就不能拒绝零假设; 若这个概率很小,比如说 p < 0.05,那么在我们模拟的正态分布中观察到样本统计量的概率就是一个小概率事件,我们就可以拒绝零假设; 若p值等于0.05,可增加样本容量,重新进行抽样检验。 有什么 假设检验的基本思想 逻辑上的反证法:我们先假设原命题(零假设H0)成立,然后推出明显矛盾的结果,证明原命题不成立,则我们的所证命题(备择假设H1)成立。 小概率事件:概率很小的随机事件再一次随机实验中可以认为几乎是不会发生的,这就是小概率事件,我们证明零假设H0不成立,就是利用的小概率事件。 假设检验的基本思想可以归纳为:我们把不想要的结果(即零假设H0)假设成立,然后利用样本计算出该假设成立时的概率(即支持该假设的概率,也就是p-value),如果这个概率小于显著性水平α(一般的为0.05),那么就可以说明零假设是小概率事件,可以拒绝,就证明了我们想要的结果(即备择假设H1)成立,可以表述为:在显著性水平α下拒绝原假设。 试着理解一下上面这段话,如果理解不了,可以看看怎么用,会有详细的分步讲解。 进行多次假设检验的校正 Bonferroni Correction:是一种降低多重比较时第一类错误的矫正方法,举例说明该用法:如果你想在 20 个假设检验中把 I 类错误率维持在 1%,邦弗朗尼 校正率应为 0.01/20 = 0.0005。你应该使用这个新比率作为显著性水平α,对比每 20 个检验的 p 值,再做出决定。 怎么用 建立假设: 一般的都是均值或和与某数值之间的关系。示例如下: $$ H_0:\mu \leqslant 7 $$ $$ H_1:\mu > 7 $$ 进行多次重复取样(自助法) 1 2 3 4 5 6 7 8 #从原数据集中取样,样本容量要大于30 sample_df = df.sample(100) #新建列表 means = [] #循环取样,并计算均值,存贮在列表中 for _ in range(10000): bootsample = sample_df.sample(100,replace = True)#设置重复取样 means.append(bootsample.height.mean())#计算数据集中height变量的均值 构建零假设的正态分布(因为根据中心极限定理可知,当样本容量足够大,取样次数足够多时,均值的抽样分布近似于正态分布) 1 2 3 4 #计算抽样分布的标准差 null_std = np.std(means) #构建正态分布 null_vals = np.random.normal(7,null_std,10000)#三个参数依次为正态分布的均值、标准差和取值数量,其中均值即为零假设设置的值。 计算p值 1 2 3 4 #计算原始样本的均值 sample_mean = sample_df.height.mean() #计算支撑原假设的概率,即p值。计算由原假设构建的正态分布(均值为7)大于样本统计量的概率。 p_value = (null_vals > sample_mean).mean() 若零假设为:u ≥ 7,则p_value = (null_vals < sample_mean ).mean(); 若零假设为:u = 7,则p_value = (null_vals < sample_mean).mean() + (null_vals > null_mean + (null_mean - sample_mean) ).mean() 线性回归 基本概念 线性回归是属于机器学习中监督学习范畴的一种简单预测算法。我们通过查看两个定量变量之间是否存在线性关系,来进行预测。一般使用散点图对变量之间的关系进行可视化。 反应变量就是你想进行预测的变量,其实也就是因变量(y); 解释变量就是你用于预测的变量,其实也就是自变量(x)。 相关系数:最常用的就是皮尔逊相关系数,用r表示,取值范围为[-1,1],正值表示正相关,负值表示负相关,绝对值越大,相关性就越强。在描述相关性强弱时,可以参考如下取值范围: 关于更多更详细的相关系数的知识,请戳统计学之三大相关性系数,博主写得深入浅出,而且有很多浅显易懂的例子,感兴趣的话可以看看。 方程 方程模型 线性回归的方程模型就是一元一次方程,如下所示: b0表示截距,也就是回归线与y轴交点的y坐标; b1表示斜率,也就是回归线的倾斜程度; y^ 表示回归线反应变量的预测值,并不是确切的数据集中的y值。 拟合回归线 拟合回归线时我们采用的主要算法叫做 最小二乘法,即通过回归线得到的预测反应变量值与实际反应变量之差最小时的那条就是最佳拟合回归线,其原理公式可以表示为: 编程实现 在python中我们需要调用statsmodels包来拟合回归线: 1 2 3 4 5 6 7 8 9 10 11 # 加载statsmodels包 import statsmodels.api as sm #注意一定不要忘了截距 df['intercept'] = 1 # 构建变量模型及其拟合 # y为因变量,X表示单个或多个自变量(其中要包含截距),例如 df[["intercept", "area"]] 包括了截距和面积两个变量 lm = sm.OLS(y, X) result = lm.fit() # 获取最终的拟合模型报告 print(result.summary()) 在建立模型时,一般情况下都是需要手动添加截距(一般为常数 1), 想了解更多,可以查阅Statcon: Why we need the intercept或者When is it ok to remove the intercept in a linear regression model? - Cross Validated 参数和结果解释 coef:对应变量的参数值 std err:标准误差 t:统计检验值 P>|t| :这个是对应的 p 值,它的零假设为该变量的参数值等于0,可以指示该变量是否有利于预测反应变量,也能用于比较多个变量中哪个更重要。 R-squared :即决定系数,它是相关系数的平方。取值范围在[0,1],值越大,拟合效果就越好,这个值的统计意义可以简单解释为此次拟合中的解释变量能有多少百分比的可能去解释反应变量。 多元线性回归 基本概念 多元线性回归就是由多个自变量去预测因变量的方法,其模型方程与简单线性回归基本一致,只不过是将单自变量变为了多个自变量的矩阵,如下所示: 其中X就是多个自变量的矩阵。 编程实现 在Python中的编程实现步骤也如简单线性回归类似,别忘了要定义一个截距 1 2 3 4 5 6 7 8 9 10 11 # 加载statsmodels包 import statsmodels.api as sm #注意一定不要忘了截距 df['intercept'] = 1 # 构建变量模型及其拟合 # y为因变量,X表示多个自变量的矩阵(其中要包含截距),例如 df[["intercept", "area","bedroom", "bathroom"]] 包括了截距和面积、卧室数量、洗手间数量四个变量 lm = sm.OLS(y, X) result = lm.fit() # 获取最终的拟合模型报告 print(result.summary()) 参数和结果解释 这里和简单线性回归是一致的,只不过在解释单个自变量与因变量之间的关系时,需要加上一句“在其它变量不变的情况下……” 处理分类变量 思路 处理分类变量的一个思路就是将其转化为虚拟变量,也就是将各个分类变量单独成列,然后把观察行对应的分类变量量化为0(可理解为“否”)和1(可理解为“是”)作为该列的元素,再进行拟合处理。 在拟合处理时,我们添加的虚拟变量的数量应该为原数据集中的虚拟变量总数减一。 因为要计算最佳拟合系数时,需要用到变量矩阵的转秩,而判断矩阵是否可逆的充分必要条件就是这个矩阵是满秩的,又因为我们的虚拟变量矩阵中每一个变量都可以由其他变量推导而来,所以必须要舍弃一列才能确保变量矩阵为满秩。【感兴趣可以去可汗学院补一补线性代数知识】 方法 使用pandas中的get_dummies函数来进行虚拟变量的转换 1 2 #对neighborhood列进行量化,并将结果存储在df数据集的A/B/C三个新列中 df[['A','B','C']] = pd.get_dummies(df['neighborhood']) 注意:get_dummies函数输出结果的默认排序为字典顺序(即a-z),所以在进行新列储存时,一定要注意原始变量中的分类与虚拟变量列一一对应。 结果解释 还是以ABC三个分类变量来假设,我们以C作为基准变量(也就是删除的那列),那么在显示的结果中: coef Intercepti Aa Bb 1.Intercept的coef表示:如果分类为C的话,因变量即为i; 2.A的coef表示:如果分类为A的话,因变量为i+a; 3.B的coef表示:如果分类为B的话,因变量为i+b。 潜在问题 这部分课程中给了很多额外资料的链接,理论性很重,不太好啃,建议等通关后复盘的时候试着看一看。 多重共线性现象和分析 如果我们的自变量彼此相关,就会出现多重共线性。多重共线性的一个主要问题在于:它会导致简单线性回归系数偏离我们想要的方向。要判断是否有多重共线性,最常见的办法是借助散点图或 **方差膨胀因子 (即 VIF)**。 散点图 散点图比较好理解,使用之前提到过的seaborn中的pairplot能很直观的看出各个变量之间的相关性。代码如下: 1 2 import seaborn as sns sns.pairplot(df[["col_1", "col_2", "col_3"]]) 方差膨胀因子 方差膨胀因子(Variance Inflation Factor,VIF)是指解释变量之间存在多重共线性时的方差与不存在多重共线性时的方差之比。具体的计算方法如下(计算不做要求,但要理解) 假若有X1 、X2 、X3三个自变量,X1的vif计算: 1.x1对常数项(截距)、x2、x3做多元线性回归,求出R^2 2.则变量X1的VIF=1/(1-R^2) 3.同理计算出变量X2和X3的VIF。 它是指示多元线性回归中多重共线性严重与否的指标,VIF越大,多重共线性就越严重。 经验判断方法表明: 当0<VIF<10,不存在多重共线性; 当10≤VIF<100,存在较强的多重共线性; 当VIF≥100,存在严重多重共线性。 所以我们在处理的时候,就要去除VIF超过10的最不感兴趣的变量。 在python中的编程实现如下: 1 2 3 4 5 6 7 8 9 10 # 计算 VIF 需要使用 statsmodel 包 from statsmodels.stats.outliers_influence import variance_inflation_factor from patsy import dmatrices # 筛选出作线性回归的变量(截距不要加) y, X = dmatrices('col_y ~ col_1 + col_2 + col_3', df, return_type='dataframe') vif = pd.DataFrame() # 使用 variance_inflation_factor 来计算 VIF,并储存在vif DataFrame中 vif["VIF Factor"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])] vif["features"] = X.columns 【选修】高阶项 高阶项就是在回归模型中添加诸如x^2,x^3,x1·x2等变量,获取的方式可以直接使用df[‘col_1’]进行高阶计算即可。 关键是在于观察变量之间的散点图,来确定是否需要添加高阶项。 二阶、三阶的函数曲线很有辨识度,观察他们拐几个弯就可以; 交叉项的话,就看两自变量各自与因变量之间的回归线,如果回归线几乎平行,那就不必添加交叉项; 注意:如果确定要添加某变量的高阶项,一定要确保该变量也要添加进去。 之后的24-33节也是选修,而且给了Udacity一套免费的机器学习入门课程,建议通关后再来复盘。 逻辑回归 逻辑回归就是对分类变量进行预测的方法,尤其是对二分类问题(非1即0),比如说是否使用优惠券,是否存在贷款逾期问题等等。 方程 逻辑回归的方程模型就是sigmoid函数: 结合二分类问题的概率,做对数变换可得: 如上p/(1-p)即为事件的机会比,在该问题中,能预测范围在0到1之间。 编程实现 编程实现与线性回归类似,只不过将最小二乘法(OLS)替换成了逻辑回归(Logit): 1 2 3 4 5 6 7 8 9 10 11 # 加载statsmodels包 import statsmodels.api as sm #注意一定不要忘了截距 df['intercept'] = 1 # 构建变量模型及其拟合 # y为二分类变量,X表示多个自变量的矩阵(其中要包含截距),例如 df[["intercept","duration"]] 包括了截距和持续时间 lm = sm.Logit(y, X) result = lm.fit() # 获取最终的拟合模型报告 print(result.summary()) 参数和结果解释 coef:对应变量的系数 std err:标准误差 t:统计检验值 P>|t| :这个是对应的 p 值,可以指示该变量是否有利于预测反应变量,也能用于比较多个变量中哪个更重要。 在这里我们并不关注截距,而重点关注各个解释变量。 在进行结果解释时我们常说: 在保持其他变量不变的情况下, (对于数值变量)该变量每增加一个单位,那么作为y的分类变量则增大e^coef倍; (对于分类变量)该变量为它的对立时,作为y的分类变量发生的几率为该变量基础的e^coef倍。 【选修】模型评估 之后的课程已经是机器学习入门阶段的范畴,可以等通关后,再去研究。(建议先开始免费的机器学习课程,再结合本章内容复盘看,更有助于你理解) 总结 本周导学的内容较难,理解起来也比较困难,对于置信区间和假设检验两节,大家可以再额外补充一些统计学方面的相关知识,更有助于你理解;对于回归知识,建议多看几遍教学视频再结合例题,在实践中不断尝试去理解,大家加油!下周就要开始项目四了,阶段性的胜利就在前方!

2018/9/24
articleCard.readMore

每周导学-第十周-统计学基础

If you tell yourself you can’t, you won’t. Hi,同学们,上一阶段我们学习了数据分析的基本流程、Pandas在数据分析各个过程中的应用以及Matplotlib&Pandas的可视化基础,截至目前,你们已经算是掌握了基础的数据分析技能啦!撒花!但是在统计学理论和预测方面仍有欠缺,那么P4阶段就是解决这个欠缺哒! 本周开始,我们就进入到了项目四(P4)阶段,本阶段总共包含三周,在这三周内,我们要对统计学进行学习,掌握基础的描述统计学理论、基本的概率知识、二项分布和贝叶斯公式,并学会使用 Python 来实践;学习正态分布、抽样分布、置信区间以及假设检验的概念和计算方式;学习线性回归以及逻辑回归,在真实场景中应用,比如分析 A/B 测试结果,搭建简单的监督机器学习模型。可谓是时间紧任务重,但是也别怕,统计学的基础知识还是非常简单的,跟着课程内容一步步来,自己多做笔记多查资料,一定没问题的! 那么我们的课程安排: 时间学习重点对应课程 第1周统计学基础描述统计学 - 抽样分布与中心极限定理 第2周统计学进阶置信区间 - 逻辑回归 第3周完成项目项目:分析A/B测试结果 本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决: 先自行查找问题答案(注意提取关键词),参考:谷歌/必应搜索、CSDN、stackoverflow 额外参考资料: 可汗学院概率论与统计课程 机会的数学-陈希孺 条件概率及全概率公式及贝叶斯公式 statistics for data science 若问题未解决,请将问题及其所在课程章节发送至微信群,并@助教即可 饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧! 注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索! 本周目标 学习课程中的描述统计学 - 抽样分布与中心极限定理课程,掌握统计学基础知识。 学习计划 时间学习资源学习内容 周二微信群 - 每周导学预览每周导学 周三、周四Udacity - Classroom描述统计学 - 抽样分布与中心极限定理 周五微信/Classin - 1V1课程难点 周六Classin - 优达日本周学习总结、答疑 周日笔记本总结沉淀 周一自主学习查漏补缺 本周知识清单 描述统计学基础 描述统计分析就是通过数字或可视化的方法,对数据集进行整理、分析,并对数据的分布状态、数字特征和随机变量之间的关系进行估计和描述。其简要可以分为集中趋势分析、离散程度分析以及相关分析三大部分。所以,虽然这部分是选修内容,但拜托各位一定要看,这部分理论是数据分析的基础。 数据类型 数据类型是基础,尤其是之后在进行回归预测时,针对不同的数据类型可以选择不同的算法,所以必须掌握。 数据类型可以分为两大类:数值和分类;进而分为四小类:连续、离散、定序和定类。 数据类型 数值:连续离散 身高、年龄、收入书中的页数、院子里的树、咖啡店里的狗 分类:定序定类 字母成绩等级、调查评级性别、婚姻状况、早餐食品 描述统计的量 数据类型描述方面描述方式备注 数值:集中趋势均值 中位数偶数个时取中间两值均数 众数存在没有或多个的可能 离散程度极差max - min 四分位差(IQR)75%数 - 25%数 方差每个观察值与均值之差平方和的平均数 标准差方差的平方根 数据形状左偏态均值小于中位数(普遍但不绝对,下同) (需做直方图)右偏态均值大于中位数 对称分布(通常是正态分布)均值等于中位数 异常值一般为上下超过1.5倍四分位差处理方式见下面【异常值的处理】 分类:分类计量个数或比例 偏态分布示意图 其他概念: 五数概括描述法:利用最小值、第一四分位数(25%处)、第二四分位数(中位数)、第三四分位数(75%处)和最大值五个数对数值型变量的离散程度进行描述的方法。 当我们的数据遵循正态分布时,我们可以使用均值和标准差完全理解我们的数据集。 但是,如果我们的数据集是偏态分布,五数概括法(和关联的集中趋势度量)更适用于概括数据。 除直方图外,你还可以使用箱线图进行统计描述,箱线图其实是五数概括法的可视化。 异常值的处理: 1. 至少注意到它们的存在并确定对概括统计的影响。 2. 如果是输入错误 — 删除或改正 3. 理解它们为何存在,以及对我们想要回答的关于数据的问题的影响。 4. 当有异常值时,报告五数概括法的值通常能比均值和标准差等度量更好地体现异常值的存在。 5. 报告时要小心。知道如何提出正确的问题。 随机变量 随机变量集用大写字母,如X表示; 而集里面的某个变量用对应的小写字母,如x1,x2等表示。 推论统计学基础 推论统计就是根据现有收集的部分数据对更大的总体数据进行推论的方法。他的几个关键要素为: 总体 —— 我们想要研究的整个群体。 参数 —— 描述总体的数值摘要 样本 —— 总体的子集 统计量 —— 描述样本的数值摘要 辛普森悖论 本节以录取案例分析为例,展示了辛普森悖论。这个例子不必深究,只是为了提醒大家要以多种方式去观察数据,避免出现案例分析中的反例。 辛普森悖论是在某个条件下的两组数据,分别讨论时都会满足某种性质,可是一旦合并考虑,却可能导致相反的结论。那么如何避免辛普森悖论呢?那就要从产生它的源头——混杂因素上考虑,混杂因素就是一个与核心研究无关的变量,它会随着变量的改变而改变,就比如说在课程中的例子中,不同专业的总人数就有很大差异,它会随着专业的改变而改变。所以在之后处理类似问题时就要进行多变量分析,这样才能帮助我们认清事件的本质。 概率 概率与统计的关系 从课程中给的这幅关系图就能很明显的看出来,概率是由模型(MODEL)去预测数据(DATA),而统计是由数据去建立模型(进而再去做预测,也就是‘’根据数据去预测数据’‘)。 基础知识 概率,是一种几率、可能性,描述是事件发生的可能性度量量。随机事件,指一个被赋予机率的事件 集合,针对的是事件在样本空间的一个子集。事件A发生的概率,用符号P(A)表示 。 任何事件的发生概率在 0 和 1 之间,其中包括 0 和 1。(0表示不可能发生,1表示必然发生) 独立事件:事件每次发生的结果与前后的发生结果无关。比如说,第一次掷骰子的结果与第二次的结果 互斥事件:不可能在同一次实验中出现的俩事件。比如说,掷骰子实验中的1和6 对立事件:是一种特殊的互斥事件,即试验中只有俩种可能A和B,那么事情的发生非A即B。可以表示为 如掷硬币的正面和反面。 加法原理:若两种方法均能完成此事,则此事发生的概率为P(A) + P(B) 乘法原理:若两个步骤分别不能完成此事,则此事发生的概率为P(A)·P(B) 二项分布 也叫伯努利分布,是指n个独立的事件A发生的概率分布。设每次试验中事件A发生的概率为p,则进行n次试验,A发生k次的概率为: 条件概率 在现实中,我们处理的事情并不像骰子和硬币那样简单,有些时间的结果往往依赖于其他的事情,比如说晨练的概率跟这个人是不是夜猫子有关等等。那么,这就引出了条件概率,即在事件B发生的条件下,事件A发生的概率为: 其中,P(AB)表示AB同时发生的概率。 在如下的文氏图中,AB同时发生的概率可以表示为两个圆的交集,那么B已经发生的条件下A发生的概率就是这个交集(橙色部分)占整个B圆的比例。 之前讲过独立事件,那么用公式的方式可以表达为:P(A) = P(A|B)。根据条件概率公式可以推导出,当P(AB) = P(A)P(B)时,则可说明A事件与B事件相互独立。 全概率公式 也就是A发生的概率为在互斥的多个事件(B1,B2…)已发生的条件下的条件概率之和。公式可以表示为: 贝叶斯法则 贝叶斯法则是概率推理的黄金法则,是利用先验概率计算后验概率的方法。 课程中的癌症例子十分贴切,讲解的也十分详细,所以大家看到前20个小节,能理解贝叶斯法则就可以了,后面的是在无人驾驶中的应用例子,可以跳过不看。 在课程示例中: 由条件概率能计算出患癌与检查结果为阳性同时发生的概率P(C,Pos)(红色区域占整个矩形的比例)和没患癌与检查结果同时发生的概率P(~C,Pos)(绿色区域占整个矩形的比例)。 二者相加,即为检查结果为阳性的概率(全概率公式)P(Pos)。 则,检查结果为阳性的条件下患癌概率为: 这样我们就得到了更接近真实的检查结果为阳性的患癌概率。 在这个例子中: 癌症发生的概率P(C)为先验概率,即在我们进行检查之前就对患癌概率的一个判断; 阳性结果下为癌症的概率P(C|Pos)为后验概率(阳性下非癌症、阴性癌症、阴性非癌症都是),这些是在检查发生之后,我们对患癌概率这件事的重新评估; 这就是贝叶斯法则的含义。我们先预估一个”先验概率”,然后加入实验结果,由此得到更接近事实的”后验概率”。 如果感觉理解困难,可以看一下白话版的贝叶斯讲解:怎样用非数学语言讲解贝叶斯定理(Bayes’s theorem) Python概率练习 前面我们学习了概率的基本知识,有了理论基础,本节就是利用Python落地的教学。应用的第三方包为NumPy和Pandas。 均匀随机取整 使用的函数为numpy.random.randint(low, high=None, size=None, dtype='l'): low:当没有high参数输入时,作为取值范围的最大值+1;当有high参数输入时,则作为取值范围的最小值; high:取值范围的最大值+1,默认为无输入; size:输入数字则表示取值的数量,输入元组则表示取值矩阵的行和列; dtype:数据类型,默认为np.int; 函数的输出为int或者是由int数据类型组成的ndarray。 函数的具体用法如下: 1 2 3 4 5 6 7 8 9 10 11 12 import numpy as np # 未定义high参数,取值范围是是0到1(即low - 1) >>> np.random.randint(2, size=10) array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) # 定义了high参数,取值范围是2(即low)到4(即high - 1) >>> np.random.randint(2,5,size = 10) array([2, 2, 3, 3, 4, 2, 3, 2, 2, 4]) # 定义一个2x4的矩阵,取值范围是0到4 >>> np.random.randint(5, size=(2, 4)) array([[4, 0, 2, 1], [3, 2, 2, 0]]) 不均匀随机取数 使用的函数为numpy.random.choice(a, size=None, replace=True, p=None): a:输入列表时,取数就从该列表中取;若输入为数字时,取值范围为0到该数字 - 1; size:输入数字则表示取值的数量,输入元组则表示取值矩阵的行和列; replace:布尔值,默认为True,若设置为False表示取数不会重复;(以从袋子中取球为例,True是取完放回再取,而False则是取了不放回,继续取) p:表示概率,与a的输入值一一对应。 函数的输出为int或者是由int数据类型组成的ndarray。 函数的具体用法如下: 1 2 3 4 5 6 7 8 9 #输入数字时取数 >>> np.random.choice(5, 3) array([0, 3, 4]) #设置replace参数 >>> np.random.choice(5, 3, replace=False) array([3,1,0]) #设置概率 >>> np.random.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0]) array([2, 3, 0]) 二项分布 使用的函数为numpy.random.binomial(n, p, size=None),参数也很好解释。 参数中的n即为每次试验中取值的次数,p则为试验中的某一种事件成功的概率,size则是试验的次数。 条件概率与贝叶斯规则测试 这里主要是一些Pandas函数的应用,经过上一阶段的学习应该已经很熟练了。 主要涉及的函数是分组和统计计数类的函数,比如说groupby,query,count等,如果忘记的话,自己查官方文档或者之前的笔记,这里不再赘述。 正态分布 课程中以抛硬币模型引入了二项分布进而讲解了正态分布模型,那么到底什么是正态分布或者满足什么条件就可以算是正态分布了呢? 在相同条件下,我们随机地对某一测试对象(抛硬币20次,其中正面的次数)进行多次测试(抛很多次20次)时,测得的数值在一定范围内波动(从0到20),其中接近平均值的数据(10左右)占多数,远离平均值的占少数。具有这种分布规律的随机变量的分布就称作正态分布。 大概长这样儿: 它的概率密度函数可以表示为: 这里为什么要引入正态分布呢? 假设检验是基于正态分布的 许多社会和经济现象对应的随机变量分布,都可以用正态分布来描述 中心极限定理 在此之前,先回顾下推论统计的几个概念: 总体 —— 我们想要研究的整个群体。 参数 —— 描述总体的数值摘要 样本 —— 总体的子集 统计量 —— 描述样本的数值摘要 课程中举得例子是统计优达学生中喝咖啡的人所占比例,我们看下图: 图中所有的杯子(学生)就叫做总体;此外可以看到有四个深浅不一的蓝色底框,每个底框链接了5个学生,这5个学生就是样本,每组样本我们还计算了喝咖啡的比例,这就是统计量。 一般的,样本数≥30即可称为大样本。 大样本条件下,抽样平均数的分布接近正态分布。 但必要抽样数目的确定是有相关公式计算的,这里就不给出了,感兴趣的话可以去搜搜看。 现在我们继续按照课程中的例子进行取样,样本容量为5,不断得取10000次,计算均值的分布情况如下: (完全看不出这是个什么分布) 将样本容量改为50,仍然取10000次,计算均值的分布情况如下: 已经可以看出正态分布的样子了,那如果继续增加样本容量,改为5000,同样取10000次,计算均值的分布情况如下: 想比上一幅图,这幅可视化更接近正态分布,均值处于相同的位置,但方差(离散程度)明显小了很多。 上面的这个过程就是中心极限定理的含义,随着样本容量的逐渐增大,平均数的抽样分布越接近正态分布(但也不一定必须要很大很大才能近似于正态分布),同样这也适用于求和,比例等,但不适用于所有的统计量,比如说最大值,方差等等。 中心极限定理的妙处就在于,我们可以从任意的乱七八糟的分布取任意数量的样本值(比如上面例子中的5,50),然后计算样本的均值(或者和),不断得取值求均,最终做他们频率的可视化,你会发现这是一个非常完美的正态分布。 现实生活中有很多的随机过程,有的分布就是乱七八糟,但是你可以通过中心极限定理,得到他们均值或者和的正态分布,这也是为什么正态分布在统计中如此常用的原因之一。 如果感觉理解起来还是有点儿困难的话,你可以戳在线抽样分布模拟器,自己动手试一试。 大数定理 大数定理表达的是随着样本容量增加,样本平均数越来越接近总体平均数,字面上的意思很好理解,但这里有一点要注意,我们举例来说明一下: 比如说,我现在有100枚硬币,放在一个盒子里,随便摇一下盒子,打开,对正面朝上的硬币进行计数(当然,我们知道期望为100 x 0.5 = 50): 第一次实验的结果是55;第二次是60;第三次是70,三次实验的均值为((55+60+70)/3 ≈62),那你觉得,下次实验的结果是更有可能小于50还是大于50呢? 你有可能这样想,根据大数定理,随着我们试验次数的不断增加,均值肯定是不断趋向于50的,前三次的实验中每次都超过50,那么下次的实验会有更大的可能小于50,来纠正前三次实验的偏差。 如果你真的这样想,你就陷入了赌徒悖论。大数定理不关心前面发生的有限次实验,因为后面还有无限次的实验,而这无限次实验的期望值是50。这个例子可能比较随意,但这就是大数定理的含义。 自助法 自助法,bootstrap,也就是重复抽样。还记得上一节导学中讲到的numpy.random.choice函数吗?里面有一个replace参数,默认为True表示重复取样,也就是自助法;若设置为False,则表示不重复取样。 总结 本期导学主要对描述统计学和概率的基础知识进行了总结,这部分偏理论一些,如果觉得理解起来有点吃力,可以通过重复看视频,边看边用笔去算或者去网上搜集一些资料或者找一些教科书去查阅,要求是:不一定要完全掌握其原理,但求理解和会用。

2018/9/13
articleCard.readMore

每周导学-第九周-P3阶段总结

Nothing is particularly hard if you divide it into small jobs. Hi,同学们,本周是我们P3阶段的最后一周,前三周我们掌握了数据分析的基本流程、Pandas在数据分析各个流程中的基本应用,使用matplotlib&Pandas进行可视化的技巧,并且在项目三中得到了巩固和锻炼。我也陆续收到了大家的项目展示,都十分厉害,尤其是问题的提出以及可视化,非常能吸引人,只是数据整理阶段的代码还需再慢慢磨练,得以精简。本周导学呢,我们就是对之前所学做一个总结,希望大家也能自己做一份总结(这份总结才是最贴切你自己需求的),优达日的时候我们会一起交流一下自己的项目心得以及踩过的坑,等你们哦~ 项目三(P3)阶段总共包含四周,在这一个月内,我们要对数据分析入门进行学习,学习数据分析思维,掌握Python数据分析及可视化方法,并使用所学知识完成项目三:探索数据集,尝试着自己完成整个数据分析的流程,得到一些饶有兴趣的结论,你一定会非常有成就感哒!那么以下便是这四周的学习安排: 时间学习重点对应课程 第1周数据分析过程-1数据分析过程&案例研究-1 第2周数据分析过程-2案例研究-1&案例研究-2 第3周完成项目项目:探索数据集 第4周项目修改与通过修改项目、查缺补漏、休息调整 !!看这里!!:在P3课程里面安排了SQL的高阶课程,但是因为在项目三中并不会涉及到SQL知识,所以为了保证大家学习的连贯性,在完成前两周的课程之后,就开始项目。至于!!SQL的高阶知识,大家可以放在课程通关后进行选修!!; 本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决: 先自行查找问题答案(注意提取关键词),参考:谷歌/百度搜索、菜鸟教程、CSDN、stackoverflow、Python for Data Analysis, 2nd Edition 、Python Cookbook 若问题未解决,请将问题及其所在课程章节发送至微信群,并@助教即可 饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧! 注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索! 本周目标 完成你的项目,并且对P3阶段做一个自我总结,最好能以博客或者朋友圈文章的形式进行输出。 学习计划 时间学习资源学习内容 周二微信群 - 每周导学预览每周导学 周三、周四Udacity - Classroom项目三 周五微信/Classin - 1V1课程难点 周六Classin - 优达日本周学习总结、答疑 周日笔记本总结沉淀 周一自主学习查漏补缺 知识点清单 第六周-数据分析过程 数据分析的基本流程 提出问题 整理数据(收集、评估、清理) 探索性数据分析 得出结论,传达结果 Pandas在数据分析中的应用 导入文件(read_csv/excel/sep/encoding) 数据评估(shape / info / describe / columns/ isnull/ duplicated/ value_counts/ sort_values/ ascending/ unique/ nunique) 数据筛选(df[‘col_name’]/loc/iloc/np.r_/isin/query/groupby/&/|) 数据清理(drop/inplace/fillna/dropna/drop_duplicates/rename/replace) 数据融合(merge/concat/append/join) 可视化(plot) 导出数据(to_csv/index/encoding = ‘utf-8-sig’) 第七周-可视化 基本概念(fig/ax) 开始绘图(plt.subplots/plt.add_subplot/plt.figure) 坐标轴设置 调整范围(ax.axis/xlim/ylim) 调整刻度 设置间隔(locator_params) 设置顺序,角度(xticks(order_list,tick_names,rotation) 双轴(twinx) 标题与轴标题(title,xlabel,ylabel) 图例(legend) 颜色与样式(plot(x,y,’color``marker``line‘) 网格(grid) 图像注释(annote) 平行于坐标轴的线(vline/hline) 常用可视化图形 散点图(scatter) 条形图(bar/barh) 直方图(hist) 饼状图(pie) 箱线图(box) 第八周-TMDb数据分析 如何提出问题? 找出关键变量,提与之相关的问题 数据备份(copy) 如何将一列处理为多列?(genres列的处理) 拓展:pivot函数 如何着手探索性数据分析? 单变量 - 双变量 - 多变量 关键变量 - 其他变量与关键变量 可视化 热度图(heatmap) pairplot 一些函数: 获取某一位置的数值 quantile 按列表筛选 isin 第八周-FBI枪支数据分析 DataFrame行列变换:transpose 按字符串内容筛选:contains 按索引进行数据融合:join 总结 通过这四周的学习,你又掌握了: 数据分析的基本流程 Pandas在数据分析各个流程中的基本应用 Pandas常用函数的用法 Matplotlib在可视化中的应用 此外,你还增长了这些软技能: 数据分析思维(化繁为简、化难为易、关键信息的提取) 耐心(EDA的过程,做过的都知道) 细心(有没有调试半天最终才发现是自己马虎导致的问题?) 如果你学习时间充裕,你还有可能掌握了: Seaborn在可视化中的应用 如何快速有效地使用搜索引擎 在Stackoverflow注册账户,提出问题,成为一名铜牌用户 有了自己的技术博客,并发表了第一篇总结性文章 … … 哈!这么总结下来,发现不知不觉间,又掌握了很多!又进步了很多!我导师之前教育我说:“你之所以现在这么焦虑,都是因为你自己的能力满足不了你的欲望。”那么,同样因为对未来感到焦虑来到这里学习的你们,经过这段时间的学习,焦虑是不是缓解了许多呢?哈哈,所以,请不要放松脚步,KEEP GOING!

2018/9/9
articleCard.readMore

每周导学-第八周-FBI枪支数据分析

Stop being afraid of what could go wrong and start being positive about what could go right. Hi,同学们,经过了前两周的学习,我们掌握了数据分析的基本流程、Pandas在数据分析各个流程中的基本应用以及使用matplotlib&Pandas进行可视化的技巧,那么本周我们就真刀实枪地找一套数据集练练手。本周的导学有两期,分别选用了项目三中的两个数据集(TMDb电影数据和FBI枪支数据)进行分析,只是分享思路和方法,起一个抛砖引玉的作用,大家选择其他的数据集也可以举一反三,如果有什么棘手的问题随时微信联系我就OK~ 本周开始,我们就进入到了项目三(P3)阶段,本阶段总共包含四周,在这一个月内,我们要对数据分析入门进行学习,学习数据分析思维,掌握Python数据分析及可视化方法,并使用所学知识完成项目三:探索数据集,尝试着自己完成整个数据分析的流程,得到一些饶有兴趣的结论,你一定会非常有成就感哒!那么以下便是这四周的学习安排: 时间学习重点对应课程 第1周数据分析过程-1数据分析过程&案例研究-1 第2周数据分析过程-2案例研究-1&案例研究-2 第3周完成项目项目:探索数据集 第4周项目修改与通过修改项目、查缺补漏、休息调整 !!看这里!!:在P3课程里面安排了SQL的高阶课程,但是因为在项目三中并不会涉及到SQL知识,所以为了保证大家学习的连贯性,在完成前两周的课程之后,就开始项目。至于!!SQL的高阶知识,大家可以放在课程通关后进行选修!!; 本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决: 先自行查找问题答案(注意提取关键词),参考:谷歌/百度搜索、菜鸟教程、CSDN、stackoverflow、Python for Data Analysis, 2nd Edition 、Python Cookbook 若问题未解决,请将问题及其所在课程章节发送至微信群,并@助教即可 饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧! 注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索! 本周目标 在此处挑选和你确认过眼神的数据集,并对其进行数据分析和探索,得出你自己的结论,然后进行提交。 学习计划 时间学习资源学习内容 周二微信群 - 每周导学预览每周导学 周三、周四Udacity - Classroom项目三 周五微信/Classin - 1V1课程难点 周六Classin - 优达日本周学习总结、答疑 周日笔记本总结沉淀 周一自主学习查漏补缺 项目准备 环境准备 强烈建议大家完成本地环境的搭建,在本地完成此项目。搭建本地环境的方法请参考Anaconda的安装与配置一节,完成后你将获得本项目中会用到的关键软件:Spyder和Jupyter Notebook。 文件准备 项目文件:依次进入到项目:探索数据集 –> 3.实战项目中,下载项目文件的ipynb格式。 数据集选择:在此处选择你感兴趣的数据集并下载至与项目文件相同的文件夹。(若下载失败,请微信联系我索取) 本地打开:在项目文件的文件夹下,按住Shift键,右击选择在此处打开命令窗口,输入jupyter notebook,待打开本地页面之后,选择项目文件打开,之后就请开始你的表演。 方法准备 项目文件中已经给大家列好了基本流程,所以请在开始项目之前,一定要先整体浏览一遍项目文件,着重看一下: 项目流程 每一个流程中你需要做哪些工作 每一个流程中的提示 要记得,数据分析过程不是一蹴而就的,是螺旋上升接近目标的过程,所以一定要保持耐心,对照着项目评估准则一步步完成。 另外,一开始你的notebook会显得很乱没有章法,那在提交之前最好能再修改一个整理好的版本。 项目流程(FBI枪支数据) 数据集说明 该数据来自联邦调查局 (FBI) 的全国即时犯罪背景调查系统 (NICS)。NICS 用于确定潜在买家是否有资格购买枪支或爆炸物。枪支店可以进入这个系统,以确保每位客户没有犯罪记录或符合资格购买。该数据已经收纳了来自 census.gov 的州级数据作为补充数据。NICS 数据在一个 xlsx 文件格式的一个表格中,它包含了按照月份(month)、州 (state) 、类型 (type) 统计的武器调查数量 (the number of firearm checks) ;美国的人口普查数据 (U.S. census data) 储存在一个 csv 文件中。它包含了州级的几个变量,每个州的大多数变量在 2016 年只有一个数据点,但一些变量有一年以上的数据。 提出问题 虽说本数据集有两个数据文件,但围绕的关键词只有一个,那就是枪支,所以提出问题时,也一定要围绕着该关键词进行提问。问题示例: 就本数据集统计而言,哪个州的枪支总量增长最高?该州的增长速率如何? 就本数据集统计而言,全美整体购买枪支总量及各种类的趋势是什么? 2016年哪个州的人均拥有枪支量最高? 结合2016年各州的人口普查数据,是否有哪项数据与人均拥有枪支量线性相关? 导入拓展包 一般来说,就导入如下几个拓展包就够了,当然如果后续操作中还需导入其他包的话,再补充即可。 1 2 3 4 5 6 7 8 9 10 11 12 13 # 用这个框对你计划使用的所有数据包进行设置 # 导入语句。 import pandas as pd import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt import seaborn as sns # 务必包含一个‘magic word’,以便将你的视图与 notebook 保持一致。 %matplotlib inline #关于更多信息,请访问该网页: # http://ipython.readthedocs.io/en/stable/interactive/magics.html 数据整理 导入数据 1 2 3 4 #导入枪支数据 df_gun = pd.read_excel('gun_data.xlsx') #导入人口普查数据,这里有一点需要注意,若数据集中全部是包含有千位分隔符的数据,可以在read_csv中添加参数"thousands = ','"。 df_census = pd.read_csv('U.S. Census Data.csv') 评估数据 枪支数据 浏览数据 1 df_gun.head() 这里要注意一点,因为数据集的列数较多,jupyter会自动折叠中间的部分列,导致我们预览数据时总是看不完整,这时候你可以尝试下: 1 2 #col_numbers设置为不小于你数据集列数的某一值 pd.set_option('max_columns',col_numbers) 同理,也可以用’max_rows’设置最大显示行数。 列及数据类型 1 df_gun.info() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <class 'pandas.core.frame.DataFrame'> RangeIndex: 12485 entries, 0 to 12484 Data columns (total 27 columns): month 12485 non-null object state 12485 non-null object permit 12461 non-null float64 permit_recheck 1100 non-null float64 handgun 12465 non-null float64 long_gun 12466 non-null float64 other 5500 non-null float64 multiple 12485 non-null int64 admin 12462 non-null float64 prepawn_handgun 10542 non-null float64 prepawn_long_gun 10540 non-null float64 prepawn_other 5115 non-null float64 redemption_handgun 10545 non-null float64 redemption_long_gun 10544 non-null float64 redemption_other 5115 non-null float64 returned_handgun 2200 non-null float64 returned_long_gun 2145 non-null float64 returned_other 1815 non-null float64 rentals_handgun 990 non-null float64 rentals_long_gun 825 non-null float64 private_sale_handgun 2750 non-null float64 private_sale_long_gun 2750 non-null float64 private_sale_other 2750 non-null float64 return_to_seller_handgun 2475 non-null float64 return_to_seller_long_gun 2750 non-null float64 return_to_seller_other 2255 non-null float64 totals 12485 non-null int64 dtypes: float64(23), int64(2), object(2) memory usage: 2.6+ MB 纵览了一下,各列的数据类型基本没什么问题,唯一有问题的是month列,应该是datetime类型。整个数据集就是由时间、州名和各式各样的枪支数据组成的。 查看各列的缺失值情况 1 2 #这里我们计算的缺失比例 df_gun.isnull().sum()/df_gun.shape[0] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 month 0.000000 state 0.000000 permit 0.001922 permit_recheck 0.911894 handgun 0.001602 long_gun 0.001522 other 0.559471 multiple 0.000000 admin 0.001842 prepawn_handgun 0.155627 prepawn_long_gun 0.155787 prepawn_other 0.590308 redemption_handgun 0.155386 redemption_long_gun 0.155467 redemption_other 0.590308 returned_handgun 0.823789 returned_long_gun 0.828194 returned_other 0.854626 rentals_handgun 0.920705 rentals_long_gun 0.933921 private_sale_handgun 0.779736 private_sale_long_gun 0.779736 private_sale_other 0.779736 return_to_seller_handgun 0.801762 return_to_seller_long_gun 0.779736 return_to_seller_other 0.819383 totals 0.000000 dtype: float64 可见数据集的缺失情况非常严重,这时候需要你直接运行df_gun去观察全部数据,这样才能有据猜想数据缺失的原因。简要通览数据后,我们发现近年的数据缺失不大,猜想之前的统计中没有对枪支进行详细分类或者是统计不全导致的,而且就枪支数量而言,缺失数据较少的permit、handgun、long_gun和other等列占绝对优势,所以我们完全可以只筛选最有代表性的这几列进行分析。 因为筛选后的数据跟之前相差较大,为了提高后续步骤的效率,可以在此先进行数据清理 1 2 #因为此次筛选的数据列是间隔的,所以调用了numpy的r_函数生成列表,按照列序号筛选间隔的列。 df_gun = df_gun.iloc[:,np.r_[0:3,4,5,7,8,26]].dropna() 之后,还需对最后一列totals进行修正 1 df_gun['totals'] = df_gun['permit']+df_gun['handgun']+df_gun['long_gun']+df_gun['multiple']+df_gun['admin'] 查看重复值 1 2 #检查是否有数据重复 sum(df_gun.duplicated()) 1 0 无重复数据。 查看state列的唯一值数 1 df_gun['state'].nunique() 1 55 美国一共有50个州,多出来的5个是什么鬼?是不是有缩写的州名导致的重复? 1 df_gun['state'].value_counts() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 New Mexico 227 California 227 South Carolina 227 Arkansas 227 Kansas 227 New Jersey 227 West Virginia 227 Texas 227 Maryland 227 District of Columbia 227 New Hampshire 227 Alaska 227 Mississippi 227 Alabama 227 Vermont 227 Illinois 227 North Dakota 227 Rhode Island 227 Pennsylvania 227 Oklahoma 227 Kentucky 227 Florida 227 North Carolina 227 Utah 227 Idaho 227 Connecticut 227 Missouri 227 Nebraska 227 Tennessee 227 Massachusetts 227 Nevada 227 Arizona 227 Hawaii 227 Indiana 227 Oregon 227 Michigan 227 Minnesota 227 Ohio 227 New York 227 Wyoming 227 Iowa 227 Maine 227 Guam 227 Wisconsin 227 South Dakota 227 Puerto Rico 227 Georgia 227 Washington 227 Delaware 227 Louisiana 226 Virginia 226 Montana 226 Colorado 226 Mariana Islands 218 Virgin Islands 214 Name: state, dtype: int64 结果一目了然,不仅有美国各州,还包括了Mariana Islands 、Virgin Islands 等地,感兴趣可以去搜了一下,都是老美宣誓主权的一些群岛。 人口普查数据 评估的步骤差不多,所以只罗列一些需要注意的点。 1 df_census.info() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <class 'pandas.core.frame.DataFrame'> RangeIndex: 85 entries, 0 to 84 Data columns (total 52 columns): Fact 80 non-null object Fact Note 28 non-null object Alabama 65 non-null object Alaska 65 non-null object Arizona 65 non-null object Arkansas 65 non-null object California 65 non-null object Colorado 65 non-null object Connecticut 65 non-null object Delaware 65 non-null object Florida 65 non-null object Georgia 65 non-null object Hawaii 65 non-null object Idaho 65 non-null object Illinois 65 non-null object Indiana 65 non-null object Iowa 65 non-null object Kansas 65 non-null object Kentucky 65 non-null object Louisiana 65 non-null object Maine 65 non-null object Maryland 65 non-null object Massachusetts 65 non-null object Michigan 65 non-null object Minnesota 65 non-null object Mississippi 65 non-null object Missouri 65 non-null object Montana 65 non-null object Nebraska 65 non-null object Nevada 65 non-null object New Hampshire 65 non-null object New Jersey 65 non-null object New Mexico 65 non-null object New York 65 non-null object North Carolina 65 non-null object North Dakota 65 non-null object Ohio 65 non-null object Oklahoma 65 non-null object Oregon 65 non-null object Pennsylvania 65 non-null object Rhode Island 65 non-null object South Carolina 65 non-null object South Dakota 65 non-null object Tennessee 65 non-null object Texas 65 non-null object Utah 65 non-null object Vermont 65 non-null object Virginia 65 non-null object Washington 65 non-null object West Virginia 65 non-null object Wisconsin 65 non-null object Wyoming 65 non-null object dtypes: object(52) memory usage: 34.6+ KB 发现一个奇怪的事情,基本上所有列数据都在65行之后没有了,肯定有什么猫腻,可以用tail()或者直接打开文件查看(因为数据量很小),发现后面几行都是对数据统计的一些说明,没有实际意义,直接删除即可。而且在该数据中只有50个州的数据。 清理数据 清理数据就是对上一步中发现的问题进行清理,并且删除无关列,最终得到的是一个方便你进行分析及可视化的干净数据。 清理前记得备份数据 删除无关列 建议使用drop函数 1 2 3 4 #删除列 df_census.drop('Fact Note',axis = 1,inplace = True) #删除行 df_census.drop(np.arange(64,85),inplace = True) 数据融合 想要找出人口普查的数据与枪支数据之间的关系,肯定要把这两个数据进行融合。 融合前,我们先观察一下人口普查数据中到底有哪些,发现每个州的大部分变量都只在2016年有记录点,所以我们就要分别从人口普查数据和枪支数据中筛选出2016年的数据,再以州作为键(key)进行合并。 筛选数据 1 2 3 4 5 6 #先筛选出人口普查数据中2016年的数据,并将Fact列作为索引 df_census_2016 = df_census[df_census.Fact.str.contains('2016')].set_index('Fact') #转秩 df_census_2016 = df_census_2016.transpose() #筛选2016年的枪支数据,并按照州分组计算全年均值 df_gun_2016 = df_gun[df_gun['month'].str.contains('2016')].groupby('state').mean() 处理千位分隔符和百分号 在人口普查数据中数字中均包含有千位分隔符或者是百分号,这会给我们之后进行分析带来不便,处理掉他们,并且转换为浮点型数据。 1 2 3 4 5 #先将有千位分隔符的列转为float类型 for i in [ 'Population estimates, July 1, 2016, (V2016)','Housing units, July 1, 2016, (V2016)', 'Building permits, 2016']: df_census_2016[i] = df_census_2016[i].str.split(',') df_census_2016[i] = df_census_2016[i].str.join('') df_census_2016[i] = df_census_2016[i].astype(float) 百分号的处理方式同上类似。 数据融合 我们在之前的导学中总结过Pandas做数据融合的方法,就此项目而言,两个数据以索引(Index,也就是各州的州名)为键进行融合,最简单的方法就是用join()函数了。如果你忘了,可以点这里复习一下。 1 df_2016 = df_gun_2016.join(df_census_2016) 好,至此我们的数据就算是整理完毕了,接下来就是探索性分析及可视化阶段,这里没有什么特别需要注意的地方,大家就随性而为。 探索性数据分析 在这个阶段你可以随意做可视化,尽可能多得去探索你想解决的问题。在探索阶段,作图可以不用很规范,你自己知道是什么意思就可以,而且可能会有些探索的问题结果意义不大,所以在提交项目时,要进行择优保留并对其润色修饰。 探索不同年份,美国或者是不同州的枪支数量变化就使用df_gun数据集; 探索不同州的人口普查数据与枪支持有量之间的关系就使用我们之后整理的df_2016数据集。 得出结论 对你整理好的可视化图像进行总结,结论要有根有据但也不要只是停留在描述,可以进行适当的猜测。 最后 导学只是参考和分享,我是还原了自己在做项目时的思路历程,这并不是提交项目时应有的样子。 记得提交前一定要再重新审视一遍,调整代码,注释,修缮可视化及结论。 经过P3的历练,相信你能更自信,也更能有成就感,坚持!! 加油!!!

2018/9/8
articleCard.readMore

每周导学-第八周-TMDb数据分析

Awareness is the greatest agent for change. Hi,同学们,经过了前两周的学习,我们掌握了数据分析的基本流程、Pandas在数据分析各个流程中的基本应用以及使用matplotlib&Pandas进行可视化的技巧,那么本周我们就真刀实枪地找一套数据集练练手。本周的导学有两期,分别选用了项目三中的两个数据集(TMDb电影数据和FBI枪支数据)进行分析,只是分享思路和方法,起一个抛砖引玉的作用,大家选择其他的数据集也可以举一反三,如果有什么棘手的问题随时微信联系我就OK~ 本周开始,我们就进入到了项目三(P3)阶段,本阶段总共包含四周,在这一个月内,我们要对数据分析入门进行学习,学习数据分析思维,掌握Python数据分析及可视化方法,并使用所学知识完成项目三:探索数据集,尝试着自己完成整个数据分析的流程,得到一些饶有兴趣的结论,你一定会非常有成就感哒!那么以下便是这四周的学习安排: 时间学习重点对应课程 第1周数据分析过程-1数据分析过程&案例研究-1 第2周数据分析过程-2案例研究-1&案例研究-2 第3周完成项目项目:探索数据集 第4周项目修改与通过修改项目、查缺补漏、休息调整 !!看这里!!:在P3课程里面安排了SQL的高阶课程,但是因为在项目三中并不会涉及到SQL知识,所以为了保证大家学习的连贯性,在完成前两周的课程之后,就开始项目。至于!!SQL的高阶知识,大家可以放在课程通关后进行选修!!; 本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决: 先自行查找问题答案(注意提取关键词),参考:谷歌/百度搜索、菜鸟教程、CSDN、stackoverflow、Python for Data Analysis, 2nd Edition 、Python Cookbook 若问题未解决,请将问题及其所在课程章节发送至微信群,并@助教即可 饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧! 注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索! 本周目标 在此处挑选和你确认过眼神的数据集,并对其进行数据分析和探索,得出你自己的结论,然后进行提交。 学习计划 时间学习资源学习内容 周二微信群 - 每周导学预览每周导学 周三、周四Udacity - Classroom项目三 周五微信/Classin - 1V1课程难点 周六Classin - 优达日本周学习总结、答疑 周日笔记本总结沉淀 周一自主学习查漏补缺 项目准备 环境准备 强烈建议大家完成本地环境的搭建,在本地完成此项目。搭建本地环境的方法请参考Anaconda的安装与配置一节,完成后你将获得本项目中会用到的关键软件:Spyder和Jupyter Notebook。 文件准备 项目文件:依次进入到项目:探索数据集 –> 3.实战项目中,下载项目文件的ipynb格式。 数据集选择:在此处选择你感兴趣的数据集并下载至与项目文件相同的文件夹。(若下载失败,请微信联系我索取) 本地打开:在项目文件的文件夹下,按住Shift键,右击选择在此处打开命令窗口,输入jupyter notebook,待打开本地页面之后,选择项目文件打开,之后就请开始你的表演。 方法准备 项目文件中已经给大家列好了基本流程,所以请在开始项目之前,一定要先整体浏览一遍项目文件,着重看一下: 项目流程 每一个流程中你需要做哪些工作 每一个流程中的提示 要记得,数据分析过程不是一蹴而就的,是螺旋上升接近目标的过程,所以一定要保持耐心,对照着项目评估准则一步步完成。 另外,一开始你的notebook会显得很乱没有章法,那在提交之前最好能再修改一个整理好的版本。 项目流程(TMDb) 数据集说明 本项目选择的数据集为Kaggle提供的TMDb电影数据。此数据集中包含 1 万条电影信息,信息来源为“电影数据库”(TMDb,The Movie Database),包括用户评分和票房等。数据已进行了简单清理,涉及到的变量如下表所示: 变量名注释变量名注释 id电影序号keywords电影关键词 imdb_idimdb电影序号overview剧情摘要 popularity受欢迎程度runtime电影时长(min) budget预算($)genres电影风格 revenue收入production_companies制作公司 original_title电影名称release_date发布日期(月/日/年) cast演员表vote_count评价次数 homepage电影网址vote_average平均评分 director导演release_year发布年份 tagline宣传词budget_adj预算(考虑通胀) revenue_adj收入(考虑通胀) 提出问题 对数据简单浏览之后,你要进行角色扮演了,假如你现在就是一名电影行业的数据分析师,通过分析此数据集,你能为公司提供哪些有用的发现或者规律呢?或者你只是一名会数据分析的电影爱好者,通过分析此数据集,你能否给小伙伴们推荐一些合适的电影呢?这里提供几个参考: 电影类型相关: 哪些类型的受欢迎程度最高?随着时间推移有什么变化呢? 随着时间的推移,各类型的数量身上有什么变化呢? 哪些类型赚钱最多?投资收益比呢? 哪些类型拍摄的数量最多? 导演相关: 哪些导演最能吸金? 哪些导演的电影平均评分最稳定或者最高? 制作公司相关: 哪些公司最能赚钱?最能赚口碑?评分最稳定或者最高? 影响电影评分的要素有哪些? 影响电影收益的要素有哪些? 最近几年的电影都有哪些关键词? …… 整理好你感兴趣的问题后,那就开始吧~ 在本示例中,选择的主题为今晚有空,让好电影与你相伴,所以我们的目标就是筛选出好看的电影咯~ 导入拓展包 一般来说,就导入如下几个拓展包就够了,当然如果后续操作中还需导入其他包的话,再补充即可。 1 2 3 4 5 6 7 8 9 10 11 12 13 # 用这个框对你计划使用的所有数据包进行设置 # 导入语句。 import pandas as pd import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt import seaborn as sns # 务必包含一个‘magic word’,以便将你的视图与 notebook 保持一致。 %matplotlib inline #关于更多信息,请访问该网页: # http://ipython.readthedocs.io/en/stable/interactive/magics.html 数据整理 导入数据 1 2 df = pd.read_csv('tmdb-movies.csv') df.head(3) 评估数据 列及数据类型 1 df.info() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <class 'pandas.core.frame.DataFrame'> RangeIndex: 10866 entries, 0 to 10865 Data columns (total 21 columns): id 10866 non-null int64 imdb_id 10856 non-null object popularity 10866 non-null float64 budget 10866 non-null int64 revenue 10866 non-null int64 original_title 10866 non-null object cast 10790 non-null object homepage 2936 non-null object director 10822 non-null object tagline 8042 non-null object keywords 9373 non-null object overview 10862 non-null object runtime 10866 non-null int64 genres 10843 non-null object production_companies 9836 non-null object release_date 10866 non-null object vote_count 10866 non-null int64 vote_average 10866 non-null float64 release_year 10866 non-null int64 budget_adj 10866 non-null float64 revenue_adj 10866 non-null float64 dtypes: float64(4), int64(6), object(11) memory usage: 1.7+ MB 纵然了一下,各列的数据类型没什么问题,唯一一个可能有问题的是release_date列,应该是datetime类型,但因为我们后面的分析中只会用到电影的上映年份,也就是release_year列,所以这列不处理也罢。 查看各列的缺失值情况 1 df.isnull().sum() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 id 0 imdb_id 10 popularity 0 budget 0 revenue 0 original_title 0 cast 76 homepage 7930 director 44 tagline 2824 keywords 1493 overview 4 runtime 0 genres 23 production_companies 1030 release_date 0 vote_count 0 vote_average 0 release_year 0 budget_adj 0 revenue_adj 0 可见数据集的情况很不错,几个关键列几乎没有缺失。至于director列的缺失,你可以依照电影标题去搜索它的导演,然后进行填充,或者干脆直接删除掉。 查看重复值 1 sum(df.duplicated()) 1 1 有一行重复数据,过会儿直接清理掉。 查看基本数据统计情况 1 df.describe() 因为这是在数据评估阶段,所以着重看min和max,检查是否有异常值。本数据集中没什么问题。 查看各列元素 1 df['column_name'] 可以查看各列的详细情况,避免因为折叠而忽略了某些严重问题。 比如说,我们通过查看各列情况,发现cast、keywords、genres和production_companies这四列中的都包含有以|分隔开的多个平级元素,这在进行之后的按类分析时会非常不便,所以需要清理。(但也不是这四列都要清理,只用清理你的分析中会用到的就行。) 还有就是budget_adj和revenue_adj两列是科学记数法,在进行可视化的时候,坐标轴的显示肯定就会很丑,到时候要注意处理。 清理数据 清理数据就是对上一步中发现的问题进行清理,并且删除无关列,最终得到的是一个方便你进行分析及可视化的干净数据。 清理前记得备份数据 数据备份 1 df_clean = df.copy() 删除无关列 在本次示例项目中,我们的目的是找出好看的电影,所以评分和受欢迎程度是关键参数,然后再探索下他们与其他参数之间是否存在联系。 那就按照如下方法删除一些无关列(其实是筛选出想要的列,顺便再拍一下序): 1 df = df[['original_title','production_companies','director','cast','genres','keywords','runtime','popularity','vote_count','vote_average','release_year','budget_adj','revenue_adj']] 缺失值的处理 因为关键列并没有出现数据缺失,所以并未进行处理。 删除重复值 1 df.drop_duplicates(inplace = True) genres列处理 电影类型是关键筛选条件,所以要细分。 1 2 #将genres列转为str格式(因为NaN是float格式的) df_clean.genres = df_clean.genres.astype(str) 1 2 3 4 #获取所有的电影类型 genres_set = set() #定义空集合 for x in df_clean['genres']: genres_set.update(x.split('|')) 1 2 #从genres_set中删除nan genres_set.remove('nan') 1 2 3 #将各电影类型作为列添加到数据集中,并用1表示‘是’,0表示‘否’ for genres in genres_set: df_clean[genres] = df_clean['genres'].str.contains(genres).apply(lambda x:1 if x else 0) 1 2 3 #删除genres列,并检查 df_clean.drop('genres',axis = 1,inplace = True) df_clean.head(3) production_companies列处理 属于电影的参考列,所以我们只筛选首公司。 1 2 #只筛选第一家主要投资的公司 df_clean.production_companies = df_clean.production_companies.str.split('|').str[0] 1 2 #为了符合逻辑,更改列名 df_clean.rename(columns = {'production_companies':'production_company'},inplace = True) cast列处理 演员也是电影的参考列,只筛选出两名主演。 1 2 3 4 5 #筛选前两位主演 df_clean['major_actor_1'] = df_clean.cast.str.split('|').str[0] df_clean['major_actor_2'] = df_clean.cast.str.split('|').str[1] #删除cast列 df_clean.drop('cast',axis = 1,inplace = True) 添加income_adj列 原数据中只有budget_adj和revenue_adj列,后者减去前者即为电影的收益。 1 df_clean['income_adj'] = df_clean['revenue_adj'] - df_clean['budget_adj'] 至此,清理数据告一段落。 探索性数据分析 在这个阶段你可以随意做可视化,尽可能多得去探索你想解决的问题。在探索阶段,作图可以不用很规范,你自己知道是什么意思就可以,而且可能会有些探索的问题结果意义不大,所以在提交项目时,要进行择优保留并对其润色修饰。 探索受欢迎程度及评分 电影的受欢迎程度和平均评分是我们在进行电影推荐时的主要参考,所以我们先来观察下这两列的主要分布情况以及与其他列的相关性。 分布情况 1 2 3 4 #受欢迎程度的分布情况 df_clean['popularity'].plot(kind = 'hist',bins = 200,title = 'The Distribution of Popularity(log)',logx = True,figsize = (8,6))#这里采用了x轴的对数坐标,考虑下为什么呢? plt.ylabel('Count of Movies') plt.xlabel('Popularity(log)'); 1 2 3 4 #平均评分的分布情况 df_clean['vote_average'].plot(kind = 'hist',bins = 30,title = 'The Distribution of Average Rating',figsize = (8,6))#这里就是用的普通的x轴坐标,为什么呢? plt.ylabel('Count of Movies') plt.xlabel('Average Rating'); 通过观察这两幅图我们可以发现:绝大部分的电影受欢迎程度都在10以下,平均评分却是一个类正态分布,电影评分集中在5到7之间。 与上映年份的关系 1 2 3 #受欢迎程度 df_clean.groupby('release_year')['popularity'].mean().plot(kind = 'line') plt.hlines(df_clean['popularity'].quantile(.75),xmin = 1960,xmax = 2015,color = 'red'); 1 2 3 #评分 df_clean.groupby('release_year')['vote_average'].mean().plot(kind = 'line') plt.hlines(df_clean['vote_average'].quantile(.75),xmin = 1960,xmax = 2015,color = 'red'); 通过观察这两幅可视化,我们发现:随着上映日期逐渐接近现在,受欢迎程度呈波动上升趋势,但是评分却是波动下降。这应该是因为年代越久远的电影观看人数越少,评分次数也就越少(需附图验证),个别的高评分对平均评分的影响也就越大,这才导致了受欢迎程度低却评分高的现象。 与其他数值型变量的关系 本数据集中的数值型变量不是很多,但要是一对一对的去看他们之间的相关性会很累,懒人智者推动科技进步嘛,前辈们帮我们都考虑好了,可以参考下面的代码: 1 2 #筛选出数值变量 df_corr = df_clean[['runtime','popularity','vote_count','vote_average','budget_adj','revenue_adj','income_adj']] 各变量之间相关性的热度图 1 2 3 4 5 fig, ax = plt.subplots(figsize=(10, 6)) corr = df_corr.corr() #计算相关性 hm = sns.heatmap(round(corr,2), annot=True, ax=ax, cmap="coolwarm",fmt='.2f', linewidths=.05) fig.subplots_adjust(top=0.93) fig.suptitle('Movie Attributes Correlation Heatmap', fontsize=14); 从这幅图里面,可以很明显的读出一些信息: 受欢迎程度与评分人数有较强的正相关关系,与收益的正相关程度也稍强,这很好理解; 平均评分却鲜有相关的变量,那影响评分的因素都有哪些呢?(导演?主演?制片公司?) pairplot 你不满足于只看冷冰冰的数字,想看到更直观的散点图或者直方图,那就请参考如下代码: 1 2 3 4 5 pp = sns.pairplot(df_corr, size=1.8, aspect=1.8, plot_kws=dict(edgecolor="k", linewidth=0.5), diag_kind="kde", diag_kws=dict(shade=True)) fig = pp.fig fig.subplots_adjust(top=0.93, wspace=0.3) t = fig.suptitle('Movie Attributes Pairwise Plots', fontsize=14) 从上面这幅可视化中,我们不仅能看到各变量两两之间的散点图(相关性),还能看到各变量的分布情况,真可谓是大杀器。 那,热度与评分和其他分类变量有没有什么关系呢? …(请继续探索) … KEEP GOING 电影推荐 在做电影推荐时,受欢迎程度和评分是我们的关键评估指标。 按电影类型推荐 比如说,你有一个哥们比较喜欢看Adventure类的电影,听说你在做TMDb的电影数据分析,所以来找你推荐,你会推荐哪些呢? 1 2 #首先我们要筛选出Adventure类的电影 df_Ad = df_clean[df_clean['Adventure'] == 1] 1 2 3 #既然是推荐,自然要筛选一些热门的评分高的电影,所以这里我们选择了好于其他90%的电影(结果为15部电影) df_Ad_po = df_Ad[df_Ad.popularity > df_Ad.popularity.quantile(.9)] df_Ad_po_vo = df_Ad_po[df_Ad_po.vote_average > df_Ad_po.vote_average.quantile(.9)] 1 2 #排序 df_Ad_po_vo.sort_values(by = 'popularity',inplace = True) 1 2 3 4 5 6 7 8 #可视化 sns.set(style="white")#小美化一下 x = df_Ad_po_vo.original_title y = df_Ad_po_vo['popularity'] #排序能让可视化更美观 plt.yticks(np.arange(len(x)), x) plt.barh(np.arange(len(x)),y); 结论立马就出来了,首推的电影就是Interstellar(星际穿越)。当然这种方法可以定义成一个函数,参数即为电影类型,这样就能省心省力的得到所有电影的最热最佳推荐了。 当然,你还可以尝试: 按导演推荐 我一开始想着用groupby直接按照导演分类,然后求评分的均值再作图,可是结果并不如人意。 1 df_clean.groupby('director')['vote_average'].mean().sort_values()[-15:].plot(kind = 'barh',color = 'b'); 这些导演好像都不是很熟悉,应该是数据集中只收录了一部或者很少的电影作品,然而又因为这些作品的评分较高,才导致这种情况,所以我们要先对导演做一个筛选,比如说,筛选出收入作品数量在10部及以上的导演。 1 2 3 4 5 6 7 #先对原数据中的director列作计数统计,然后筛选大于等于10的数据存为一个新的DataFrame(目的是为了方便筛选) df_director = pd.DataFrame(df_clean.director.value_counts() >= 10) #将10部及以上作品的导演存为一个列表 directors = list(df_director[df_director['director']].index) #然后使用isin函数,筛选原数据中在directors列表中的导演,并求均值作图 #平均评分 df_clean[df_clean.director.isin(directors)].groupby('director')['vote_average'].mean().sort_values()[-10:].plot(kind = 'barh',color = 'b'); 1 2 #受欢迎程度 df_clean[df_clean.director.isin(directors)].groupby('director')['popularity'].mean().sort_values()[-10:].plot(kind = 'barh',color = 'b'); 这次得到的结果更大众一些,出现的导演名字也基本都听过。Christopher Nolan和Quentin分别获得了双料榜首和榜眼,这两个人的名字也算是电影的品质保证了吧。 按主演推荐 按制片公司推荐 … … 当然,你还可以分析电影评分与其他变量的相关性,或者从效益角度出发,去分析票房、预算、收益等等。但万变不离其宗,用数据分析的流程做指导,所学知识为基础,Bing或者Google为利剑(搜索的时间可能要占到一半以上,所以不要慌,搜索完记在小本本上),开始你的项目三征服之路吧! 得出结论 对你整理好的可视化图像进行总结,结论要有根有据但也不要只是停留在描述,可以进行适当的猜测。 最后 导学只是参考和分享,我是还原了自己在做项目时的思路历程,这并不是提交项目时应有的样子。 记得提交前一定要再重新审视一遍,调整代码,注释,修缮可视化及结论。 经过P3的历练,相信你能更自信,也更能有成就感,坚持!! 加油!!!

2018/9/5
articleCard.readMore

每周导学-第七周-Matplotlib可视化

If you don’t like where you are , change it. You’re not a tree. Hi,同学们,上一周我们学习了数据分析的基本流程,以及Pandas在数据分析各个流程中的应用,本周呢就是在上周的基础上,掌握Python数据分析可视化的基础知识,包括matplotlib及pandas可视化。可视化是数据分析的重要环节,是你进行探索性数据分析、得出结论、传达结果的关键,所以,一定的可视化技巧是非常必须的,除了本章涉及到的两个知识点外,我还会在最后提供一些其他的python可视化库链接和其他可视化软件的链接,希望大家能不满足于导学,而去积极求索,加油!! 本周开始,我们就进入到了项目三(P3)阶段,本阶段总共包含四周,在这一个月内,我们要对数据分析入门进行学习,学习数据分析思维,掌握Python数据分析及可视化方法,并使用所学知识完成项目三:探索数据集,尝试着自己完成整个数据分析的流程,得到一些饶有兴趣的结论,你一定会非常有成就感哒!那么以下便是这四周的学习安排: 时间学习重点对应课程 第1周数据分析过程-1数据分析过程&案例研究-1 第2周数据分析过程-2案例研究-1&案例研究-2 第3周完成项目项目:探索数据集 第4周项目修改与通过修改项目、查缺补漏、休息调整 !!看这里!!:在P3课程里面安排了SQL的高阶课程,但是因为在项目三中并不会涉及到SQL知识,所以为了保证大家学习的连贯性,在完成前两周的课程之后,就开始项目。至于!!SQL的高阶知识,大家可以放在课程通关后进行选修!!; 本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决: 先自行查找问题答案(注意提取关键词),参考:谷歌/百度搜索、菜鸟教程、CSDN、stackoverflow、Python for Data Analysis, 2nd Edition 、Python Cookbook 若问题未解决,请将问题及其所在课程章节发送至微信群,并@助教即可 饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧! 注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索! 本周目标 学习总结课程中数据分析过程及案例研究1&2中所用到的可视化知识,掌握可视化在数据分析中的应用。 学习计划 时间学习资源学习内容 周二微信群 - 每周导学预览每周导学 周三、周四Udacity - Classroom案例研究1&2 周五微信/Classin - 1V1课程难点 周六Classin - 优达日本周学习总结、答疑 周日笔记本总结沉淀 周一自主学习查漏补缺 本周知识清单 matplotlib matplotlib是Python泰斗级别的绘图库,因受到Matlab的启发构建而成,所以你会觉得它的命令API,还有那九十年代感强烈的可视化图像跟matlab很相似。它非常适合在jupyter notebook中交互式作图,这个库“功能非常强大”,但也“非常复杂”,所以这里只能介绍matplotlib的一些基础和常用的方法,想了解更多就需要你自主探索啦! 导入matplotlib 1 import matplotlib.pyplot as plt 在notebook中使用 1 2 #想在Jupyter Notebook中顺利显示出可视化图像,你需要添加如下代码 %matplotlib inline 官方链接 你可以点击matplotlib.pyplot搜索查看一些函数的说明和用法;或者你可以点击Pyplot Gallery查看一些代码实例,找到灵感。 基本概念 在使用matplotlib生成图像时,整个图像为一个Figure对象。在Figure对象中可以包含一个,或者多个Axes对象。每个Axes对象都是一个拥有自己坐标系统的绘图区域。其逻辑关系如下: 在如下的单图fig中,我们给出了我们的绘图中只有一个坐标系区域(也就是ax),此外还有以下对象: Data: 数据区,包括数据点、描绘形状 Axis: 坐标轴,包括 X 轴、 Y 轴及其标签、刻度尺及其标签 Title: 标题,数据图的描述 Legend: 图例,区分图中包含的多种曲线或不同分类的数据 其他的还有图形文本 (Text)、注解 (Annotate)等其他描述 各个对象之间的隶属关系如下图所示: 所以大家在之后进行可视化的时候,根据这些隶属关系来去对参数进行设置,这样逻辑不乱,代码也清晰。 常用参数设置 开始绘图 在绘图前,首先需要设置的就是fig(画布)和ax(图),我们主要通过plt.subplots()函数来定义 1 2 #绘制单图 fig, ax = plt.subplots() 1 2 #绘制多图,subplots的第一个参数为行数,第二个参数为列数 fig,(ax1,ax2) = plt.subplots(1,2,sharey = True)#设置共享y轴 1 2 #绘制多图时,注意前面的变量为一个矩阵的形式,如下前面为2x2矩阵,则后面subplots的行列参数也应该都为2 fig,((ax1,ax2),(ax3,ax4)) = plt.subplots(2,2,sharex = True)#设置共享x轴 另一种添加子图的方法 绘制子图主要使用的函数为:add_subplot(abc),调用该函数会生成一个包含axb个子图的画布,而c则表示位置,按照从左至右,从上至下的顺序依次排列。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 x = np.arange(1,100) fig = plt.figure() #定义画布 ax1 = fig.add_subplot(221) # 定义2*2个子图(1表示左一) ax1.plot(x,x) # 绘制左一折线图 ax2 = fig.add_subplot(222) ax2.plot(x,-x) # 绘制右一折线图(右一) ax3 = fig.add_subplot(223) ax3.plot(x,x*x) # 绘制左二折线图(左二) ax4 = fig.add_subplot(224) ax4.plot(x,np.log(x)); # 绘制右二折线图(右二),添加分号可以只显示图像 坐标轴设置 调整范围 主要是用来利用调整坐标轴范围进行图像的截取,可以使用ax.axis()函数,也可使用plt.xlim()或者plt.ylim()函数,具体用法如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #ax.axis([0,10,0,50]) [x左,x右,y下,y上] x = np.arange(-10,10,0.1) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(x,x**2) ax.axis([0,10,0,50]) #plt.xlim([0,10]) ,调整x轴坐标范围 #plt.ylim([0,50]) ,调整y轴坐标范围 fig1 = plt.figure() ax1 = fig1.add_subplot(111) ax1.plot(x,x**2) plt.xlim([0,10]) plt.ylim([0,50]); 坐标轴刻度调整 1 2 3 4 5 6 7 8 9 10 #利用ax.locator_params()设置刻度间隔 x = np.arange(0,11,0.1) fig1 = plt.figure() ax1 = fig1.add_subplot(111) ax1.plot(x,x) #ax1.locator_params(nbins=20) #同时调整x轴与y轴 #ax1.locator_params('x',nbins=20) #只调整x轴 ax1.locator_params('y',nbins=20) #只调整y轴 plt.axis([0,10,0,10]); 1 2 #利用plt.xticks()设置x轴刻度顺序/旋转角度 plt.xticks([0,2,3,1,4], ['Tom', 'Dick', 'Harry', 'Sally', 'Sue'], rotation=30); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #时间刻度调整 import datetime import matplotlib as mpl start = datetime.datetime(2018,7,1) stop = datetime.datetime(2018,8,1) delta = datetime.timedelta(days=1) dates = mpl.dates.drange(start,stop,delta) y = np.random.rand(len(dates)) fig2 = plt.figure() ax2 = fig2.add_subplot(111) ax2.plot_date(dates,y,linestyle='-',marker='') #日期格式调整,关键代码 date_format= mpl.dates.DateFormatter('%Y-%m-%d') ax2.xaxis.set_major_formatter(date_format) fig2.autofmt_xdate();#防止刻度重叠 双轴 有时候想要在同一张图中显示两种不同范围的变量,这时候就要设置双轴 双轴的关键代码为twinx()函数(也就是双胞胎x轴?) 1 2 3 4 5 6 7 8 9 10 11 12 x = np.arange(1,11,0.1) y1 = x*x y2 = np.log(x) fig1 = plt.figure() ax1 = fig1.add_subplot(111) plt.ylabel('Y1') ax2 = ax1.twinx()#关键代码 plt.ylabel('Y2',rotation=270)#注意添加ylabel的顺序不能错,旋转显示 ax1.plot(x,y1) ax2.plot(x,y2,'--r'); 标题与轴标题 标题与轴标题都是一幅可视化图像中的必须要素。你可以参考如下示例来设置你的标题与轴标题。 示例: 1 2 3 4 5 6 7 8 9 plt.title('This is title',color = 'r',fontsize = 17) plt.xlabel('This is xlabel') plt.ylabel('This is ylabel'); ##其等效于: # fig,ax = plt.subplots() # ax.set_title('This is title',color = 'r',fontsize = 17) # ax.set_xlabel('This is xlabel') # ax.set_ylabel('This is xlabel'); 图例 图例在进行多变量比较的可视化中必不可少。你可以通过在plot()函数中添加参数’label’来对所绘曲线设置图例 1 2 3 4 5 6 7 x = np.arange(1,11,1) fig = plt.figure() ax = fig.add_subplot(111) line1 = ax.plot(x,x*2,label='Bad') line2 = ax.plot(x,x*3,label='Normal') line3 = ax.plot(x,x*4,label='Good') plt.legend(loc='best'); 也可以通过调用plt.legend()函数对图例进行设置。 1 2 3 4 5 6 7 8 x = np.arange(1,11,1) fig = plt.figure() ax = fig.add_subplot(111) line1, = ax.plot(x,x*2) #注意line1后面的逗号,不可缺少 line2, = ax.plot(x,x*3) line3, = ax.plot(x,x*4) plt.legend(handles = [line1, line2, line3],labels = ['Bad', 'Normal', 'Good'],loc = 'best'); 颜色与样式 调用matplotlib.pyplot.plot函数即可设置所画图像的颜色与样式,设置方法如下: 1 plt.plot(x,y,'[color][marker][line]') 常用颜色 字符颜色字符颜色 b蓝色g绿色 r红色y黄色 c青色k黑色 m洋红色w白色 #rrggbbRGB颜色0.7灰度值 常用线条样式 字符描述字符描述 ‘-‘实线‘:’虚线(·······) ‘–’虚线(——)‘None’或’ ‘或’’什么都不画 ‘-.’点划线 线条标记 字符描述字符描述 ‘o’圆圈‘.’点 ‘D’菱形‘s’正方形 ‘h’六边形1‘*’星号 ‘H’六边形2‘d’小菱形 ‘_’水平线‘v’一角朝下的三角形 ‘8’八边形‘<’一角朝左的三角形 ‘p’五边形‘>’一角朝右的三角形 ‘,’像素‘^’一角朝上的三角形 ‘+’加号‘\‘竖线 ‘None’,’’,’ ‘无‘x’X 示例: 1 2 3 4 5 6 fig,ax = plt.subplots() y=np.arange(1,5) ax.plot(y,'cx--') ax.plot(y+1,'kp:') ax.plot(y+2,'mo-.'); 网格 也就是可视化图像中的网格,可以方便读者快速估取某点的横纵坐标。我们通过调用plt.grid()函数来对启用网格。一般情况下,使用该函数的默认参数即可 1 2 3 4 5 6 7 #采用默认参数 x= np.arange(1,10,0.1) fig1 = plt.figure() ax1 = fig1.add_subplot(111) ax1.grid() ax1.plot(x,np.log(x)) plt.show() 但你也可以通过如下方式进行设置。 1 2 3 4 5 6 7 y = np.arange(1,5,0.1) plt.plot(y,y**2) plt.grid(color='r',linestyle=':',linewidth='2') # color 设置网格的颜色(颜色与样式中的均可用) # linestyle 设置线显示的类型(一共四种即'-','--','-.',':') # linewidth 设置网格线宽 plt.show() 添加图中注释 有时候你需要为可视化图中的某个关键点做出注释,方便读者能一眼看出,这时候你就需要调用plt.annote()函数来实现你的目的了。 该函数中几个关键的参数分别为: str:一个字符串,来写出你想要标注的内容; xy:标注点的坐标 xytext:标注内容起始位置的坐标(也就是从该点开始显示你的注释内容) arrowprops:设置注释指向标注点的箭头 facecolor:箭头颜色 width:箭头宽度 headlength:箭头头部长度(单位为磅) headwidth:箭头头部宽度 你也可以去搜索该函数,获取更多参数的设置方法。 示例: 1 2 3 4 5 6 7 8 x =np.arange(-10,11,1) y = x*x fig1 = plt.figure() ax1 = fig1.add_subplot(111) ax1.plot(x,y) ax1.annotate('this is minimum',xy=(0,0),xytext=(-1.5,20), arrowprops=dict(facecolor='r',headlength=10)); 添加平行于坐标轴的线 你可能需要添加一条平行于x轴或者是y轴的线,在图像中分割不同区域。这时候,你就需要调用vlines(x, ymin, ymax)函数或者是hlines(y, xmin, xmax)函数,除了括号内的参数之外,你还可以设置颜色(color)参数和线型(linestyles)参数。(设置方法参考颜色与样式章节) 示例: 1 2 plt.vlines(0, 0, 0.5, colors = "c", linestyles = "--"); plt.hlines(0.25, -0.04, 0.04, colors = "r", linestyles = "-."); 常用图形 可视化图形参考 如何能选择最适合的图形来表示你想分析的结果呢?这里提供一个简单的参考~ 散点图(scatter) 1 2 3 4 5 6 7 8 9 np.random.seed(7)#设置随机种子,可以保证每次的随机数是一致的 N = 50 x = np.random.rand(N)#生成50个0到1的随机数 y = np.random.rand(N) colors = np.random.rand(N) area = (30 * np.random.rand(N))**2 #随便设置的一个计算值,来表示大小 plt.scatter(x, y, s=area, c=colors, alpha=0.5);#用s设置大小区分,用c设置颜色区分 条形图(bar) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #例1 #函数使用包 from matplotlib.ticker import FuncFormatter x = np.arange(4) money = [1.5e5, 2.5e6, 5.5e6, 2.0e7] def millions(x, pos): '''定义一个函数,将科学记数法转为以million为单位,保留一位小数,并添加美元$和单位M; 两个参数分别表示导入的值和位置。''' return '$%.1fM' % (x * 1e-6) formatter = FuncFormatter(millions)#调用函数,将millions函数作为模块化函数 fig, ax = plt.subplots() ax.yaxis.set_major_formatter(formatter)#设置y轴按函数模块化 plt.bar(x, money) plt.xticks(x, ('Bill', 'Fred', 'Mary', 'Sue')); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #例2 横向柱形图 x = np.arange(4) money = [1.5e5, 2.5e6, 5.5e6, 2.0e7] def millions(x, pos): '''定义一个函数,将科学记数法转为以million为单位,保留一位小数,并添加美元$和单位M; 两个参数分别表示导入的值和位置。''' return '$%.1fM' % (x * 1e-6) formatter = FuncFormatter(millions)#调用函数,将millions函数作为模块化函数 fig, ax = plt.subplots() ax.xaxis.set_major_formatter(formatter) plt.barh(x, money)#关键代码:barh plt.yticks(x, ('Bill', 'Fred', 'Mary', 'Sue')); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #例3 拼接柱状图 N = 5 menMeans = (20, 35, 30, 35, 27) womenMeans = (25, 32, 34, 20, 25) ind = np.arange(N) # 等效于[0,1,2,3,4] width = 0.35 # 柱的宽度 p1 = plt.bar(ind, menMeans, width) p2 = plt.bar(ind, womenMeans, width,bottom=menMeans) #关键代码:bottom plt.ylabel('Scores') plt.title('Scores by group and gender') plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5')) plt.yticks(np.arange(0, 81, 10)) plt.legend((p1, p2), ('Men', 'Women')); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #例4 并列柱状图 N = 5 menMeans = (20, 35, 30, 35, 27) womenMeans = (25, 32, 34, 20, 25) ind = np.arange(N) width = 0.35 p1 = plt.bar(ind-width/2, menMeans, width) #关键代码 -width/2,也就是将柱子向左移动了width/2 p2 = plt.bar(ind+width/2, womenMeans, width) #关键代码 +width/2 plt.ylabel('Scores') plt.title('Scores by group and gender') plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5')) plt.yticks(np.arange(0, 81, 10)) plt.legend((p1[0], p2[0]), ('Men', 'Women')); 直方图(hist) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fig = plt.figure() ax1 = fig.add_subplot(221) ax2 = fig.add_subplot(222) ax3 = fig.add_subplot(212) mu = 100 #定义均值 sigma = 20 #定义标准差 x = mu +sigma * np.random.randn(2000) #生成一个标准正态分布函数 ax1.hist(x,bins=10,color='green',normed=True) #输入数据,bins=总共有几条条状图,color=颜色,normed=True:图形面积之和为1 ax2.hist(x,bins=50,color='red',normed=False) #normed=False:纵坐标显示实际值 x = np.random.randn(1000)+2 y = np.random.randn(1000)+3 ax3.hist2d(x,y,bins=10); #二维直方图 饼状图(pie) 1 2 3 4 5 6 7 labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' sizes = [15, 30, 45, 10] #占比 explode = (0, 0.1, 0, 0) #设置第二位也就是‘Hogs’凸显,间距为0.1 fig1, ax1 = plt.subplots() ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',shadow=True, startangle=90)#autopct对输出进行格式化,startangle为起始角度,一般设置为90比较好看 ax1.axis('equal');#保证为正圆 箱线图(box) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 fig = plt.figure() ax1 = fig.add_subplot(211) ax2 = fig.add_subplot(212) data = np.random.normal(size=1000, loc=0.0, scale=1.0) ax1.boxplot(data,sym='o',whis=1.5) # plt.boxplot(x, notch=None, sym=None, vert=None, whis=None, positions=None, widths=None, patch_artist=None, meanline=None, showmeans=None, showcaps=None, showbox=None, showfliers=None, boxprops=None, labels=None, flierprops=None, medianprops=None, meanprops=None, capprops=None, whiskerprops=None) # x:指定要绘制箱线图的数据; # notch:是否是凹口的形式展现箱线图,默认非凹口; # sym:指定异常点的形状,默认为+号显示; # vert:是否需要将箱线图垂直摆放,默认垂直摆放; # whis:指定上下须与上下四分位的距离,默认为1.5倍的四分位差; # positions:指定箱线图的位置,默认为[0,1,2…]; # widths:指定箱线图的宽度,默认为0.5; # patch_artist:是否填充箱体的颜色; # meanline:是否用线的形式表示均值,默认用点来表示; # showmeans:是否显示均值,默认不显示; # showcaps:是否显示箱线图顶端和末端的两条线,默认显示; # showbox:是否显示箱线图的箱体,默认显示; # showfliers:是否显示异常值,默认显示; # boxprops:设置箱体的属性,如边框色,填充色等; # labels:为箱线图添加标签,类似于图例的作用; # filerprops:设置异常值的属性,如异常点的形状、大小、填充色等; # medianprops:设置中位数的属性,如线的类型、粗细等; # meanprops:设置均值的属性,如点的大小、颜色等; # capprops:设置箱线图顶端和末端线条的属性,如颜色、粗细等; # whiskerprops:设置须的属性,如颜色、粗细、线的类型等; data = np.random.normal(size=(100, 4), loc=0.0, scale=1.0) labels = ['A','B','C','D'] ax2.boxplot(data, labels=labels); 散点直方图(scatter hist) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 x = np.random.randn(200) y = x + np.random.randn(200)*0.5 #定义坐标轴参数 margin_border = 0.1 width = 0.6 margin_between = 0.02 height = 0.2 #散点图参数 left_s = margin_border #距左边框距离 bottom_s = margin_border #距底部距离 height_s = width #散点图高度 width_s = width #散点图宽度 #顶部直方图参数 left_x = margin_border #距左边框距离 bottom_x = margin_border+width+margin_between #距底部距离 = 散点图距底部距离+散点图高度+散点图与直方图的间距 height_x = height #直方图高度 width_x = width #直方图宽度 left_y = margin_border+width+margin_between bottom_y = margin_border height_y = width width_y = height plt.figure(1,figsize=(8,8)) rect_s = [left_s,bottom_s,width_s,height_s] rect_x = [left_x,bottom_x,width_x,height_x] rect_y = [left_y,bottom_y,width_y,height_y] # 开始按照定义的尺寸绘图 axScatter = plt.axes(rect_s) axHisX = plt.axes(rect_x) axHisY = plt.axes(rect_y) axHisX.set_xticks([])#取消顶部直方图的x轴刻度显示 axHisY.set_yticks([])#取消右侧直方图的y轴刻度显示 #绘制散点图 axScatter.scatter(x,y) #设定边界 bin_width = 0.25 xymax = np.max([np.max(np.fabs(x)),np.max(np.fabs(y))])#取出x与y中最大的绝对值 lim =int(xymax/bin_width+1) * bin_width axScatter.set_xlim(-lim,lim) axScatter.set_ylim(-lim,lim) bins = np.arange(-lim,lim+bin_width,bin_width) axHisX.hist(x,bins=bins) axHisY.hist(y,bins=bins,orientation='horizontal')#水平作图 axHisX.set_xlim(axScatter.get_xlim()) axHisY.set_ylim(axScatter.get_ylim()); 其他 保存图像到本地 参考如下代码: 1 2 3 4 #保存至当下路径 fig.savefig('test.jpg'); #保存至其他路径 fig.savefig('E:/DAND/DAND_VIP/test.jpg'); 显示中文 使用matplotlib做可视化不能显示中文,根本原因是因为官方配置中没有中文字体,所以,我们把中文字体添加进去就ok啦。具体方法如下: 1 2 #coding:utf-8 plt.rcParams['font.sans-serif']=['simhei']#simhei为‘黑体’ 示例: 1 2 3 4 5 6 7 8 9 10 11 12 x = np.arange(1,11,1) fig = plt.figure() ax = fig.add_subplot(111) line1 = ax.plot(x,-x*2,label='优') line2 = ax.plot(x,-x*3,label='良') line3 = ax.plot(x,-x*4,label='差') plt.legend(loc='best') plt.title('标题',color = 'r',fontsize = 17) plt.xlabel('x轴',fontsize = 13) plt.ylabel('-y轴',fontsize = 13); 坐标轴显示负号 有可能你做得可视化图像中,坐标轴的符号显示一个框框,这时候你添加如下设置即可。 1 plt.rcParams['axes.unicode_minus']=False Pandas Plot pandas plot函数是基于matplotlib的一个在pandas中快速绘图的方法,用法简单,而且兼容所有matplotlib属性设置的函数,所以,你可以用pandas plot函数来绘图,然后调用matplotlib中的函数对可视化图形进行设置,最终达到你心中的预期。 官方链接 pandas.DataFrame.plot 常用参数设置 data:你可以直接调取DataFrame作为参数输入 x:x轴数据 y:y轴数据 kind:绘图类型 line :折线图 bar :条形图 barh:水平条形图 hist:直方图 box:箱线图 kde:就是在条形图的基础上添加了概率密度曲线 area :相当于填充面积的折线图 pie:饼状图 scatter:散点图 hexbin:热度图 其余参数与matplotlib的参数设置类似,这里不再赘述。 总结 matplotlib是python可视化的鼻祖,绘图全面,多功能是他的优点,几乎没有他不能完成的可视化任务; 但是,他的缺点也很明显,比如:可视化图形配色丑;参数太多,设置琐碎;没有交互式。。。 所以针对这些问题,后人们又开发了许多python的可视化包,比如说:以美观、简洁著称的seaborn、做交互式的plotly、pyecharts等等,后续我看时间允许的话,再出一些教程,大家也可以按需去官网学习,主要是看给出的示例,看关键代码,自己多总结。 项目相关 P3的项目需要你完完整整得过一遍数据分析的过程,所以呢,单独的某一个数据集肯定满足不了大家,贴心的Udacity给大家准备了几个数据集备选,戳数据集预览,挑一个自己感兴趣的先~ 参考 matplotlib绘图基础

2018/8/28
articleCard.readMore