预备知识-python核心用法常用数据分析库(下)
Posted lmandcc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了预备知识-python核心用法常用数据分析库(下)相关的知识,希望对你有一定的参考价值。
2、预备知识-python核心用法常用数据分析库(下)
概述
Python 是当今世界最热门的编程语言,而它最大的应用领域之一就是数据分析。在python众多数据分析工具中,pandas是python中非常常用的数据分析库,在数据分析,机器学习,深度学习等领域经常被使用。使用 Pandas 我们可以 Excel/CSV/TXT/mysql 等数据读取,然后进行各种清洗、过滤、透视、聚合分析,也可以直接绘制折线图、饼图等数据分析图表,在功能上它能够实现自动化的对大文件处理,能够实现 Excel 的几乎所有功能并且更加强大。
本实验将通过实战的方式,介绍pandas数据分析库的基本使用,让大家在短时间内快速掌握python的数据分析库pandas的使用,为后续项目编码做知识储备
实验环境
- Python 3.7
- Pycharm
任务二:Pandas数据分析实战-1
【任务目标】
本任务主要目标为使用pandas进行数据分析实战,在实战过程中带大家了解pandas模块的一下功能:
- 了解数据
- 分析数据问题
- 清洗数据
- 整合代码
【任务步骤】
1、准备工作
打开CMD窗口后,执行如下命令,打开jupyter notebook编辑器
jupyter notebook
成功执行以上命令后,系统将自动打开默认浏览器,如下图所示:
成功打开浏览器后,按如下流程创建 notebook 文件
对新建notebook进行重命名操作
2、notebook 文件新建完成后,接下来在新建的 notebook 中编写代码
- 了解数据
在处理任何数据之前,我们的第一任务是理解数据以及数据是干什么用的。我们尝试去理解数据的列/行、记录、数据格式、语义错误、缺失的条目以及错误的格式,这样我们就可以大概了解数据分析之前要做哪些“清理”工作。
本次我们需要一个 patient_heart_rate.csv 的数据文件,这个数据很小,可以让我们一目了然。这个数据是 csv 格式。数据是描述不同个体在不同时间的心跳情况。数据的列信息包括人的年龄、体重、性别和不同时间的心率。
- 加载数据即查看数据集
import pandas as pd
df = pd.read_csv(\'data/patient_heart_rate.csv\')
df.head()
运行结果如下:
分析数据问题
- 没有列头
- 一个列有多个参数
- 列数据的单位不统一
- 缺失值
- 重复数据
- 非 ASCII 字符
- 有些列头应该是数据,而不应该是列名参数
3、清洗数据
3.1、 没有列头
如果我们拿到的数据像上面的数据一样没有列头,Pandas 在读取 csv 提供了自定义列头的参数。下面我们就通过手动设置列头参数来读取 csv,代码如下:
import pandas as pd
column_names= [\'id\', \'name\', \'age\', \'weight\',\'m0006\',
\'m0612\',\'m1218\',\'f0006\',\'f0612\',\'f1218\']
df = pd.read_csv(\'data/patient_heart_rate.csv\', names = column_names)
df.head()
运行结果如下:
上面的结果展示了我们自定义的列头。我们只是在这次读取 csv 的时候,多了传了一个参数 names = column_names,这个就是告诉 Pandas 使用我们提供的列头。
4、一个列有多个参数
在数据中不难发现,Name 列包含了两个参数 Firtname 和 Lastname。为了达到数据整洁目的,我们决定将 name 列拆分成 Firstname 和 Lastname
使用 str.split(expand=True),将列表拆成新的列,再将原来的 Name 列删除
df[[\'first_name\',\'last_name\']] = df[\'name\'].str.split(expand=True)
df.drop(\'name\', axis=1, inplace=True)
df.head()
运行结果如下:
5、列数据的单位不统一
如果仔细观察数据集可以发现 Weight 列的单位不统一。有的单位是 kgs,有的单位是 lbs
lbs_weight_s = df[df.weight.str.contains("lbs").fillna(False)][\'weight\']
lbs_weight_s = lbs_weight_s.apply(lambda lbs: "%.2fkgs" % (float(lbs[:-3])/2.2) )
df.loc[lbs_weight_s.index,\'weight\'] = lbs_weight_s
运行结果如下:
6、缺失值处理
在数据集中有些年龄、体重、心率是缺失的。我们又遇到了数据清洗最常见的问题——数据缺失。一般是因为没有收集到这些信息。我们可以咨询行业专家的意见。典型的处理缺失数据的方法:
- 删:删除数据缺失的记录
- 赝品:使用合法的初始值替换,数值类型可以使用 0,字符串可以使用空字符串“”
- 均值:使用当前列的均值
- 高频:使用当前列出现频率最高的数据
- 源头优化:如果能够和数据收集团队进行沟通,就共同排查问题,寻找解决方案。
7、重复数据处理
有的时候数据集中会有一些重复的数据,执行以下代码观察数据集前10条数据
df.head(10)
运行结果如下:
观察以上结果,可以发现在我们的数据集中也存在重复的数据,如下
首先我们校验一下是否存在重复记录。如果存在重复记录,就使用 Pandas 提供的 drop_duplicates() 来删除重复数据。
df.drop_duplicates([\'first_name\',\'last_name\'],inplace=True)
df.head(10)
运行结果如下:
删除weight字段重复的数据
df.drop_duplicates([\'weight\'],inplace=True)
df.head(10)
运行结果如下
8、 非ASCII 字符
在数据集中 Fristname 和 Lastname 有一些非 ASCII 的字符。
处理非 ASCII 数据方式有多种
- 删除
- 替换
- 仅仅提示一下
我们使用删除的方式:
df[\'first_name\'].replace({r\'[^\\x00-\\x7F]+\':\'\'}, regex=True, inplace=True)df[\'last_name\'].replace({r\'[^\\x00-\\x7F]+\':\'\'}, regex=True, inplace=True)df.head()
运行结果如下:
9、有些列头应该是数据,而不应该是列名参数
有一些列头是有性别和时间范围组成的,这些数据有可能是在处理收集的过程中进行了行列转换,或者收集器的固定命名规则。这些值应该被分解为性别(m,f),小时单位的时间范围(00-06,06-12,12-18)
sorted_columns = [\'id\',\'age\',\'weight\',\'first_name\',\'last_name\']df = pd.melt(df, id_vars=sorted_columns, var_name=\'sex_hour\', value_name=\'puls_rate\')df = df[df.puls_rate != \'-\'].dropna()df = df.sort_values([\'id\',\'first_name\',\'last_name\']).reset_index()def split_sex_date(sex_hour): sex = sex_hour[:1] if \'f\' == sex: sex = \'女\' elif \'m\' == sex: sex = \'男\' hour = sex_hour[1:] return pd.Series([sex,hour])df[[\'sex\',\'hour\']] = df.sex_hour.apply(split_sex_date)df.drop(\'sex_hour\',axis=1)
运行结果如下:
任务三:Pandas数据分析实战-2
【任务目标】
本任务主要目标为使用pandas进行数据分析实战,在实战过程中带大家了解pandas模块的一下功能:
- 日期的处理
- 字符编码的问题
【任务步骤】
1、参考【任务一】第1步中操作,在jupyter notebook编辑中重新新建一个notebook 文件,命名为 pandas-data-processing-3,如下图所示:
2、预览数据
这次我们使用 Artworks.csv,我们选取 100 行数据来完成本次内容。具体步骤:
- 导入Pandas
- 读取 csv 数据到 DataFrame(要确保数据已经下载到指定路径)
DataFrame 是 Pandas 内置的数据展示的结构,展示速度很快,通过 DataFrame 我们就可以快速的预览和分析数据。代码如下:
import pandas as pddf = pd.read_csv(\'./data/Artworks.csv\').head(100)df.head(10)
运行结果如下:
2、统计日期数据
我们仔细观察一下 Date 列的数据,有一些数据是年的范围(1976-1977),而不是单独的一个年份。在我们使用年份数据画图时,就不能像单独的年份那样轻易的画出来。我们现在就使用 Pandas 的 value_counts() 来统计一下每种数据的数量。
首先,选择要统计的列,并调用 value_counts():
df[\'Date\'].value_counts()
运行结果如下:
3、日期数据问题
Date 列数据,除了年份是范围外,还有三种非正常格式。下面我们将这几种列出来:
- 问题一,时间范围(1976-77)
- 问题二,估计(c. 1917,1917 年前后)
- 问题三,缺失数据(Unknown)
- 问题四,无意义数据(n.d.)
接下来我们会处理上面的每一个问题,使用 Pandas 将这些不规则的数据转换为统一格式的数据。
问题一和二是有数据的只是格式上欠妥当,问题三和四实际上不是有效数据。针对前两个问题,我们可以通过代码将据格式化来达到清洗的目的,然而,后两个问题,代码上只能将其作为缺失值来处理。简单起见,我们将问题三和四的数据处理为0。
处理问题一
问题一的数据都是两个年时间范围,我们选择其中的一个年份作为清洗之后的数据。为了简单起见,我们就使用开始的时间来替换这样问题的数据,因为这个时间是一个四位数的数字,如果要使用结束的年份,我们还要补齐前两位的数字。
首先,我们需要找到问题一的数据,这样我们才能将其更新。要保证其他的数据不被更新,因为其他的数据有可能是已经格式化好的,也有可能是我们下面要处理的。
我们要处理的时间范围的数据,其中包含有“-”,这样我们就可以通过这个特殊的字符串来过滤我们要处理的数据,然后,通过 split() 利用“-”将数据分割,将结果的第一部分作为处理的最终结果。
代码如下
row_with_dashes = df[\'Date\'].str.contains(\'-\').fillna(False)for i, dash in df[row_with_dashes].iterrows(): df.at[i,\'Date\'] = dash[\'Date\'][0:4]df[\'Date\'].value_counts()
运行结果如下:
处理问题二
问题二的数据体现了数据本身的不准确性,是一个估计的年份时间,我们将其转换为年份,那么,就只要保留最后四位数字即可,该数据的特点就是数据包含“c”,这样我们就可以通过这一特征将需要转换的数据过滤出来。
row_with_cs = df[\'Date\'].str.contains(\'c\').fillna(False)for i,row in df[row_with_cs].iterrows(): df.at[i,\'Date\'] = row[\'Date\'][-4:]df[row_with_cs]
运行结果如下:
处理问题三四
将这问题三四的数据赋值成初始值 0
df[\'Date\'] = df[\'Date\'].replace(\'Unknown\',\'0\',regex=True)
df[\'Date\'] = df[\'Date\'].replace(\'n.d.\',\'0\',regex=True)
df[\'Date\']
运行结果如下:
4、附:完成代码
注意:完整代码中删除了数据展示部分
import pandas as pd
df = pd.read_csv(\'../data/Artworks.csv\').head(100)
df.head(10)
df[\'Date\'].value_counts()
row_with_dashes = df[\'Date\'].str.contains(\'-\').fillna(False)
for i, dash in df[row_with_dashes].iterrows():
df.at[i,\'Date\'] = dash[\'Date\'][0:4]
df[\'Date\'].value_counts()
row_with_cs = df[\'Date\'].str.contains(\'c\').fillna(False)
for i,row in df[row_with_cs].iterrows():
df.at[i,\'Date\'] = row[\'Date\'][-4:]
df[\'Date\'].value_counts()
df[\'Date\'] = df[\'Date\'].replace(\'Unknown\',\'0\',regex=True)
df[\'Date\'] = df[\'Date\'].replace(\'n.d.\',\'0\',regex=True)
df[\'Date\'].value_counts()
网络编程知识预备 ——libcurl库简介及其编程使用
本文为学习笔记,整合课程内容以及下列文章:
其中,libcurl函数库常用字段解读部分:
目录
Libcurl库简介
在linux下用c语言做HTTP的编程有一种方法是依赖于这个libcurlv库,以后做跨平台网络协议相关的开发,第一个要想到的就是它。
libcurl是一个跨平台的网络协议库,支持http, https, ftp等协议,libcurl同样支持:
(1)HTTPS证书授权
(2)HTTP POST, HTTP PUT, FTP 上传
(3) HTTP基本表单上传,代理,cookies,和用户认证
库下载地址:库下载
然后发送到linux开发环境中。
Libcurl等三方库的通用编译方法
三方库使用前通读方法
解压下载的库
tar xvf curl-7.71.1.tar.bz2
- 1
进入文件夹
cd curl-7.71.1
- 1
对于这种开源的包,一定要学会它的使用:
先看README:
vi README
- 1
并没有发现一些特别有用的东西。
没关系,去看这个
docs文件夹很重要,一般是对README的补充
cd docs
- 1
不需要看太多,看类似于这个:前面README提到的相关的API手册
vi curl.1
- 1
也很难受,真提取不到什么信息。
嵌入式开发变得简单了是因为嵌入式经过十几二十年的发展有很多人对其进行解读,写了很多文章。
重点是看INSTALL文件
还是重点来看看docs下的INSTALL文件,库一定要学会安装才能使用。
卧槽,外国人在绕圈圈,大概看看INSTALL.md
可以看到./configure后面没有跟任何参数就是默认安装位置了,这里我们肯定要做配置,不配置都不知道文件安装到哪里去了
make就是编译的意思
make install就是把编译的结果拷贝到根的指定文件夹底下
关于帮助:
不在原本默认的路径下安装说明:
配置是否支持https:
回到/curl-7.71.1
目录下,configure --help看看
./configure --help
- 1
可以看到上文所提及的安装路径配置:
也可以看到特别重要的交叉编译说明:
库的配置、编译、安装
(1)安装位置的更改:
配置为:$
获取当前路径,编译的时候会自动生成_install文件夹,并且把编译生成的东西全部放入这个文件夹。
./configure --prefix=$PWD/_install
- 1
另外,这是针对于交叉编译的配置:编译后在树莓派上用
如果上述操作直接在树莓派上进行,则不用再去额外配置交叉编译。工作中开发板往往没有编译工具,需要在上位机上进行编译,那么这里就要进行交叉编译配置。
./configure --prefix=$PWD/_install --host=arm-linux
这样,在ubuntu中就会使用arm-gcc进行编译
(2)开始编译
make
- 1
(3)安装
make install
- 1
(4)预览
进入 /_install
我们用的是头文件
cd include
- 1
进入里面的这个
cd curl
- 1
这些都是要用到的头文件
就像树莓派编译是要链接库一样
gcc a.c -lwiringPi -lpthread
用到这个库的时候,我们同样需要链接_install/lib
里面的libcurl.so
动态库 (.a
是静态库)
调用libcurl编程访问百度主页
把_install
里的内容结合一下示例代码来访问一下百度。
代码
#include <stdio.h>
#include <curl/curl.h>
typedef unsigned int bool;//数据类型别名用typedef 有冒号
#define true 1 //宏定义用define 无冒号
#define false 0
bool getUrl(char *filename)
{
CURL *curl;
CURLcode res;
FILE *fp;
if ((fp = fopen(filename, "w")) == NULL) // 返回结果用文件存储
return false;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: Agent-007");
curl = curl_easy_init(); // 初始化
if (curl)
{
//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");// 代理
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 改协议头
curl_easy_setopt(curl, CURLOPT_URL,"http://www.baidu.com");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); //将返回的http头输出到fp>指向的文件,即为filename文件,而主函数传入的参数是 /tmp/get.html,即为真正保存在get.html文件中
curl_easy_setopt(curl, CURLOPT_HEADERDATA, fp); //将返回的html主体数据输
出到fp指向的文件
res = curl_easy_perform(curl); // 执行
if (res != 0) {
curl_slist_free_all(headers); //释放句柄
curl_easy_cleanup(curl);
}
fclose(fp);
return true;
}
}
bool postUrl(char *filename)
{
CURL *curl;
CURLcode res;
FILE *fp;
if ((fp = fopen(filename, "w")) == NULL)
return false;
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt"); // 指定cookie文件
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86"); // 指定post内容:用户信息 字段之间&连接,尝试登陆新浪邮箱
//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");
curl_easy_setopt(curl, CURLOPT_URL, " http://mail.sina.com.cn/cgi-bin/login.cgi "); // 指定url
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);//执行
curl_easy_cleanup(curl);
}
fclose(fp);
return true;
}
int main(void)
{
getUrl("/tmp/get.html");
postUrl("/tmp/post.html");
}
为什么要有最开始的那三句代码呢?
类似于bool,true,faluse
,这是C99标准才会支持,C++里有专门的bool类型,用来表示真或假。但是在C语言里没有这样的类型,为了修改方便直接这样替换。
编译注意:
链接库和头文件再编译,同时注意指明他们的路径
gcc getAndPost.c -I ./curl-7.71.1/_install/include/ -L ./curl-7.71.1/_install/lib/ -lcurl
- 1
注意了,动态库静态库的链接用
-L
,而头文件用-I
错误排查:
(1)如果只是使用
-L
是默认去usr/lib
下去找的,会提示找不到cannot find -lcurl
(2)如果编译报错一堆函数不认识,函数是存在库里面的,说明没有链接库
usr/bin/ld: getAndPost.c:(.text+0x1a2): undefined reference to `curl_easy_init'
/usr/bin/ld: getAndPost.c:(.text+0x1d2): undefined reference to `curl_easy_setopt'
/usr/bin/ld: getAndPost.c:(.text+0x1f6): undefined reference to `curl_easy_setopt'
/usr/bin/ld: getAndPost.c:(.text+0x217): undefined reference to `curl_easy_setopt'
/usr/bin/ld: getAndPost.c:(.text+0x238): undefined reference to `curl_easy_setopt'
/usr/bin/ld: getAndPost.c:(.text+0x244): undefined reference to `curl_easy_perform'
(3)提示找不到头文件
#include <curl/curl.h>
,说明没有指明头文件的路径
可以看到已经生成了可执行文件./a.out
直接运行这个./a.out
是会报错的(为什么我没有报错??可能是我用的Ubuntu20,老师是18.04??不,很有可能是因为我当时网络是断开的)
error while loading shared libraries: libcurl.so.4:cannot open shared object file:no such file or directory
原因是没有添加环境变量,忘记怎么添加咋办?面向百度,export lib path
export LD_LIBRARY_PATH=./curl-7.71.1/_install/lib/
- 1
成功运行后,可以看到vi /tmp/get.html
中已经有了百度官网的代码。(仅贴出部分)
这跟我们平常去访问百度是一样的,只是用了前端css去排版的比较好看罢了,当你右键查看页面源码就知道了。
而vi /tmp/port.html
里面不会有东西,因为访问失败了:新浪的用户和密码不匹配。
libcurl函数库常用字段解读
1.调用curl_global_init()
:初始化libcurl
函数只能用一次。(其实在调用curl_global_cleanup 函数后仍然可再用)
如果这个函数在curl_easy_init
函数调用时还没调用,它将由libcurl库自动调用,所以多线程下最好主动调用该函数以防止在线程中curl_easy_init时多次调用。
注意:虽然libcurl是线程安全的,但curl_global_init是不能保证线程安全的,
所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线
程中。
参数:flags
CURL_GLOBAL_ALL //初始化所有的可能的调用。(最常用)
CURL_GLOBAL_SSL //初始化支持 安全套接字层。
CURL_GLOBAL_WIN32 //初始化win32套接字库。
CURL_GLOBAL_NOTHING //没有额外的初始化。
- 1
- 2
- 3
- 4
2.调用curl_easy_init()
:得到 easy interface型指针,拿到句柄
用来初始化一个CURL的指针(有些像返回FILE类型的指针一样)。相应的在调用结束时要用curl_easy_cleanup函数清理。
一般curl_easy_init意味着一个会话的开始. 它会返回一个easy_handle(CURL*对象), 一般都用在easy系列的函数中。
后续所有的操作都是对这个指针进行设置,把这种类型的指针就叫做句柄,实例:
其实socket服务器再socket函数后生成的fd,后续的bind,accept等操作也是基于这个fd,也可以理解为句柄
3.调用curl_easy_setopt(CURL *handle, CURLoption option, parameter)
:设置传输选项
根据设置的传输选项,实现回调函数以完成用户特定任务(设置与操作句柄)
这个函数最重要了.几乎所有的curl 程序都要频繁的使用它.它告诉curl库.程序将有如何的行为. 比如要查看一个网页的html代码等.(这个函数有些像ioctl函数)
参数:
(1)
CURL
类型的指针
(2)CURLoption
类型的选项.(都在curl.h库里有定义,man 也可以查看到)
(3)parameter
既可以是个函数的指针,也可以是某个对象的指针,也可以是 个long型的变量,取决于第二个参数。
CURLoption常用的选项(宏):
(1)CURLOPT_URL:设置访问URL,就是设置访问的网址
(2)CURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA
回调函数:网页有数据请求回来的时候,如何去处理这些数据。(做人脸识别,肯定要获得人脸识别的结果)
设置的回调函数格式要求为:
size_t function( void *ptr, size_t size, size_t nmemb, void *stream)
;
函数将在libcurl接收到数据后被调用,因此函数多做数据保存的功能,如处理下载文件。
CURLOPT_WRITEFUNCTION使用举例
①陈老师的车牌识别车牌识别
int BufferWriterFunc(char* data,size_t size,size_t nmemb,char *buffer)
{
strcpy(bufferData,data);//把返回的data数据放在本地的bufferData数组中
return size*nmemb;
}
//配置如下:
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,BufferWriterFunc);
②修改上面访问百度的代码
size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
{
char buf[1024] = {'\\0'};
strncpy(buf,ptr,1024);
printf("===========get data ===========\\n");
printf("%s\\n",buf);
}
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,readData);
CURLOPT_WRITEDATA使用举例
也可以通过 CURLOPT_WRITEDATA属性给默认回调函数传递一个已经打开的文件指针,用于将数据输出到文件里。
正如上面访问百度的例子:
FILE *fp;
if ((fp = fopen(filename, "w")) == NULL)//提前打开了一个文件流
return false;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);//请求回来的所有数据都放到文件中
(3)CURLOPT_POSTFIELDS
在post请求中:以&
拼接字符串的形式把参数链接起来
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86"); // 指定post内容:用户信息,尝试登陆新浪邮箱
下片文章提到的翔云人工智能平台OCRkey和密码就要放在这里传输。
4.调用curl_easy_perform()
:执行传输任务
在初始化CURL类型的指针 以及curl_easy_setopt完成后调用. 就像字面的意思所说perform就像是个舞台.让我们设置的option 运作起来。
5.调用curl_easy_cleanup()
:释放内存
结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数。
该死的a库不好用
./a.out: /usr/lib/arm-linux-gnueabihf/libssl.so.1.1: version `OPENSSL_1_1_1' not found (required by ./curl-7.71.1/_install/lib/libcurl.so.4)
往期文章
网络编程知识预备(1) ——了解OSI网络模型
网络编程知识预备(2) ——浅显易懂的三次握手与四次挥手
网络编程知识预备(3) ——SOCKET、TCP、HTTP之间的区别与联系
网络编程知识预备(4) ——了解HTTP协议与HTTPS协议
网络编程知识预备(5) ——libcurl库简介及其编程使用
以上是关于预备知识-python核心用法常用数据分析库(下)的主要内容,如果未能解决你的问题,请参考以下文章