暂时未有相关云产品技术能力~
4、tableau保存操作文本的两种格式说明1)“.twbx”格式和“.twbx”格式 从下图可以看出,tableau保留操作有两种格式,一种是“.twb”格式,一种是“.twbx”格式。“.twb”格式:此种格式保存的文件,如果单独将这个文件发给别人,别人也用不了,除非你将数据源一并发给别人,别人才可以使用。“.twbx”格式:又叫做“打包工作簿”。此种格式保留的文件,可以直接给别人打开使用,不需要发数据源。2)将tableau导出为任意版本的tableau文件 由于不同版本之间的tableau文件,不能直接打开使用,因此需要我们在导出文件的时候,可以保存成不同的版本。
经过上述操作,会出现如下界面:表格操作的四大按钮。1)田字格按钮的作用:分别对单元格、区、标题,进行线条颜色、线条粗细的设置。单元格:表中的数值区域,都是一个个的单元格。区:数值区域的左右边界,我们称为区。标题:表最左侧的叫做行标题,表最上方的叫做列标题。2)填充格按钮的作用:为整张表的标题、区、单元格设置填充色。“行分级”操作:让表格有隔行显示效果。3)A按钮的作用:专门针对表中的文本进行字体颜色、字体大小、字体格式、是否斜体等操作。注意:工作表是对表中所有文本进行一次性的设置。当我们单独对去、标题等设置了操作,则会覆盖掉之前对于工作表的操作。4)对齐按钮的作用:专门设置表中文本,是左对齐,还是右对齐,还是居中对齐这些操作。
⑤ 将数据源转换到工作表⑥ 双击客户名称字段,再双击销售额字段,最后双击利润字段,就会出现下表⑦ 调整适当的宽度⑧ 最终效果如下3、调整tableau中表格样式的常用四大按钮调整表的格式:设计表的格式。光标放在表中任意位置,右击鼠标,点击设计格式;
1、tableau的介绍1)tableau的优势它可以解决数据孤岛问题。可以将来自不同系统的数据(Mysql、Oracle、ERP),通过这一个产品,将它们结合到一起使用。拥有丰富多样的图表。色彩丰富,还可以做图形交互。2)维度和指标“维度”指的是说明和观察事物的角度,一般不是数字。“指标”指的是衡量事务的标准,一般都是一些数字。eg:对于一个4S店。维度:车型、地区。指标:销售量、销售额、利润。3)展现形式看板、驾驶舱、可视化大屏。4)设计形式工作表:是tableau最小的工作单位,里面放的是图表。仪表板:是由多个工作表构成。故事:是由多个工作表或多个仪表板构成。5)设计流程数据–>设计形式–>展现形式2、数据导入、数据浏览① 导入数据:这个很简单,tableau中支持很多不同软件的数据导入像excel、MySQL、Oracle…② 选中某个表,将其拖动到右侧空白区域。③ 经过上述操作,就会展示出表中的数据④ 仔细观察数据上方的图标#:井号键,代表数值。📅:小日历,代表日期。Abc:Abc,代表字符串。
1、什么是数据离散化? 连续属性的离散化,就是将连续属性的值域划分为若干个离散的区间。最后用不同的符号或整数值,代表每个子区间的属性值。 2、为什么要进行数据离散化? 数据离散化可以有效的降低时间复杂度和内存开销。 对于某些机器学习算法来说,像决策树、随机森林、朴素贝叶斯。他们的数据集大多数都是针对的离散型数据。因此做出有效的数据离散化,对于降低计算复杂度和提高算法准确率有很重要的影响。 离散型数据更容易理解。针对收入字段,一个人是3000,一个人是20000。如果将收入看成一个连续型变量,对于这么多数字,我们需要通过数字层面的比较才能知道,谁属于高薪,谁属于低薪,看起来并不直观。如果将收入转换为离散化数据类型(低薪、中薪、高薪),就能够很清楚的看出原始数字的含义。 离散化后的特征对异常数据有很强的鲁棒性:对于年龄这个特征,如果年龄>30是1,否则0。假如特征没有离散化,一个异常数据“年龄300岁”会给模型造成很大的干扰。 更多数据离散化的内容,可以参考如下文章:https://zhuanlan.zhihu.com/p/91181935 3、怎么进行数据离散化? 对于获取到的数据集,会有很多个特征,也就是我们常说的字段。有的特征是连续性数据类型,有的数据本身就是离散型数据变量。 已经是离散型数据变量,我们不用管。但是对于连续性数据变量,如果需要进行数据离散化,应该怎么办?1)pd.cut()和pd.qcut()的参数说明qcut():表示自动分组,一般用的不太多。cut():表示自定义分组,这个用的最多。语法:pd.cut(x, bins=, labels=, right=, )x表示一个序列(列表、Series等),也就是我们想要离散化的数据类型。bins在定义分组的时候,可以传入一个序列,进行自定义分组。labels表示给每个分组起别名。right=False表示左闭右开区间。默认是right=True表示左开右闭区间。pd.cut()一般会与value_counts()进行搭配使用,用于统计每个分组的个数。2)pd.cut()和pd.qcut()的使用说明① pd.qcut()的使用说明x = [165,174,160,180,159,163,192,184] s = pd.Series(x,index=["NO1:165","NO1:174","NO1:160","NO1:180",\ "NO1:159","NO1:163","NO1:192","NO1:184"]) s_qcut = pd.qcut(s,3) print(s_qcut)结果如下:② pd.cut()的使用说明x = [165,174,160,180,159,163,192,184] s = pd.Series(x,index=["NO1:165","NO1:174","NO1:160","NO1:180",\ "NO1:159","NO1:163","NO1:192","NO1:184"]) s_cut = pd.cut(s,bins=[150,165,180,195]) print(s_cut) # 添加labels参数后 x = [165,174,160,180,159,163,192,184] s = pd.Series(x,index=["NO1:165","NO1:174","NO1:160","NO1:180",\ "NO1:159","NO1:163","NO1:192","NO1:184"]) s_cut = pd.cut(s,bins=[150,165,180,195],labels=["低","中","高"]) print(s_cut) # 添加right参数后 x = [165,174,160,180,159,163,192,184] s = pd.Series(x,index=["NO1:165","NO1:174","NO1:160","NO1:180",\ "NO1:159","NO1:163","NO1:192","NO1:184"]) s_cut = pd.cut(s,bins=[150,165,180,195],labels=["低","中","高"],right=False) print(s_cut)结果如下:3)pd.cut()配合value_counts()使用import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = "SimHei" plt.rcParams["axes.unicode_minus"] = False x = [165,174,160,180,159,163,192,184] s = pd.Series(x,index=["NO1:165","NO1:174","NO1:160","NO1:180",\ "NO1:159","NO1:163","NO1:192","NO1:184"]) s_cut = pd.cut(s,bins=[150,165,180,195],labels=["低","中","高"],right=False) count = s_cut.value_counts() print(count) count.plot(kind="bar") plt.xticks(rotation=360)结果如下:4、离散化数据的后期处理(one-hot编码) 不管是连续性数据变量,还是离散型数据编码,都是数据的一个特征,都有它独特的含义。但是对于离散型数据编码,一般展现出来的是文本字符串,我们虽然认识,但是机器不认识,因此在处理这些数据的时候,就需要将其变成数字。 比如说,我们有这样两组数据。一组数据代表的是性别,一组数据代表的是物种,另外一组数据代表的是毛发。如下所示。 从图中可以看出。对于性别来说,不是男、就是女,一般的处理方式都是采取二值编码,即“男=1”,“女=0”。对于物种来说,有很多个物种,图中我们采取的是1,2,3…这种格式的编码。对于毛发来说,我们采取的也是1,2,3…这种格式的编码。 但是很显然不太合适,对于性别、物种来说,采用图中的编码方式,很显然3>2>1>0,计算机会将这样的数字会等效看代,因为存在着一种大小关系。但是对于毛发、学历来说,采用这种编码方式,却是可以的,因此毛发有多有少,学历有高有低,因此不同的数字大小,表示等级的不同。 因此,我们需要使用one-hot编码处理一下,最终效果如下。1)pd.get_dummies(data,prefix=)的使用data表示数组、Series或DataFrame。prefix表示给分组加前缀。① data传入一个Seriesx = [165,174,160,180,159,163,192,184] s = pd.Series(x,index=["NO1:165","NO1:174","NO1:160","NO1:180",\ "NO1:159","NO1:163","NO1:192","NO1:184"]) s_cut = pd.cut(s,bins=[150,165,180,195],labels=["低","中","高"]) print(s_cut) pd.get_dummies(s_cut)结果如下:② data传入一个DataFramedf = pd.DataFrame({"性别":["男","女","男"], "物种":["主","狗","猫"]}) print(df) pd.get_dummies(df)结果如下:
1、什么是SSH? SSH为Secure Shell(安全外壳协议)的缩写,简单说,SSH只是一种网络协议,用于计算机之间的加密登录。 很多ftp、pop和telnet在本质上都是不安全的,因为它们在网络上用明文传送口令和数据,别有用心的人很容易就可以截获这些口令和数据。而SSH就是专为远程登录会话和其他网络服务,提供安全性协议。 2、SSH由“客户端”和“服务端”的软件组成的 服务端是一个守护进程(sshd),它在后台运行并响应,来自客户端的连接请求。 客户端包含ssh程序以及像scp(远程拷贝)、slogin(远程登陆)、sftp(安全文件传输)等其他的应用程序。 注意:谁被连接,就把谁看成服务端。 例如:我装了两台虚拟机bigdata111和bigdata112,假如bigdata111想要连接bigdata112,此时就需要借助bigdata112中的sshd进程,此时可以把bigdata111看成客户端,把bigdata112看成服务端。客户端(bigdata111)要连接服务端(bigdata112),那么服务端(bigdata112)这个sshd守护进程,会响应来自客户端(bigdata111)的连接请求。"可以使用netstat -nltp命令,查看sshd端口号和进程号。" netstat -nltp "ps命令可以查看sshd的进程号。" ps aux | grep ssh 3、SSH认证机制 从客户端来看,SSH提供两种级别的安全验证。1)基于口令的安全验证 只要你知道对方帐号和口令(密码),就可以登录到远程主机。但是搭建集群的时候,需要进行多台虚拟机之间的传输,假如每次都要输入口令(密码),显得很麻烦。2)基于秘钥的安全验证上图黑色部分1,2,3原理说明: 客户端先生成一对密钥(公钥、私钥),私钥自己保留着,公钥远程拷贝给目标主机(你要远程登陆谁,谁就是目标主机),并将该公钥放到目标主机的授权池。 为什么是授权池? 你可以类比现实生活中的一个大池子,既然是池子,肯定可以容纳很多东西,它不仅可以接纳bigdata111发送过来的公钥,它还可以接纳来自其它机器发送过来的公钥,谁要是想登陆到我,直接都把公钥塞到我这个授权池就好啦。上图蓝色部分Ⅰ、Ⅱ、Ⅲ、Ⅳ原理说明: 完成上述发送公钥操作后,Ⅰ当客户端bigdata111请求登陆服务端bigdata112的时候,Ⅱ服务端检查是否存在这个公钥,如果公钥存在,Ⅲ服务端将该公钥加密一个随机字符串返回给客户端,Ⅳ客户端收到加密公钥后,便用自己的私钥解密返回给服务端。如果能够正确解密(解密后的字符串和加密后的字符串一致),就允许这个登陆请求。免密登录的操作原理如下: 知道上述原理后,免密登陆就显得很简单。 在客户端生成一对密钥,然后把公钥发送到服务端的授权池,就OK了。 4、演示“远程拷贝” 首先,把bigdata112中的东西删掉,方便演示。(假如你不确定这样做是否安全,那么你可以先【拍一个快照】,再进行错误。一旦发生错误,就可以恢复原来的样子)[root@bigdata112 ~]# rm -rf *删除后可以看到,bigdata112中/root家目录下,没什么其他东西了 。 接着,在bigdata111中创建一个a.txt文件,如下所示:需求:把bigdata111中的a.txt文件,发送到bigdata112这个机器中!!!远程拷贝命令如下:[root@bigdata111 ~]# scp -r a.txt root@bigdata112:~/特别注意1:远程拷贝使用的是scp命令;a.txt是我们要拷贝的文件;root@bigdata112表示我们要把文件拷贝给bigdata112这台机器的root用户;:后面写的是路径,这里代表我们要拷贝到bigdata112的root用户的家目录下。特别注意2:因为,我们在bigdata111的vim /etc/hosts目录下,配置了bigdata112的主机映射。因此,我可以将192.168.2.112写成bigdata112,假如你没有配置主机映射,那么需要写成“scp -r a.txt root@192.168.2.112:~/”。第一次进行远程拷贝(没有经过任何配置),会出现以下询问:[root@bigdata111 ~]# scp -r a.txt root@bigdata112:~/ Are you sure you want to continue connecting (yes/no)? yes root@bigdata112's password: ******这里我们写yes,然后输入自己设置的bigdata112的登陆密码******,即可。最后,我们去到bigdata112下面查看,是否存在“a.txt”的文件。注意这样一个细节问题:当我们远程发送一次文件后,若再次进行发送,发现就不会在询问你“Are you sure you want to continue connecting (yes/no)?”,而是直接让你输入密码,这是为什么呢?[root@bigdata111 ~]# scp -r a.txt root@bigdata112:~/ Are you sure you want to continue connecting (yes/no)? yes root@bigdata112's password: ****** a.txt # 再次发送 [root@bigdata111 ~]# scp -r a.txt root@bigdata112:~/ root@bigdata111's password: ****** a.txt原因:这里有一个隐藏的文件“.ssh”,我们先进入到该目录下 :[root@bigdata111 ~]# cd .ssh/ [root@bigdata111 .ssh]# ll total 4 -rw-r--r--. 1 root root 798 Sep 30 00:19 known_hosts从上面可以看出,这里有一个文件known_hosts。当我第一次远程发送文件的时候,会在客户端自动创建一个这样的known_hosts文件,服务端(bigdata112)的IP相当于在客户端(bigdata111)注册了,当再次远程发送的时候,就不会问你yes还是no了。当我们删除该文件,你再进行远程发送,又会询问你yes还是no了。 5、配置免密登录:和免密登陆相关的文件夹/root/.ssh免密登陆配置的步骤如下:1)创建密钥对:ssh-keygen[root@bigdata111 .ssh]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: e1:ba:be:ee:23:cc:91:9f:9b:71:36:b6:84:91:b6:dc root@bigdata112 The key's randomart image is: +--[ RSA 2048]----+ | | | | | . | | o . | | .+ S | | oo * | | o o*.E | | + +O o | | =O+. | +-----------------+注意:输入ssh-keygen后,连续点击Enter三次(什么也不用输入),即可。当出现上述图,代表创建密钥对成功。同时,我们可以查看该目录下,也多了几个文件id_rsa、id_rsa.pub。[root@bigdata111 .ssh]# ll total 12 -rw-------. 1 root root 1675 Sep 30 00:39 id_rsa -rw-r--r--. 1 root root 397 Sep 30 00:39 id_rsa.pub -rw-r--r--. 1 root root 798 Sep 30 00:19 known_hosts2)发送公钥到另一台机器的授权池 我们先去bigdata112的“.ssh”目录下查看其中的文件"注意ll中的参数-a可以将文件夹下,所有以.开头的文件显示出来" [root@bigdata112 ~]# ll -a total 68 dr-xr-x---. 4 root root 4096 Sep 30 00:22 . dr-xr-xr-x. 22 root root 4096 Sep 29 18:45 .. -rw-r--r--. 1 root root 81 Sep 30 00:48 a.txt -rw-------. 1 root root 10420 Sep 29 23:30 .bash_history -rw-r--r--. 1 root root 18 May 20 2009 .bash_logout -rw-r--r--. 1 root root 176 May 20 2009 .bash_profile -rw-r--r--. 1 root root 176 Sep 23 2004 .bashrc -rw-r--r--. 1 root root 100 Sep 23 2004 .cshrc -rw-------. 1 root root 125 Sep 30 00:03 .mysql_history -rw-------. 1 root root 312 Sep 21 05:14 .mysql_secret drwxr-xr-x. 2 root root 4096 Sep 20 19:33 .oracle_jre_usage drwx------. 2 root root 4096 Sep 30 00:39 .ssh -rw-r--r--. 1 root root 129 Dec 4 2004 .tcshrc -rw-------. 1 root root 5900 Sep 29 22:45 .viminfo [root@bigdata112 ~]# cd .ssh [root@bigdata112 .ssh]# ll total 0从上面可以看出,bigdata112的“.ssh”目录下目前是空的。当我们发送公钥到另一台机器的授权池后:[root@bigdata111 ~]# ssh-copy-id 192.168.2.112 root@192.168.2.112's password: ****** Now try logging into the machine, with "ssh '192.168.2.112'", and check in: .ssh/authorized_keys to make sure we haven't added extra keys that you weren't expecting.第一次发送要输入192.168.2.112的登陆密码,当出现上述结果,证明发送成功。再次查看bigdata112的“.ssh”目录下查看其中的文件。[root@bigdata112 .ssh]# ll total 4 -rw-------. 1 root root 397 Sep 30 00:52 authorized_keys可以看出,这里多了一个authorized_keys的文件。 6、检验是否配置成功 上面我们已经配置好了SSH免密登陆,这里,我们再次将a.txt文件从bigdata111发送到bigdata112,看看是否还要输入密码 。 首先,将路径切换到“.ssh”的上一级目录/root目录下:[root@bigdata111 ~]# cd ~ 接着,使用如下命令远程发送:[root@bigdata111 ~]# scp -r a.txt root@bigdata112:~/ The authenticity of host 'bigdata112 (192.168.2.112)' can't be established. RSA key fingerprint is 78:8c:77:14:bc:76:1a:83:dc:84:9f:f5:52:3b:b1:4c. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'bigdata112' (RSA) to the list of known hosts. a.txt 100% 3 0.0KB/s 00:00 [root@bigdata111 ~]# scp -r a.txt root@bigdata112:~/ a.txt 从上面可以看出,发送的第一次,只是询问了一句yes还是no,当我们下面再次发送,一次密码也不用输入了。 在最后,我们还可以在bigdata111中,试着远程登陆一下bigdata112。[root@bigdata111 ~]# ssh bigdata112 Last login: Sun Sep 29 22:47:11 2019 from bigdata111 [root@bigdata112 ~]# exit logout Connection to bigdata112 closed. [root@bigdata111 ~]#
3)演示说明① 绘制不同饮料类型构成的饼图plt.figure(dpi=100) x1 = np.array([6,10,11,8,15]) x = x1/np.sum(x1) labels = ["果汁","矿泉水","绿茶","其它","碳酸饮料"] colors=["r", "g", "b", "y", "m"] explode = [0.05,0,0,0,0] plt.pie(x,labels=labels,colors=colors,autopct="%.0f%%", explode=explode,startangle=90,counterclock=False) plt.axis("equal") plt.savefig("不同饮料类型构成的饼图",dpi=300)结果如下:② 绘制环形图:以绘制三环形为例操作如下:plt.figure(figsize=(8,5),dpi=100) x1 = [3496.57,1161.55,1251.09,1961.07] x2 = [1383.36,775.09,595.09,1605.61] x3 = [3756.56,1623.36,1730.51,3255.94] labels = ["劳动者报酬","生产税金额","固定资产折旧","营业盈余"] colors=['pink','greenyellow','lightcoral','cyan'] plt.pie(x1,colors=colors,autopct="%.0f%%",radius=1.3, wedgeprops=dict(width=0.3,edgecolor="w"), startangle=90,counterclock=False,pctdistance = 0.9) plt.pie(x2,colors=colors,autopct="%.0f%%",radius=1, wedgeprops=dict(width=0.3,edgecolor="w"), startangle=90,counterclock=False,pctdistance = 0.85) plt.pie(x3,colors=colors,autopct="%.0f%%",radius=0.7, wedgeprops=dict(width=0.3,edgecolor="w"), startangle=90,counterclock=False,pctdistance = 0.75) plt.legend(labels=labels,loc="best",title="生产总值构成") plt.title("生产总值构成的环形图") plt.axis("equal") plt.savefig("生产总值构成的环形图",dpi=300)结果如下:6、绘制直方图① 语法格式plt.pie(x,y,height,color,edgecolor,width=0.8,bottom=None,align=“center”)② 参数说明x 表示要绘图的数据。labels 每个部分显示的标签。explode 指定每个部分距离圆心的偏移量(单位为半径的长度)。colors 指定每个部分的颜色。autopct 设置每个部分显示的比例值(格式化)。counterclock 是否逆时针绘图。默认为True。startangle 初始绘图点位置(逆时针偏移x轴的角度),默认为偏移0度(x轴)。shadow 是否含有阴影,默认为False。(用处不大)③ 演示说明df = pd.read_excel(r"C:\Users\黄伟\Desktop\matplotlib.xlsx",sheet_name="直方图") def func(x): if x>=140 and x<150: return "(140,150]" elif x>=150 and x<160: return "(150,160]" elif x>=160 and x<170: return "(160,170]" elif x>=170 and x<180: return "(170,180]" elif x>=180 and x<190: return "(180,190]" elif x>=190 and x<200: return "(190,200]" elif x>=200 and x<210: return "(200,210]" elif x>=210 and x<220: return "(210,220]" elif x>=220 and x<230: return "(220,230]" elif x>=230 and x<240: return "(230,240]" df["分组"] = df["销售量"].apply(func) df1 = df.groupby("分组")["销售量"].count() df1 = pd.DataFrame(df1) df1 = df1.reset_index() df1["频率"] = df1["销售量"].apply(lambda x:x/np.sum(df1["销售量"])) df1["频率"] = df1["频率"].apply(lambda x:"{:.2%}".format(x)) plt.figure(figsize=(6,5),dpi=100) plt.hist(df["销售量"],bins=[140,150,160,170,180,190,200,210,220,230,240],edgecolor='white',color="pink") x = np.array([140,150,160,170,180,190,200,210,220,230,240]) plt.xticks(x+5,["{}-{}".format(x,x+10) for x in range(140,231,10)],rotation=90) plt.yticks(np.arange(0,31,5)) for z in zip(x+2.5,df1["销售量"]): plt.annotate("{}".format(z[1]),xy=z,color="black") plt.tight_layout() plt.savefig("某电脑公司销售量分布的直方图",dpi=300)结果如下:
3、绘制柱形图1)作用 柱形图又叫条形图、柱状图,用来比较两个或以上的价值(不同时间或者不同条件),只有一个变量,通常利用于较小的数据集分析。2)语法格式和参数说明① 语法格式plt.bar(x,height,color,edgecolor,width=0.8,bottom=None,align=“center”)② 参数说明x 表示在x轴的哪个位置绘制柱形图;height表示每个柱子的高度。color 表示柱子的颜色。edgecolor 表示柱子边缘的颜色。width 表示每个柱子的宽度。柱子的宽度可以相同,可以不同。bottom 表示每个柱子的底部位置。每个柱子的底部位置可以相同,可以不同。align 表示柱子的位置与x值的对应关系。可选center、edge参数。center表示柱子位于x值的中心位置,edge表示柱子位于x值的边缘位置。3)演示说明① 绘制某超市饮料类型和顾客性别的条形图plt.figure(dpi=100) x1 = [1,2,3,4,5] y1 = [6,10,11,8,15] x2 = [1,2] y2 = [22,28] plt.subplot(121) plt.bar(x1,y1,width=0.5,align="center",color="r") plt.title("不同饮料类型的人数对比图") plt.xlabel("饮料类型") plt.ylabel("数量") plt.xticks([1,2,3,4,5],["果汁","矿泉水","绿茶","其它","碳酸饮料"]) plt.yticks(np.arange(0,16,3)) for x1,y1 in zip(x1,y1): plt.text(x1,y1,y1,ha="center",va="bottom",fontsize=10) plt.subplot(122) plt.bar(x2,y2,width=0.8,align="center",color="g") plt.title("不同顾客性别的人数对比图") plt.xlabel("顾客性别") plt.ylabel("数量") plt.xticks([1,2],["男","女"]) plt.yticks(np.arange(0,31,5)) for x2,y2 in zip(x2,y2): plt.text(x2,y2,y2,ha="center",va="bottom",fontsize=10) plt.subplots_adjust(wspace=0.5) plt.savefig("饮料类型和顾客性别",dpi=300)结果如下:② 绘制某超市不同饮料类型下,男女人数的对比图plt.figure(dpi=100) x = np.array([1,2,3,4,5]) y1 = np.array([1,6,7,2,6]) y2 = np.array([5,4,4,6,9]) plt.bar(x,y1,width=0.5,label="男",color="g") plt.bar(x+0.5,y2,width=0.5,label="女",color="b") plt.title("某超市不同饮料类型下男女人数的对比图") plt.xlabel("饮料类型") plt.ylabel("数量") plt.legend(loc="best",title="顾客性别") plt.xticks(x+0.15,["果汁","矿泉水","绿茶","其它","碳酸饮料"]) plt.yticks(np.arange(0,11,2)) for x,y1 in zip(x,y1): plt.text(x,y1,y1,ha="center",va="bottom",fontsize=10) for x,y2 in zip(x+0.5,y2): plt.text(x,y2,y2,ha="center",va="bottom",fontsize=10) plt.savefig("某超市不同饮料类型下男女人数的对比图",dpi=300)结果如下:4、绘制不同饮料类型的帕累托图1)演示说明① 绘制不同类型饮料的帕累托图plt.figure(dpi=100) x = np.array([1,2,3,4,5]) y1 = np.array([6,10,11,8,15]) # 先将y1中的元素,进行降序排序 y1 = np.sort(y1)[::-1] y2 = y1.cumsum()/np.sum(y1) plt.bar(x,y1,width=0.3,color="g") plt.xlabel("饮料类型") plt.ylabel("数量") plt.xticks(x,["碳酸饮料","绿茶","矿泉水","其它","果汁"]) for xy1 in zip(x,y1): plt.annotate("{}".format(xy1[1]),xy=xy1,ha="center",va="bottom") plt.twinx() plt.plot(x,y2,color="r",lw=3) plt.ylabel("百分比") plt.yticks(np.arange(0,1.1,0.2)) plt.title("不同类型饮料的帕累托图") plt.savefig("不同类型饮料的帕累托图",dpi=300)结果如下:5、绘制饼图1)作用 饼图用圆形及圆内扇形的角度来表示数值大小的图形,它主要用于表示一个样本(或总体)中各组成部分的数据占全部数据的比例。对于研究一个总体的结构性组成很有作用。2)语法格式和参数说明① 语法格式plt.pie(x,y,height,color,edgecolor,width=0.8,bottom=None,align=“center”)② 参数说明x 表示要绘图的数据。labels 每个部分显示的标签。explode 指定每个部分距离圆心的偏移量(单位为半径的长度)。colors 指定每个部分的颜色。autopct 设置每个部分显示的比例值(格式化)。counterclock 是否逆时针绘图。默认为True。startangle 初始绘图点位置(逆时针偏移x轴的角度),默认为偏移0度(x轴)。shadow 是否含有阴影,默认为False。(用处不大)一些重要参数的图示说明:
1、绘制X轴、Y轴平行线1)作用 绘制X轴、Y轴平行线,主要用来做对比参考。2)语法格式与相关参数说明① 语法格式绘制X轴平行线plt.axhline(y,xmin,xmax)绘制Y轴平行线plt.axvline(x,ymin,ymax)② 参数说明3)演示说明① 绘制X轴平行线plt.subplot(121) plt.axhline(0.5,0,1,c="r",lw=3) plt.subplot(122) plt.axhline(0.5,0.2,0.8,c="g",lw=3)结果如下:② 绘制Y轴平行线plt.subplot(121) plt.axvline(0.5,0,1,c="r",lw=3) plt.subplot(122) plt.axvline(0.5,0.2,0.8,c="g",lw=3)结果如下:2、绘制折线图1)作用 折线图用于显示随时间或有序类别而变化的趋势。折线图其实是由多个点连接在一起得到了,当点足够多的时候,折线图就变成了平滑的曲线。2)语法格式和参数说明① 语法格式plot(y)plot(y,‘格式’)plot(x,y)plot(x,y,‘格式’)plot(x1,y1,‘格式1’,x2,y2,‘格式2’ …… xn,yn,“格式n”)② 参数说明3)演示说明① 绘制一个点plt.plot(50, marker="D")结果如下:② 绘制多个点 当只传入一组数据的时候,那么每个元素的下标相当于X轴横坐标,这一组数据中的每个值相当于Y轴的纵坐标。当传入两组数据,第一组数据相当于X轴横坐标,第二组数据相当于Y轴的纵坐标。plt.subplot(121) plt.plot([8,2,9,15,-3],c="g",marker="v",ls="--") plt.subplot(122) plt.plot([-3,-1,5,8,12], [2,-10,9,3,6],c="r",marker="*",ls="-")结果如下:③ 绘制对比折线图plt.figure(dpi=100) x = np.arange(1,13) y1 = np.array([568,645,789,412,435,673,345,632,467,876,912,1222]) y2 = np.array([675,412,545,645,831,345,459,734,812,611,1500,900]) plt.plot(x,y1,c="r",marker="*",ls="-",label="2019年销售额") plt.plot(x,y2,c="g",marker="v",ls="--",label="2020年销售额") plt.legend(loc="best",ncol=2) plt.title("2019-2020年销售额对比图") plt.xlabel("月份") plt.ylabel("销售额") plt.xticks(np.arange(1,13),[str(i)+"月" for i in range(1,13)]) p1 = zip(x,y1) p2 = zip(x,y2) for x,y1 in p1: plt.text(x,y1,y1,ha="center",va="bottom",fontsize=10) for x,y2 in p2: plt.text(x,y2,y2,ha="center",va="bottom",fontsize=10) plt.savefig("2019-2020年销售额对比图",dpi=300)结果如下:
3)使用for循环打印groupby()分组对象中每一组的具体数据x = {"name":["a","a","b","b","c","c","c"],"num":[2,4,0,5,5,10,15]} df = pd.DataFrame(x) display(df) groupdf = df.groupby("name") for (x,y) in groupdf: display(x, y)结果如下:4)groupby()分组参数的4种形式单字段分组:根据df中的某个字段进行分组。多字段分组:根据df中的多个字段进行联合分组。字典或Series:key指定索引,value指定分组依据,即value值相等的记录,会分为一组。自定义函数:接受索引,索引相同的记录,会分为一组。使用如下数据演示这4种分组参数:df = pd.DataFrame({"部门":["A", "A", "B", "B"], "小组":["g1", "g2", "g1", "g2"], "利润":[10, 20, 15, 28], "人员":["a", "b", "c", "d"], "年龄":[20, 15, 18, 30]}) display(df)结果如下:① 单字段分组:根据df中的某个字段进行分组。g = df.groupby("部门") display(g) for (x,y) in g: display(x, y)结果如下:② 多字段分组:根据df中的多个字段进行联合分组。g = df.groupby(["部门","小组"]) display(g) for (x,y) in g: display(x, y)结果如下:③ 字典:key指定索引,value指定分组依据,即value值相等的记录,会分为一组。g = df.groupby({0:1, 1:1, 2:1, 3:2}) display(g) for (x,y) in g: display(x, y)结果如下:
2、groupby分组聚合的原理说明1)原理图2)原理说明split:按照指定规则分组,由groupby实现;apply:针对每个小组,使用函数进行操作,得到结果,由agg()函数实现;combine:将每一组得到的结果,汇总起来,得到最终结果;注意:combine这一步是自动完成的,因此针对pandas中的分组聚合,我们只需要学习两个内容,① 学习怎么分组;② 学习如何针对每个分组中的数据,进行对应的逻辑操作;3、groupby分组对象的相关操作 我们可以通过groupby方法来对Series或DataFrame对象实现分组操作,该方法会返回一个分组对象。但是,如果直接查看(输出)该对象,并不能看到任何的分组信息。1)groupby()函数语法① 语法如下groupby(by=[“字段1”,“字段2”,…],as_index=True)② 参数说明by参数传入的分组字段,当只有一个字段的时候,可以直接写by=“字段1”。当多字段联合分组的时候,就写成列表形式by=[“字段1”,“字段2”]。as_index参数的使用如图所示③ 参数as_index的使用说明x = {"name":["a","a","b","b","c","c","c"],"num":[2,4,0,5,5,10,15]} df = pd.DataFrame(x) display(df) df.groupby("name",as_index=True).agg({"num":"sum"}) df.groupby("name",as_index=False).agg({"num":"sum"})结果如下:2)groupby分组对象的常用方法或属性。① groups属性:返回一个字典,key表示组名,value表示这一组中的所有记录;② size()方法:返回每个分组的记录数;x = {"name":["a","a","b","b","c","c","c"],"num":[2,4,0,5,5,10,15]} df = pd.DataFrame(x) display(df) df.groupby("deptno").groups df.groupby("deptno").size()结果如下:
1、MySQL和Pandas做分组聚合的对比说明1)都是用来处理表格数据 不管是mysql,还是pandas,都是处理像excel那样的二维表格数据的。对于一个二维表,每一行都可以看作是一条记录,每一列都可以看作是字段。2)分组聚合的风格不同 学过mysql的人都知道,mysql在做数据处理和统计分析的时候,有一个很大的痛点:语法顺序和执行顺序不一致,这就导致很多初学者很容易写错sql语句。 业界处理像excel那样的二维表格数据,通常有如下两种风格:DSL风格:使用面向对象的方式来操作,pandas就是采用这种方式,通俗说就是“语法顺序和执行顺序一致”。SQL风格:写sql语句来处理。3)从代码角度,说明两者的不同① mysql语法顺序:SELECT Column1, Column2, mean(Column3), sum(Column4) FROM SomeTable WHERE Condition 1 GROUP BY Column1, Column2 HAVING Condition2逻辑执行顺序:from...where...group...select...having...limit② pandas语法顺序和逻辑执行顺序:df[Condition1].groupby([Column1,Column2],as_index=False).agg({Column3: "mean",Column4:"sum"})③ 图示说明首先from相当于取出MySQL中的一张表,对比pandas就是得到了一个df表对象。然后就是执行where筛选,对比pandas就相当于写一个condition1过滤条件,做一个分组前的筛选筛选。接着就是执行group分组条件,对比pandas就是写一个groupby条件进行分组。再接着就是执行select条件,聚合函数就是写在select后面的,对比pandas就是执行agg()函数,在其中针对不同的列执行count、max、min、sum、mean聚合函数。最后执行的是having表示分组后的筛选,在pandas中,通过上图可以发现我们得到了一个df1对象,针对这个df1对象,我们再做一次筛选,也表示分组后的筛选。综上所述:只要你的逻辑想好了,在pandas中,由于语法顺序和逻辑执行顺序是一致的,你就按照逻辑顺序写下去,就很容易了。4)用一个例子讲述MySQL和Pandas分组聚合① 求不同deptno(部门)下,sal(工资)大于8000的部门、工资;② mysqi中代码执行如下select deptno,sum(sal) sums from emp group by deptno having sums > 9000;结果如下:③ pandas中代码执行如下df = pd.read_excel(r"C:\Users\黄伟\Desktop\emp.xlsx") display(df) df = df.groupby("deptno",as_index=False).agg({"sal":"sum"}) display(df) df1 = df[df["sal"]>9000] display(df1)结果如下:
② 打印df中列或行的数据类型df = pd.read_excel(r"C:\Users\黄伟\Desktop\test.xlsx",sheet_name=2) display(df) x = df.apply(lambda x:print(type(x)),axis=0) print("-------------------------------------") y = df.apply(lambda x:print(type(x)),axis=1)结果如下:2、applymap()函数1)applymap()函数作用① applymap()函数只能作用于DataFrame 依次取出DataFrame中的每一个具体的元素作为参数,传递给function函数,进行转换。2)案例说明df = pd.read_excel(r"C:\Users\黄伟\Desktop\test.xlsx",sheet_name=2) display(df) df[['语文', '数学', '英语', '物理', '化学', '生物']].applymap(lambda x:x+100)结果如下:
1、apply()函数1)apply()函数作用① apply()函数作用于Series 和Series的map()方法作用是一样的,依次取出Series中的每一个元素作为参数,传递给function函数,进行一次转换。② apply()函数作用于DataFrame 依次取出DataFrame中的每一个元素作为参数,传递给function函数,进行转换。注意:DataFrame中的每一个元素是一个Series。③ 原始数据链接如下http://note.youdao.com/noteshare?id=3943f6b14c322e683fb2fe3bfdd11f63&sub=06345554A2234845B796B525E76697ED 2)apply()函数作用于Series① 案例一:1代表男,0代表女,完成如下替换df = pd.read_excel(r"C:\Users\黄伟\Desktop\test.xlsx",sheet_name=3) display(df) def func(x): if x == "男" or x == "女": return x elif x == 1: return "男" else: return "女" df["性别"] = df["性别"].apply(func) display(df)结果如下:② 案例二:将身高统一替换为“cm”单位df = pd.read_excel(r"C:\Users\黄伟\Desktop\test.xlsx",sheet_name=3) display(df) def func(x): if x.endswith("cm"): return x else: v = float(x.replace("m","")) return str(v*100)+"cm" df["身高"] = df["身高"].apply(func) display(df)结果如下:③ 案例三:提取日期中的年、月、日df = pd.read_excel(r"C:\Users\黄伟\Desktop\test1.xlsx") display(df) # 注意:这里的日期列,是时间格式 df["year"] = df["日期"].apply(lambda x:x.year) df["month"] = df["日期"].apply(lambda x:x.month) df["day"] = df["日期"].apply(lambda x:x.day) display(df)结果如下:3)apply函数作用于DataFrame① 案例一:求出某些列的均值df = pd.read_excel(r"C:\Users\黄伟\Desktop\test.xlsx",sheet_name=2) display(df) df1 = df[["语文","物理"]] display(df1) display(type(df1)) df[["语文","物理"]].apply(lambda x:x.mean())结果如下:
1、常用函数说明在df中使用统计函数,其实很简单,我们主要关注以下3点,就没问题: ① 了解每个函数的具体含义是什么; ② 不管是Series还是DataFrame,默认都是自动忽略NaN值,进行运算的; ③ DataFrame有行、列区分,因此在使用统计函数的时候,一般是结合axis=0或者axis=1参数对df中的哪一行、哪一列进行操作;注意:axis的具体含义,在操作DataFrame时极其重要,因此不要死记硬背,理解原理后,就永远忘记不了 。要记住不管是numpy还是pandas中,aixs的含义都是一致的。具体可以参考我之前的文章https://blog.csdn.net/weixin_41261833/article/details/1037628742、sum、mean、count、max、min 这五个函数属于最常用的几个函数,在mysql中叫做“聚合函数”(只不过mean在mysql中叫做avg),我们以sum函数为例进行说明。df = pd.read_excel(r"C:\Users\黄伟\Desktop\test.xlsx",sheet_name=2) display(df) # 重置索引 df = df.set_index("name") df.sum(axis=1) df.sum(axis=0)结果如下:3、median、abs、mod、prod、var、std# 我们就用一列来讲述这几个函数的用法 df = pd.DataFrame({"id":["00{}".format(i) for i in range(1,10)], "score":[2,3,4,4,5,6,7,7,8]}) display(df) # 求该列数据的中位数 df["score"].median(axis=0) # 求该列数据的每个值除以3得到的余数 df["score"].mod(3,axis=0) # 求该列数据的连乘积 display(2*3*4*4*5*6*7*7*8) df["score"].prod(axis=0) # 求该列数据的方差 x = df["score"].var(axis=0) display(x) # 求该列数据的标准差 y = df["score"].std(axis=0) display(y) # 标准差等于方差的开方 np.sqrt(x) == y结果如下:注意:这一组函数中,需要注意的是mod函数的用法,里面需要传入一个值,作为除数。 4、argmax和idxmax、argmin和idxmin argmax和idxmax是一组,用于返回一组数据中最大值的下标。argmin和idxmin是一组,用于返回一组数据中最小值的下标。但是当我们使用argmax和argmin的时候,会出现一个提示,告诉我们这个函数以后会被idxmax和idxmin代替,因此我们只需要掌握idxmax和idxmin的用法即可。df = pd.DataFrame({"id":["00{}".format(i) for i in range(1,10)], "score":[2,3,4,4,5,6,7,7,8]}) display(df) df["score"].idxmax(axis=0) df["score"].idxmin(axis=0)结果如下:5、unique:求一组数据中的唯一值 对于unique的使用,需要特别注意。unique函数是针对Series的操作,是针对于df的某一行,或者某一列进行操作,因此没有axis参数。unique不仅可以针对数字去重,还可以针对字符串去重。df = pd.DataFrame({"id":["00{}".format(i) for i in range(1,10)], "score":[2,3,4,4,5,6,7,7,8]}) display(df) df["score"].unique()结果如下:6、value_counts:求一组数据中每个值出现的次数(很重要) value_counts不仅可以统计一组数字中,不同值出现的次数,还可以统计一组字符串中,不同值出现的次数。df = pd.DataFrame({"id":["00{}".format(i) for i in range(1,10)], "eat_hand":["right","right","left","right","left","right","right","right","left"], "score":[2,3,4,4,5,6,7,7,8]}) display(df) df["score"].value_counts()结果如下:
⑧ 使用CTRL + S保存一下创建的映射;4)创建一个任务① 创建一个任务;② 选择该创建任务,所要执行的映射;③ 修改源表的连接对象;④ 修改目标表的连接对象:三张目标表都要修改;注意:edw_emp_deptno_20和edw_emp_deptno_30都要按照图中方式进行修改。⑤ 使用CTRL + S保存该创建的任务;5)创建一个工作流① 创建一个工作流;② 建立工作流与任务之间的连接;③ 使用CTRL + S,保存一下工作流;④ 通过任务启动工作流;⑤ 上述操作会自动打开M客户端,我们在M客户端查看一些日志信息。尤其是当我们出现错误的时候,日志信息可以帮助我们找到自己的错误究竟在哪里;⑥ 最后可以去edw用户下,查看3张目标表中的数据,正是我们想要的效果;
1、需求2、路由器转换组件的功能3、ETL开发流程1)定义源表2)定义三个目标表:edw_emp_deptno_10、edw_emp_deptno_20、edw_emp_deptno_30① 定义3个目标表;② 生成并执行sql,将这些表在目标数据库中创建;③ 可以去目标数据库中查看这三张目标表;3)创建一个映射:m_edw_emp_router① 创建一个映射;② 将一个源表和三个目标表拖拉到右侧的灰色区域;③ 在源表和目标表之间,添加一个“路由器转换组件”;④ 把源表中的所有字段,首先传递给“路由器转换组件”;⑤ 双击“路由器转换组件”,对其进行“组设置”;⑥ 上述操作完成以后,会出现如下结果;对上图的解释如下:⑦ 将“路由器转换组件”中不同的分组,分别传递给不同的目标表;
1.图片来源该图片来源于百度图片,如果侵权,请联系我删除!图片仅用于知识交流。2.读取图片并显示imread():读取图片;imshow():展示图片;waitkey():设置窗口等待,如果不设置,窗口会一闪而过;import cv2 import numpy as np # 读取照片 img=cv2.imread('girl.jpg') # 显示图像 cv2.imshow('img',img) # 窗口等待的命令,0表示无限等待 cv2.waitKey(0)效果如下:3.图片缩放resize():图片缩放,其中fx和fy表示缩放比例,0.5表示缩放为以前的 一半。import cv2 import numpy as np # 读取照片 img=cv2.imread('girl.jpg') # 图像缩放 img = cv2.resize(img,None,fx=0.5,fy=0.5) rows,cols,channels = img.shape print(rows,cols,channels) # 显示图像 cv2.imshow('img',img) # 窗口等待的命令,0表示无限等待 cv2.waitKey(0)结果如下:4.将图片转换为灰度图像三色图片有RGB三个颜色通道,无法进行腐蚀和膨胀的操作。这个就需要我们将彩色图片转换为hsv灰度图像后,再完成腐蚀和膨胀的操作。cv2.cvtColor(img,cv2.COLOR_BGR2HSV)可以将彩色图片转化为hsv灰度图片。import cv2 import numpy as np # 读取照片 img=cv2.imread('girl.jpg') # 图像缩放 img = cv2.resize(img,None,fx=0.5,fy=0.5) rows,cols,channels = img.shape print(rows,cols,channels) cv2.imshow('img',img) # 图片转换为二值化图 hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) # 显示图像 cv2.imshow('hsv',hsv) # 窗口等待的命令,0表示无限等待 cv2.waitKey(0)结果如下:5.将图片进行二值化处理二值化处理是为了将图片转换为黑白图片。二值化类似于1表示男、2表示女,对于图像的处理我们也需要自定义一个最小值和最大值,这里分别用lower_blue和upper_blue表示lower_blue = np.array([90,70,70])upper_blue = np.array([110,255,255])inRange(hsv, lower_blue, upper_blue)将图片进行二值化操作。import cv2 import numpy as np # 读取照片 img=cv2.imread('girl.jpg') # 图像缩放 img = cv2.resize(img,None,fx=0.5,fy=0.5) rows,cols,channels = img.shape print(rows,cols,channels) cv2.imshow('img',img) # 图片转换为灰度图 hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) cv2.imshow('hsv',hsv) # 图片的二值化处理 lower_blue = np.array([90,70,70]) upper_blue = np.array([110,255,255]) mask = cv2.inRange(hsv, lower_blue, upper_blue) # 显示图像 cv2.imshow('mask',mask) # 窗口等待的命令,0表示无限等待 cv2.waitKey(0)结果如下:缺点:我们观察第三章图片,发现黑色区域有时候会出现一些噪声(白点),这里可能显示的不是很明显,有的图片显示的很明显,这就需要我们进行腐蚀或膨胀。6.图象的腐蚀和膨胀上面的图象进行二值化后,出现了一些噪声,我们可以采用腐蚀或膨胀进行图片的处理,观察哪种的处理效果好一些。erode(mask,None,iterations=1)进行腐蚀操作。dilate(erode,None,iterations=1)进行膨胀操作。import cv2 import numpy as np # 读取照片 img=cv2.imread('girl.jpg') # 图像缩放 img = cv2.resize(img,None,fx=0.5,fy=0.5) rows,cols,channels = img.shape print(rows,cols,channels) cv2.imshow('img',img) # 图片转换为灰度图 hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) cv2.imshow('hsv',hsv) # 图片的二值化处理 lower_blue=np.array([90,70,70]) upper_blue=np.array([110,255,255]) mask = cv2.inRange(hsv, lower_blue, upper_blue) #腐蚀膨胀 erode=cv2.erode(mask,None,iterations=1) cv2.imshow('erode',erode) dilate=cv2.dilate(erode,None,iterations=1) cv2.imshow('dilate',dilate) # 窗口等待的命令,0表示无限等待 cv2.waitKey(0)结果如下:观察上图:对于这个图片,无论是腐蚀或膨胀,都起到了很好的去图片噪声的操作,我们使用腐蚀后的图片也可以,我们使用膨胀后的图片也可以。7.遍历每个像素点进行颜色替换图片是由每一个像素点组成的,我们就是要找到腐蚀后得到图片的,白色底色处的像素点,然后将原图中对应位置处的像素点,替换为红色。import cv2 import numpy as np # 读取照片 img=cv2.imread('girl.jpg') # 图像缩放 img = cv2.resize(img,None,fx=0.5,fy=0.5) rows,cols,channels = img.shape print(rows,cols,channels) cv2.imshow('img',img) # 图片转换为灰度图 hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) cv2.imshow('hsv',hsv) # 图片的二值化处理 lower_blue=np.array([90,70,70]) upper_blue=np.array([110,255,255]) mask = cv2.inRange(hsv, lower_blue, upper_blue) #腐蚀膨胀 erode=cv2.erode(mask,None,iterations=1) cv2.imshow('erode',erode) dilate=cv2.dilate(erode,None,iterations=1) cv2.imshow('dilate',dilate) #遍历替换 for i in range(rows): for j in range(cols): if erode[i,j]==255: # 像素点为255表示的是白色,我们就是要将白色处的像素点,替换为红色 img[i,j]=(0,0,255) # 此处替换颜色,为BGR通道,不是RGB通道 cv2.imshow('res',img) # 窗口等待的命令,0表示无限等待 cv2.waitKey(0)效果如下:
② 添加文字块儿from docx import Document doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") # 这里相当于输入了一个空格,后面等待着文字输入 paragraph3 = doc.add_paragraph() paragraph3.add_run("我被加粗了文字块儿").bold = True paragraph3.add_run(",我是普通文字块儿,") paragraph3.add_run("我是斜体文字块儿").italic = True doc.save(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx")结果如下:③ 添加一个分页from docx import Document doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") doc.add_page_break() doc.save(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx")结果如下:④ 添加图片from docx import Document from docx.shared import Cm doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") doc.add_picture(r"G:\6Tipdm\7python办公自动化\concat_word\sun_wu_kong.png",width=Cm(5),height=Cm(5)) doc.save(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") """ Cm模块,用于设定图片尺寸大小 """结果如下:⑤ 添加表格from docx import Document doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") list1 = [ ["姓名","性别","家庭地址"], ["唐僧","男","湖北省"], ["孙悟空","男","北京市"], ["猪八戒","男","广东省"], ["沙和尚","男","湖南省"] ] list2 = [ ["姓名","性别","家庭地址"], ["貂蝉","女","河北省"], ["杨贵妃","女","贵州省"], ["西施","女","山东省"] ] table1 = doc.add_table(rows=5,cols=3) for row in range(5): cells = table1.rows[row].cells for col in range(3): cells[col].text = str(list1[row][col]) doc.add_paragraph("-----------------------------------------------------------") table2 = doc.add_table(rows=4,cols=3) for row in range(4): cells = table2.rows[row].cells for col in range(3): cells[col].text = str(list2[row][col]) doc.save(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx")结果如下:⑥ 提取word表格,并保存在excel中(很重要)from docx import Document from openpyxl import Workbook doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test2.docx") t0 = doc.tables[0] workbook = Workbook() sheet = workbook.active for i in range(len(t0.rows)): list1 = [] for j in range(len(t0.columns)): list1.append(t0.cell(i,j).text) sheet.append(list1) workbook.save(filename = r"G:\6Tipdm\7python办公自动化\concat_word\来自word中的表.xlsx")结果如下:3、利用Python调整Word文档样式1)修改文字字体样式from docx import Document from docx.shared import Pt,RGBColor from docx.oxml.ns import qn doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test2.docx") for paragraph in doc.paragraphs: for run in paragraph.runs: run.font.bold = True run.font.italic = True run.font.underline = True run.font.strike = True run.font.shadow = True run.font.size = Pt(18) run.font.color.rgb = RGBColor(255,255,0) run.font.name = "宋体" # 设置像宋体这样的中文字体,必须添加下面2行代码 r = run._element.rPr.rFonts r.set(qn("w:eastAsia"),"宋体") doc.save(r"G:\6Tipdm\7python办公自动化\concat_word\_test1.docx")结果如下:2)修改段落样式① 对齐样式from docx import Document from docx.enum.text import WD_ALIGN_PARAGRAPH doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") print(doc.paragraphs[0].text) doc.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER # 这里设置的是居中对齐 doc.save(r"G:\6Tipdm\7python办公自动化\concat_word\对齐样式.docx") """ LEFT,CENTER,RIGHT,JUSTIFY,DISTRIBUTE,JUSTIFY_MED,JUSTIFY_HI,JUSTIFY_LOW,THAI_JUSTIFY """结果如下:② 行间距调整from docx import Document from docx.enum.text import WD_ALIGN_PARAGRAPH doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") for paragraph in doc.paragraphs: paragraph.paragraph_format.line_spacing = 5.0 doc.save(r"G:\6Tipdm\7python办公自动化\concat_word\行间距.docx")结果如下:③ 段前与段后间距这里提供代码,自行下去检验
② 解密pdf并保存为未加密的pdffrom PyPDF2 import PdfFileReader, PdfFileWriter pdf_reader = PdfFileReader(r"G:\6Tipdm\7python办公自动化\concat_pdf\时间序列.pdf") # 解密pdf pdf_reader.decrypt("a123456") pdf_writer = PdfFileWriter() for page in range(pdf_reader.getNumPages()): pdf_writer.addPage(pdf_reader.getPage(page)) with open("G:\\6Tipdm\\7python办公自动化\\concat_pdf\\未加密的时间序列.pdf", "wb") as out: pdf_writer.write(out)结果如下:章节三:python使用python-docx操作word1、python-docx库介绍该模块儿可以创建、修改Word(.docx)文件;此模块儿不属于python标准库,需要单独安装;python-docx使用官网: python-docx官网我们在安装此模块儿使用的是pip install python-docx,但是在导入的时候是import docx;2、Python读取Word文档内容注意:每进行一个操作,必须保存一下,否则等于白做;1)word文档结构介绍2)python-docx提取文字和文字块儿① python-docx提取文字有一个这样的docx文件,我们想要提取其中的文字,应该怎么做?代码如下:from docx import Document doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") print(doc.paragraphs) for paragraph in doc.paragraphs: print(paragraph.text)结果如下:② python-docx提取文字块儿from docx import Document doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") print(doc.paragraphs) paragraph = doc.paragraphs[0] runs = paragraph.runs print(runs) for run in paragraph.runs: print(run.text) ------------------------------ paragraph = doc.paragraphs[1] runs = paragraph.runs print(runs) for run in paragraph.runs: print(run.text)结果如下:3)利用Python向Word文档写入内容① 添加段落from docx import Document doc = Document(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") # print(doc.add_heading("一级标题", level=1)) 添加一级标题的时候出错,还没有解决! paragraph1 = doc.add_paragraph("这是一个段落") paragraph2 = doc.add_paragraph("这是第二个段落") doc.save(r"G:\6Tipdm\7python办公自动化\concat_word\test1.docx") """ 添加段落的时候,赋值给一个变量,方便我们后面进行格式调整; """结果如下:
代码如下:from PyPDF2 import PdfFileReader, PdfFileWriter pdf_reader = PdfFileReader(r"G:\6Tipdm\7python办公自动化\concat_pdf\时间序列.pdf") for page in range(pdf_reader.getNumPages()): pdf_writer = PdfFileWriter() pdf_writer.addPage(pdf_reader.getPage(page)) with open(f"G:\\6Tipdm\\7python办公自动化\\concat_pdf\\{page}.pdf", "wb") as out: pdf_writer.write(out)结果如下:2)旋转及排序pdf① 旋转pdf.rotateClockwise(90的倍数):顺时针旋转90度.rotateCounterClockwise(90的倍数):逆时针旋转90度from PyPDF2 import PdfFileReader, PdfFileWriter pdf_reader = PdfFileReader(r"G:\6Tipdm\7python办公自动化\concat_pdf\时间序列.pdf") pdf_writer = PdfFileWriter() for page in range(pdf_reader.getNumPages()): if page % 2 == 0: rotation_page = pdf_reader.getPage(page).rotateCounterClockwise(90) else: rotation_page = pdf_reader.getPage(page).rotateClockwise(90) pdf_writer.addPage(rotation_page) with open("G:\\6Tipdm\\7python办公自动化\\concat_pdf\\旋转.pdf", "wb") as out: pdf_writer.write(out) """ 上述代码中,我们循环遍历了这个pdf,对于偶数页我们逆时针旋转90°,对于奇数页我们顺时针旋转90°; 注意:旋转的角度只能是90的倍数; """其中一页效果展示如下:② 排序pdf需求:我们有一个PDF文件,我们需要倒序排列,应该怎么做呢?首先,我们来看python中,怎么倒叙打印一串数字,如下图所示。那么倒序排列一个pdf,思路同上,代码如下:from PyPDF2 import PdfFileReader, PdfFileWriter pdf_reader = PdfFileReader(r"G:\6Tipdm\7python办公自动化\concat_pdf\时间序列.pdf") pdf_writer = PdfFileWriter() for page in range(pdf_reader.getNumPages()-1, -1, -1): pdf_writer.addPage(pdf_reader.getPage(page)) with open("G:\\6Tipdm\\7python办公自动化\\concat_pdf\\倒序.pdf", "wb") as out: pdf_writer.write(out)结果如下:4、pdf批量加水印及加密、解密1)批量加水印from PyPDF2 import PdfFileReader, PdfFileWriter from copy import copy water = PdfFileReader(r"G:\6Tipdm\7python办公自动化\concat_pdf\水印.pdf") water_page = water.getPage(0) pdf_reader = PdfFileReader(r"G:\6Tipdm\7python办公自动化\concat_pdf\aa.pdf") pdf_writer = PdfFileWriter() for page in range(pdf_reader.getNumPages()): my_page = pdf_reader.getPage(page) new_page = copy(water_page) new_page.mergePage(my_page) pdf_writer.addPage(new_page) with open("G:\\6Tipdm\\7python办公自动化\\concat_pdf\\添加水印后的aa.pdf", "wb") as out: pdf_writer.write(out) """ 这里有一点需要注意:进行pdf合并的时候,我们希望“水印”在下面,文字在上面,因此是“水印”.mergePage(“图片页”) """结果如下:2)批量加密、解密这里所说的“解密”,是在知道pdf的密码下,去打开pdf,而不是暴力破解;① 加密pdffrom PyPDF2 import PdfFileReader, PdfFileWriter pdf_reader = PdfFileReader(r"G:\6Tipdm\7python办公自动化\concat_pdf\时间序列.pdf") pdf_writer = PdfFileWriter() for page in range(pdf_reader.getNumPages()): pdf_writer.addPage(pdf_reader.getPage(page)) # 添加密码 pdf_writer.encrypt("a123456") with open("G:\\6Tipdm\\7python办公自动化\\concat_pdf\\时间序列.pdf", "wb") as out: pdf_writer.write(out)结果如下:
2)利用pdfplumber提取表格并写入excelextract_table():如果一页有一个表格;extract_tables():如果一页有多个表格;import PyPDF2 import pdfplumber from openpyxl import Workbook with pdfplumber.open("餐饮企业综合分析.pdf") as p: page = p.pages[4] table = page.extract_table() print(table) workbook = Workbook() sheet = workbook.active for row in table: if not "".join() == "" sheet.append(row) workbook.save(filename = "新pdf.xlsx")结果如下:缺陷:可以看到,这里提取出来的表格有很多空行,怎么去掉这些空行呢?判断:将列表中每个元素都连接成一个字符串,如果还是一个空字符串那么肯定就是空行。import PyPDF2 import pdfplumber from openpyxl import Workbook with pdfplumber.open("餐饮企业综合分析.pdf") as p: page = p.pages[4] table = page.extract_table() print(table) workbook = Workbook() sheet = workbook.active for row in table: if not "".join([str(i) for i in row]) == "": sheet.append(row) workbook.save(filename = "新pdf.xlsx")结果如下:3、PDF合并及页面的排序和旋转1)分割及合并pdf① 合并pdf首先,我们有如下几个文件,可以发现这里共有三个PDF文件需要我们合并。同时可以发现他们的文件名都是有规律的(如果文件名,没有先后顺序,我们合并起来就没有意义了。)代码如下:from PyPDF2 import PdfFileReader, PdfFileWriter pdf_writer = PdfFileWriter() for i in range(1,len(os.listdir(r"G:\6Tipdm\7python办公自动化\concat_pdf"))+1): print(i*50+1,(i+1)*50) pdf_reader = PdfFileReader("G:\\6Tipdm\\7python办公自动化\\concat_pdf\{}-{}.pdf".format(i*50+1,(i+1)*50)) for page in range(pdf_reader.getNumPages()): pdf_writer.addPage(pdf_reader.getPage(page)) with open("G:\\6Tipdm\\7python办公自动化\\concat_pdf\merge.pdf", "wb") as out: pdf_writer.write(out)结果如下:② 拆分pdf这里有一个“时间序列.pdf”的文件,共3页,我们将其每一页存为一个PDF文件。
6)设置行高和列宽.row_dimensions[行编号].height = 行高.column_dimensions[列编号].width = 列宽workbook = load_workbook(filename="花园.xlsx") sheet = workbook.active # 设置第1行的高度 sheet.row_dimensions[1].height = 50 # 设置B列的宽度 sheet.column_dimensions["B"].width = 20 workbook.save(filename = "花园.xlsx") """ sheet.row_dimensions.height = 50 sheet.column_dimensions.width = 30 这两句代码,是将整个表的行高设置为50,列宽设置为30; """结果如下:7)合并单元格.merge_cells(待合并的格子编号).merge_cells(start_row=起始行号,start_column=起始列号,end_row=结束行号,end_column=结束列号) workbook = load_workbook(filename="花园.xlsx") sheet = workbook.active sheet.merge_cells("C1:D2") sheet.merge_cells(start_row=7,start_column=1,end_row=8,end_column=3) workbook.save(filename = "花园.xlsx")结果如下:当然,也有“取消合并单元格”,用法一致。.unmerge_cells(待合并的格子编号).unmerge_cells(start_row=起始行号,start_column=起始列号,end_row=结束行号,end_column=结束列号)章节二:python使用PyPDF2和pdfplumber操作pdf1、PyPDF2和pdfplumber库介绍PyPDF2官网: PyPDF2官网 ,可以更好的读取、写入、分割、合并PDF文件;pdfplumber官网:pdfplumber官网,可以更好地读取PDF文件内容和提取PDF中的表格;这两个库不属于python标准库,都需要单独安装;2、python提取PDF文字内容1)利用pdfplumber提取文字import PyPDF2 import pdfplumber with pdfplumber.open("餐饮企业综合分析.pdf") as p: page = p.pages[2] print(page.extract_text())结果如下:
⑨ .copy_worksheet():复制一个sheet表到另外一张excel表这个操作的实质,就是复制某个excel表中的sheet表,然后将文件存储到另外一张excel表中;workbook = load_workbook(filename = "a.xlsx") sheet = workbook.active print("a.xlsx中有这几个sheet表",workbook.sheetnames) sheet = workbook['姓名'] workbook.copy_worksheet(sheet) workbook.save(filename = "test.xlsx")结果如下:⑩ sheet.title:修改sheet表的名称.title = “新的sheet表名”workbook = load_workbook(filename = "a.xlsx") sheet = workbook.active print(sheet) sheet.title = "我是修改后的sheet名" print(sheet)结果如下:⑪ 创建新的excel表格文件from openpyxl import Workbook workbook = Workbook() sheet = workbook.active sheet.title = "表格1" workbook.save(filename = "新建的excel表格")结果如下:⑫ sheet.freeze_panes:冻结窗口.freeze_panes = “单元格”workbook = load_workbook(filename = "花园.xlsx") sheet = workbook.active print(sheet) sheet.freeze_panes = "C3" workbook.save(filename = "花园.xlsx") """ 冻结窗口以后,你可以打开源文件,进行检验; """结果如下:⑬ sheet.auto_filter.ref:给表格添加“筛选器”.auto_filter.ref = sheet.dimension 给所有字段添加筛选器;.auto_filter.ref = “A1” 给A1这个格子添加“筛选器”,就是给第一列添加“筛选器”;workbook = load_workbook(filename = "花园.xlsx") sheet = workbook.active print(sheet) sheet.auto_filter.ref = sheet["A1"] workbook.save(filename = "花园.xlsx")结果如下:4、批量调整字体和样式1)修改字体样式Font(name=字体名称,size=字体大小,bold=是否加粗,italic=是否斜体,color=字体颜色)from openpyxl.styles import Font from openpyxl import load_workbook workbook = load_workbook(filename="花园.xlsx") sheet = workbook.active cell = sheet["A1"] font = Font(name="微软雅黑",size=20,bold=True,italic=True,color="FF0000") cell.font = font workbook.save(filename = "花园.xlsx") """ 这个color是RGB的16进制表示,自己下去百度学习; """结果如下:
③ 在python中使用excel函数公式(很有用)# 这是我们在excel中输入的公式 =IF(RIGHT(C2,2)="cm",C2,SUBSTITUTE(C2,"m","")*100&"cm") # 那么,在python中怎么插入excel公式呢? workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) sheet["D1"] = "标准身高" for i in range(2,16): sheet["D{}".format(i)] = '=IF(RIGHT(C{},2)="cm",C{},SUBSTITUTE(C{},"m","")*100&"cm")'.format(i,i,i) workbook.save(filename = "test.xlsx")结果如下:此时,你肯定会好奇,python究竟支持写哪些“excel函数公式”呢?我们可以使用如下操作查看一下。import openpyxl from openpyxl.utils import FORMULAE print(FORMULAE)结果如下:④ .insert_cols()和.insert_rows():插入空行和空列.insert_cols(idx=数字编号, amount=要插入的列数),插入的位置是在idx列数的左侧插入;.insert_rows(idx=数字编号, amount=要插入的行数),插入的行数是在idx行数的下方插入;workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) sheet.insert_cols(idx=4,amount=2) sheet.insert_rows(idx=5,amount=4) workbook.save(filename = "test.xlsx")结果如下:⑤ .delete_rows()和.delete_cols():删除行和列.delete_rows(idx=数字编号, amount=要删除的行数).delete_cols(idx=数字编号, amount=要删除的列数)workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) # 删除第一列,第一行 sheet.delete_cols(idx=1) sheet.delete_rows(idx=1) workbook.save(filename = "test.xlsx")结果如下:⑥ .move_range():移动格子.move_range(“数据区域”,rows=,cols=):正整数为向下或向右、负整数为向左或向上;# 向左移动两列,向下移动两行 sheet.move_range("C1:D4",rows=2,cols=-1)演示效果如下:⑦ .create_sheet():创建新的sheet表格.create_sheet(“新的sheet名”):创建一个新的sheet表;workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) workbook.create_sheet("我是一个新的sheet") print(workbook.sheetnames) workbook.save(filename = "test.xlsx")结果如下:⑧ .remove():删除某个sheet表.remove(“sheet名”):删除某个sheet表;workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(workbook.sheetnames) # 这个相当于激活的这个sheet表,激活状态下,才可以操作; sheet = workbook['我是一个新的sheet'] print(sheet) workbook.remove(sheet) print(workbook.sheetnames) workbook.save(filename = "test.xlsx")结果如下:
6)获取某个格子的行数、列数、坐标workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) cell1 = sheet["A1"] cell2 = sheet["C11"] print(cell1.value, cell1.row, cell1.column, cell1.coordinate) print(cell2.value, cell2.row, cell2.column, cell2.coordinate) """ .row 获取某个格子的行数; .columns 获取某个格子的列数; .corordinate 获取某个格子的坐标; """结果如下:7)获取一系列格子① sheet[]方式workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) # 获取A1:C2区域的值 cell = sheet["A1:C2"] print(cell) for i in cell: for j in i: print(j.value)结果如下:特别的:如果我们只想获取“A列”,或者获取“A-C列”,可以采取如下方式:sheet["A"] --- 获取A列的数据 sheet["A:C"] --- 获取A,B,C三列的数据 sheet[5] --- 只获取第5行的数据② .iter_rows()方式当然有.iter_rows()方式,肯定也会有.iter_cols()方式,只不过一个是按行读取,一个是按列读取。workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) # 按行获取值 for i in sheet.iter_rows(min_row=2, max_row=5, min_col=1, max_col=2): for j in i: print(j.value) # 按列获取值 for i in sheet.iter_cols(min_row=2, max_row=5, min_col=1, max_col=2): for j in i: print(j.value)结果如下:③ sheet.rows()帮助我们获取所有行workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) for i in sheet.rows: print(i)结果如下:3、python如何向excel中写入某些内容?1)修改表格中的内容① 向某个格子中写入内容并保存workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) sheet["A1"] = "哈喽" # 这句代码也可以改为cell = sheet["A1"] cell.value = "哈喽" workbook.save(filename = "哈喽.xlsx") """ 注意:我们将“A1”单元格的数据改为了“哈喽”,并另存为了“哈喽.xlsx”文件。 如果我们保存的时候,不修改表名,相当于直接修改源文件; """结果如下:② .append():向表格中插入行数据.append()方式:会在表格已有的数据后面,增添这些数(按行插入);这个操作很有用,爬虫得到的数据,可以使用该方式保存成Excel文件;workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) data = [ ["唐僧","男","180cm"], ["孙悟空","男","188cm"], ["猪八戒","男","175cm"], ["沙僧","男","176cm"], ] for row in data: sheet.append(row) workbook.save(filename = "test.xlsx")结果如下:
章节一:python使用openpyxl操作excel1、openpyxl库介绍openpyxl最好用的python操作excel表格库,不接受反驳;openpyxl官网链接:openpyxl官网openpyxl只支持【.xlsx / .xlsm / .xltx / .xltm】格式的文件;2、python怎么打开及读取表格内容?1)Excel表格述语这里需要大家仔细查看图中的每一项内容,知道什么是“行(row)、列(column)”?什么是“格子(cell)”?什么是“sheet表”?2)打开Excel表格并获取表格名称from openpyxl import load_workbook workbook = load_workbook(filename = "test.xlsx") workbook.sheetnames结果如下:3)通过sheet名称获取表格from openpyxl import load_workbook workbook = load_workbook(filename = "test.xlsx") workbook.sheetnames sheet = workbook["Sheet1"] print(sheet)结果如下:4)获取表格的尺寸大小这里所说的尺寸大小,指的是excel表格中的数据有几行几列,针对的是不同的sheet而言。sheet.dimensions结果如下:5)获取表格内某个格子的数据① sheet[“A1”]方式workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) cell1 = sheet["A1"] cell2 = sheet["C11"] print(cell1.value, cell2.value) """ workbook.active 打开激活的表格; sheet["A1"] 获取A1格子的数据; cell.value 获取格子中的值; """结果如下:② sheet.cell(row=, column=)方式这种方式更简单,大家可以对比这两种方式;workbook = load_workbook(filename = "test.xlsx") sheet = workbook.active print(sheet) cell1 = sheet.cell(row = 1,column = 1) cell2 = sheet.cell(row = 11,column = 3) print(cell1.value, cell2.value)结果如下:
3)岗位名字段的处理① 岗位名字段的探索df["岗位名"].value_counts() df["岗位名"] = df["岗位名"].apply(lambda x:x.lower())说明:首先我们对每个岗位出现的频次做一个统计,可以看出“岗位名字段”太杂乱,不便于我们做统计分析。接着我们将岗位名中的大写英文字母统一转换为小写字母,也就是说“AI”和“Ai”属于同一个东西。② 构造想要分析的目标岗位,做一个数据筛选job_info.shape target_job = ['算法', '开发', '分析', '工程师', '数据', '运营', '运维'] index = [df["岗位名"].str.count(i) for i in target_job] index = np.array(index).sum(axis=0) > 0 job_info = df[index] job_info.shape说明:首先我们构造了如上七个目标岗位的关键字眼。然后利用count()函数统计每一条记录中,是否包含这七个关键字眼,如果包含就保留这个字段,不过不包含就删除这个字段。最后查看筛选之后还剩余多少条记录。③ 目标岗位标准化处理(由于目标岗位太杂乱,我们需要统一一下)job_list = ['数据分析', "数据统计","数据专员",'数据挖掘', '算法', '大数据','开发工程师', '运营', '软件工程', '前端开发', '深度学习', 'ai', '数据库', '数据库', '数据产品', '客服', 'java', '.net', 'andrio', '人工智能', 'c++', '数据管理',"测试","运维"] job_list = np.array(job_list) def rename(x=None,job_list=job_list): index = [i in x for i in job_list] if sum(index) > 0: return job_list[index][0] else: return x job_info["岗位名"] = job_info["岗位名"].apply(rename) job_info["岗位名"].value_counts() # 数据统计、数据专员、数据分析统一归为数据分析 job_info["岗位名"] = job_info["岗位名"].apply(lambda x:re.sub("数据专员","数据分析",x)) job_info["岗位名"] = job_info["岗位名"].apply(lambda x:re.sub("数据统计","数据分析",x))说明:首先我们定义了一个想要替换的目标岗位job_list,将其转换为ndarray数组。然后定义一个函数,如果某条记录包含job_list数组中的某个关键词,那么就将该条记录替换为这个关键词,如果某条记录包含job_list数组中的多个关键词,我们只取第一个关键词替换该条记录。接着使用value_counts()函数统计一下替换后的各岗位的频次。最后,我们将“数据专员”、“数据统计”统一归为“数据分析”。4)工资水平字段的处理工资水平字段的数据类似于“20-30万/年”、“2.5-3万/月”和“3.5-4.5千/月”这样的格式。我们需要做一个统一的变化,将数据格式转换为“元/月”,然后取出这两个数字,求一个平均值。job_info["工资"].str[-1].value_counts() job_info["工资"].str[-3].value_counts() index1 = job_info["工资"].str[-1].isin(["年","月"]) index2 = job_info["工资"].str[-3].isin(["万","千"]) job_info = job_info[index1 & index2] def get_money_max_min(x): try: if x[-3] == "万": z = [float(i)*10000 for i in re.findall("[0-9]+\.?[0-9]*",x)] elif x[-3] == "千": z = [float(i) * 1000 for i in re.findall("[0-9]+\.?[0-9]*", x)] if x[-1] == "年": z = [i/12 for i in z] return z except: return x salary = job_info["工资"].apply(get_money_max_min) job_info["最低工资"] = salary.str[0] job_info["最高工资"] = salary.str[1] job_info["工资水平"] = job_info[["最低工资","最高工资"]].mean(axis=1)说明:首先我们做了一个数据筛选,针对于每一条记录,如果最后一个字在“年”和“月”中,同时第三个字在“万”和“千”中,那么就保留这条记录,否则就删除。接着定义了一个函数,将格式统一转换为“元/月”。最后将最低工资和最高工资求平均值,得到最终的“工资水平”字段。5)工作地点字段的处理由于整个数据是关于全国的数据,涉及到的城市也是特别多。我们需要自定义一个常用的目标工作地点字段,对数据做一个统一处理。#job_info["工作地点"].value_counts() address_list = ['北京', '上海', '广州', '深圳', '杭州', '苏州', '长沙', '武汉', '天津', '成都', '西安', '东莞', '合肥', '佛山', '宁波', '南京', '重庆', '长春', '郑州', '常州', '福州', '沈阳', '济南', '宁波', '厦门', '贵州', '珠海', '青岛', '中山', '大连','昆山',"惠州","哈尔滨","昆明","南昌","无锡"] address_list = np.array(address_list) def rename(x=None,address_list=address_list): index = [i in x for i in address_list] if sum(index) > 0: return address_list[index][0] else: return x job_info["工作地点"] = job_info["工作地点"].apply(rename)说明:首先我们定义了一个目标工作地点列表,将其转换为ndarray数组。接着定义了一个函数,将原始工作地点记录,替换为目标工作地点中的城市。6)公司类型字段的处理这个很容易,就不详细说明了。job_info.loc[job_info["公司类型"].apply(lambda x:len(x)<6),"公司类型"] = np.nan job_info["公司类型"] = job_info["公司类型"].str[2:-2]7)行业字段的处理每个公司的行业字段可能会有多个行业标签,但是我们默认以第一个作为该公司的行业标签。# job_info["行业"].value_counts() job_info["行业"] = job_info["行业"].apply(lambda x:re.sub(",","/",x)) job_info.loc[job_info["行业"].apply(lambda x:len(x)<6),"行业"] = np.nan job_info["行业"] = job_info["行业"].str[2:-2].str.split("/").str[0]8)经验与学历字段的处理关于这个字段的数据处理,我很是思考了一会儿,不太好叙述,放上代码自己下去体会。job_info["学历"] = job_info["经验与学历"].apply(lambda x:re.findall("本科|大专|应届生|在校生|硕士",x)) def func(x): if len(x) == 0: return np.nan elif len(x) == 1 or len(x) == 2: return x[0] else: return x[2] job_info["学历"] = job_info["学历"].apply(func)9)工作描述字段的处理对于每一行记录,我们去除停用词以后,做一个jieba分词。with open(r"G:\8泰迪\python_project\51_job\stopword.txt","r") as f: stopword = f.read() stopword = stopword.split() stopword = stopword + ["任职","职位"," "] job_info["工作描述"] = job_info["工作描述"].str[2:-2].apply(lambda x:x.lower()).apply(lambda x:"".join(x))\ .apply(jieba.lcut).apply(lambda x:[i for i in x if i not in stopword]) job_info.loc[job_info["工作描述"].apply(lambda x:len(x) < 6),"工作描述"] = np.nan10)公司规模字段的处理#job_info["公司规模"].value_counts() def func(x): if x == "['少于50人']": return "<50" elif x == "['50-150人']": return "50-150" elif x == "['150-500人']": return '150-500' elif x == "['500-1000人']": return '500-1000' elif x == "['1000-5000人']": return '1000-5000' elif x == "['5000-10000人']": return '5000-10000' elif x == "['10000人以上']": return ">10000" else: return np.nan job_info["公司规模"] = job_info["公司规模"].apply(func)、11)构造新数据我们针对最终清洗干净的数据,选取需要分析的字段,做一个数据存储。feature = ["公司名","岗位名","工作地点","工资水平","发布日期","学历","公司类型","公司规模","行业","工作描述"]final_df = job_info[feature] final_df.to_excel(r"G:\8泰迪\python_project\51_job\词云图.xlsx",encoding="gbk",index=None)4、关于“工作描述”字段的特殊处理由于我们之后需要针对不同的岗位名做不同的词云图处理,并且是在tableau中做可视化展示,因此我们需要按照岗位名分类,求出不同岗位下各关键词的词频统计。import numpy as np import pandas as pd import re import jieba import warnings warnings.filterwarnings("ignore") df = pd.read_excel(r"G:\8泰迪\python_project\51_job\new_job_info1.xlsx",encoding="gbk") df def get_word_cloud(data=None, job_name=None): words = [] describe = data['工作描述'][data['岗位名'] == job_name].str[1:-1] describe.dropna(inplace=True) [words.extend(i.split(',')) for i in describe] words = pd.Series(words) word_fre = words.value_counts() return word_fre zz = ['数据分析', '算法', '大数据','开发工程师', '运营', '软件工程','运维', '数据库','java',"测试"] for i in zz: word_fre = get_word_cloud(data=df, job_name='{}'.format(i)) word_fre = word_fre[1:].reset_index()[:100] word_fre["岗位名"] = pd.Series("{}".format(i),index=range(len(word_fre))) word_fre.to_csv(r"G:\8泰迪\python_project\51_job\词云图\bb.csv", mode='a',index=False, header=None,encoding="gbk")
本文大纲1、项目背景 随着科技的飞速发展,数据呈现爆发式的增长,任何人都摆脱不了与数据打交道,社会对于“数据”方面的人才需求也在不断增大。因此了解当下企业究竟需要招聘什么样的人才?需要什么样的技能?不管是对于在校生,还是对于求职者来说,都显得很有必要。 本文基于这个问题,针对51job招聘网站,爬取了全国范围内大数据、数据分析、数据挖掘、机器学习、人工智能等相关岗位的招聘信息。分析比较了不同岗位的薪资、学历要求;分析比较了不同区域、行业对相关人才的需求情况;分析比较了不同岗位的知识、技能要求等。 做完以后的项目效果如下: 动态效果如下:2、信息的爬取(基于51job招聘网站的数据爬取)爬取岗位:大数据、数据分析、机器学习、人工智能等相关岗位;爬取字段:公司名、岗位名、工作地址、薪资、发布时间、工作描述、公司类型、员工人数、所属行业;说明:基于51job招聘网站,我们搜索全国对于“数据”岗位的需求,大概有2000页。我们爬取的字段,既有一级页面的相关信息,还有二级页面的部分信息;爬取思路:先针对某一页数据的一级页面做一个解析,然后再进行二级页面做一个解析,最后再进行翻页操作;使用工具:Python+requests+lxml+pandas+time网站解析方式:Xpath1)导入相关库import requests import pandas as pd from pprint import pprint from lxml import etree import time import warnings warnings.filterwarnings("ignore")2)关于翻页的说明# 第一页的特点 https://search.51job.com/list/000000,000000,0000,00,9,99,%25E6%2595%25B0%25E6%258D%25AE,2,1.html? # 第二页的特点 https://search.51job.com/list/000000,000000,0000,00,9,99,%25E6%2595%25B0%25E6%258D%25AE,2,2.html? # 第三页的特点 https://search.51job.com/list/000000,000000,0000,00,9,99,%25E6%2595%25B0%25E6%258D%25AE,2,3.html?注意:通过对于页面的观察,可以看出,就一个地方的数字变化了,因此只需要做字符串拼接,然后循环爬取即可。3)完整的爬取代码import requests import pandas as pd from pprint import pprint from lxml import etree import time import warnings warnings.filterwarnings("ignore") for i in range(1,1501): print("正在爬取第" + str(i) + "页的数据") url_pre = "https://search.51job.com/list/000000,000000,0000,00,9,99,%25E6%2595%25B0%25E6%258D%25AE,2," url_end = ".html?" url = url_pre + str(i) + url_end headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36' } web = requests.get(url, headers=headers) web.encoding = "gbk" dom = etree.HTML(web.text) # 1、岗位名称 job_name = dom.xpath('//div[@class="dw_table"]/div[@class="el"]//p/span/a[@target="_blank"]/@title') # 2、公司名称 company_name = dom.xpath('//div[@class="dw_table"]/div[@class="el"]/span[@class="t2"]/a[@target="_blank"]/@title') # 3、工作地点 address = dom.xpath('//div[@class="dw_table"]/div[@class="el"]/span[@class="t3"]/text()') # 4、工资 salary_mid = dom.xpath('//div[@class="dw_table"]/div[@class="el"]/span[@class="t4"]') salary = [i.text for i in salary_mid] # 5、发布日期 release_time = dom.xpath('//div[@class="dw_table"]/div[@class="el"]/span[@class="t5"]/text()') # 6、获取二级网址url deep_url = dom.xpath('//div[@class="dw_table"]/div[@class="el"]//p/span/a[@target="_blank"]/@href') RandomAll = [] JobDescribe = [] CompanyType = [] CompanySize = [] Industry = [] for i in range(len(deep_url)): web_test = requests.get(deep_url[i], headers=headers) web_test.encoding = "gbk" dom_test = etree.HTML(web_test.text) # 7、爬取经验、学历信息,先合在一个字段里面,以后再做数据清洗。命名为random_all random_all = dom_test.xpath('//div[@class="tHeader tHjob"]//div[@class="cn"]/p[@class="msg ltype"]/text()') # 8、岗位描述性息 job_describe = dom_test.xpath('//div[@class="tBorderTop_box"]//div[@class="bmsg job_msg inbox"]/p/text()') # 9、公司类型 company_type = dom_test.xpath('//div[@class="tCompany_sidebar"]//div[@class="com_tag"]/p[1]/@title') # 10、公司规模(人数) company_size = dom_test.xpath('//div[@class="tCompany_sidebar"]//div[@class="com_tag"]/p[2]/@title') # 11、所属行业(公司) industry = dom_test.xpath('//div[@class="tCompany_sidebar"]//div[@class="com_tag"]/p[3]/@title') # 将上述信息保存到各自的列表中 RandomAll.append(random_all) JobDescribe.append(job_describe) CompanyType.append(company_type) CompanySize.append(company_size) Industry.append(industry) # 为了反爬,设置睡眠时间 time.sleep(1) # 由于我们需要爬取很多页,为了防止最后一次性保存所有数据出现的错误,因此,我们每获取一夜的数据,就进行一次数据存取。 df = pd.DataFrame() df["岗位名称"] = job_name df["公司名称"] = company_name df["工作地点"] = address df["工资"] = salary df["发布日期"] = release_time df["经验、学历"] = RandomAll df["公司类型"] = CompanyType df["公司规模"] = CompanySize df["所属行业"] = Industry df["岗位描述"] = JobDescribe # 这里在写出过程中,有可能会写入失败,为了解决这个问题,我们使用异常处理。 try: df.to_csv("job_info.csv", mode="a+", header=None, index=None, encoding="gbk") except: print("当页数据写入失败") time.sleep(1) print("数据爬取完毕,是不是很开心!!!") 这里可以看到,我们爬取了1000多页的数据做最终的分析。因此每爬取一页的数据,做一次数据存储,避免最终一次性存储导致失败。同时根据自己的测试,有一些页数进行数据存储,会导致失败,为了不影响后面代码的执行,我们使用了“try-except”异常处理。 在一级页面中,我们爬取了“岗位名称”,“公司名称”,“工作地点”,“工资”,“发布日期”,“二级网址的url”这几个字段。 在二级页面中,我们爬取了“经验、学历信息”,“岗位描述”,“公司类型”,“公司规模”,“所属行业”这几个字段。3、数据预处理 从爬取到的数据中截取部分做了一个展示,可以看出数据很乱。杂乱的数据并不利于我们的分析,因此需要根据研究的目标做一个数据预处理,得到我们最终可以用来做可视化展示的数据。1)相关库的导入及数据的读取df = pd.read_csv(r"G:\8泰迪\python_project\51_job\job_info1.csv",engine="python",header=None) # 为数据框指定行索引 df.index = range(len(df)) # 为数据框指定列索引 df.columns = ["岗位名","公司名","工作地点","工资","发布日期","经验与学历","公司类型","公司规模","行业","工作描述"]2)数据去重我们认为一个公司的公司名和和发布的岗位名一致,就看作是重复值。因此,使用drop_duplicates(subset=[])函数,基于“岗位名”和“公司名”做一个重复值的剔除。# 去重之前的记录数 print("去重之前的记录数",df.shape) # 记录去重 df.drop_duplicates(subset=["公司名","岗位名"],inplace=True) # 去重之后的记录数 print("去重之后的记录数",df.shape)
③ 第三步def functions(x): if x.iloc[0]==1 and x.iloc[1]==1 and x.iloc[2]==1: return "重要价值客户" elif x.iloc[0]==1 and x.iloc[1]==1 and x.iloc[2]==0: return "潜力客户" elif x.iloc[0]==1 and x.iloc[1]==0 and x.iloc[2]==1: return "重要深耕客户" elif x.iloc[0]==1 and x.iloc[1]==0 and x.iloc[2]==0: return "新客户" elif x.iloc[0]==0 and x.iloc[1]==1 and x.iloc[2]==1: return "重要唤回客户" elif x.iloc[0]==0 and x.iloc[1]==1 and x.iloc[2]==0: return "一般客户" elif x.iloc[0]==0 and x.iloc[1]==0 and x.iloc[2]==1: return "重要挽回客户" elif x.iloc[0]==0 and x.iloc[1]==0 and x.iloc[2]==0: return "流失客户" df2["标签"] = df2[["R-SCORE是否大于均值","F-SCORE是否大于均值","M-SCORE是否大于均值"]].apply(functions,axis=1) df2.sample(10)结果如下:4)可视化展示① 绘制不同类型客户的人数对比df3 = df2.groupby("标签").agg({"标签":"count"}) df3["不同客户的占比"] = df3["标签"].apply(lambda x:x/np.sum(df3["标签"])) df3 = df3.sort_values(by="标签",ascending=True) plt.figure(figsize=(6,4),dpi=100) x = df3.index y = df3["标签"] plt.barh(x,height=0.5,width=y,align="center") plt.title("不同类型客户的人数对比") for x,y in enumerate(y): plt.text(y+450,x,y,ha="center",va="center",fontsize=14) plt.xticks(np.arange(0,10001,2000)) plt.tight_layout() plt.savefig("不同类型客户的人数对比",dpi=300)结果如下:② 绘制不同类型客户人数占比图df3 = df2.groupby("标签").agg({"标签":"count"}) df3["不同客户的占比"] = df3["标签"].apply(lambda x:x/np.sum(df3["标签"])) df3 = df3.sort_values(by="标签",ascending=True) plt.figure(figsize=(7,4),dpi=100) x = df3["不同客户的占比"] labels = ['潜力客户', '一般客户', '重要价值客户', '重要唤回客户', '重要深耕客户', '新客户', '重要挽回客户', '流失客户'] colors = ['#9999ff','#ff9999','#7777aa','#2442aa','#dd5555','deeppink','yellowgreen','lightskyblue'] explode = [0,0,0,0,0,0,0,0] patches,l_text = plt.pie(x,labels=labels,colors=colors, explode=explode,startangle=90,counterclock=False) for t in l_text: t.set_size(0) plt.axis("equal") plt.legend(loc=(0.001,0.001),frameon=False) plt.title("不同类型客户人数占比图") plt.savefig("不同类型客户人数占比图",dpi=300)结果如下:
③ 粽子售卖价格区间划分def price_range(x): #按照淘宝推荐划分价格区间 if x <= 50: return '<50元' elif x <= 100: return '50-100元' elif x <= 300: return '100-300元' elif x <= 500: return '300-500元' elif x <= 1000: return '500-1000元' else: return '>1000元' df["价格区间"] = df["价格"].apply(price_range) df["价格区间"].value_counts()结果如下:由于数据不是很多,没有很多字段,也就没有很多乱数据。因此,这里也没有做数据去重、缺失值填充等操作。所以,大家可以下去获取更多字段,更多数据,用于数据分析。数据可视化俗话说:字不如表,表不如图。通过可视化分析,我们可以将数据背后 “隐藏” 的信息,给展现出来。拓展: 当然,这里只是 “抛砖引玉”,我并没有获取太多的数据,也没有获取太多的字段。这里给学习的朋友当一个作业题,自己下去用更多的数据、更多的字段,做更透彻的分析。在这里,我们基于以下几个问题,做一个可视化展示,分别是:① 粽子销售店铺Top10柱形图;② 粽子口味排名Top5柱形图;③ 粽子销售价格区间划分饼图;④ 粽子商品名称词云图;鉴于整个文章排版,本文可视化部分的代码均可在本文末尾获取。① 粽子销售店铺Top10柱形图结论分析:去年,我们分析了一些月饼的数据,“五芳斋”、“北京稻香村”这几个牌子记忆犹新,可谓是做月饼、粽子的老店。像 “三全” 和 “思念”,在我印象中一直以为它们只做水饺和汤圆,粽子是否值得一试呢?当然,这里还有一些新的牌子,像 “诸老大”、“稻香私房”等一些牌子,大家都可以下去搜索一下。买东西,就是要精挑细选,品牌也重要。② 粽子口味排名Top5柱形图结论分析:在我印象中,小时候一直吃的最多的就是 “甜粽子”,直到我上了初中才知道,粽子还可以有肉?当然,从图中可以看出,卖 “鲜肉粽” 的店铺还是居多,毕竟这个送人,还是显得高端一些。这里还有一些味道,像 “蜜枣粽”、“豆沙粽”,我基本没吃过。如果你送人,你会送什么口味的呢?③ 粽子销售价格区间划分饼图结论分析:这里,我故意把价格区间细分。这个饼图也很符合实际,毕竟每年就过一次端午节,还是以薄利多销为主,接近80%的粽子,售价都在100元以下。当然,还有一些中档的粽子,价格在100-300元。大于300元,我觉得也没有吃的必要,反正我是不会花这么多钱去买粽子。④ 粽子商品名称词云图结论分析:从图中,可以大致看出商家的卖点了。毕竟是节日,“送礼”、“礼品” 体现了节日氛围。“猪肉”、“豆沙” 体现了粽子口味。当然,它是否是 “早餐” 好选择呢?购买的话,还支持 “团购” 哦。⑤ 图形组合为大屏本文的可视化采用的pyecharts库,进行绘制。我们先单独做好每一张图,然后进行图形整合,即可做出一张漂亮的可视化大屏。关于如何制作,可以私信获取代码!
今年,黄同学用Python爬取了某网站上面的 “粽子数据” 进行分析,看看有啥发现吧!本文就从数据爬取、数据清洗、数据可视化,三个方便,但你简单完成一个小型的数据分析项目,让你对知识能够有一个综合的运用。整个思路如下:爬取网页: https://www.jd.com/爬取说明: 基于某网站,我们搜索网站“粽子”数据,大概有100页。我们爬取的字段,既有一级页面的相关信息,还有二级页面的部分信息;爬取思路: 先针对某一页数据的一级页面做一个解析,然后再进行二级页面做一个解析,最后再进行翻页操作;爬取字段: 分别是粽子的名称(标题)、价格、品牌(店铺)、类别(口味);使用工具: requests+lxml+pandas+time+re+pyecharts网站解析方式: xpath最终的效果如下:数据爬取该网站,一般是动态加载的,也就是说,采用一般方式只能爬取到某个页面的前30个数据(一个页面一共60个数据)。基于本文,我仅用最基本的方法,爬取了每个页面的前30条数据(如果大家有兴趣,可以 自行下去爬取所有的数据)。那么,本文究竟爬取了哪些字段呢?我给大家做一个展示,大家有兴趣额,可以爬取更多的字段,做更为详细的分析。下面为大家展示爬虫代码:import pandas as pd import requests from lxml import etree import chardet import time import re def get_CI(url): headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; X64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36'} rqg = requests.get(url,headers=headers) rqg.encoding = chardet.detect(rqg.content)['encoding'] html = etree.HTML(rqg.text) # 价格 p_price = html.xpath('//div/div[@class="p-price"]/strong/i/text()') # 名称 p_name = html.xpath('//div/div[@class="p-name p-name-type-2"]/a/em') p_name = [str(p_name[i].xpath('string(.)')) for i in range(len(p_name))] # 深层url deep_ur1 = html.xpath('//div/div[@class="p-name p-name-type-2"]/a/@href') deep_url = ["http:" + i for i in deep_ur1] # 从这里开始,我们获取“二级页面”的信息 brands_list = [] kinds_list = [] for i in deep_url: rqg = requests.get(i,headers=headers) rqg.encoding = chardet.detect(rqg.content)['encoding'] html = etree.HTML(rqg.text) # 品牌 brands = html.xpath('//div/div[@class="ETab"]//ul[@id="parameter-brand"]/li/@title') brands_list.append(brands) # 类别 kinds = re.findall('>类别:(.*?)</li>',rqg.text) kinds_list.append(kinds) data = pd.DataFrame({'名称':p_name,'价格':p_price,'品牌':brands_list,'类别':kinds_list}) return(data) x = "https://search.jd.com/Search?keyword=%E7%B2%BD%E5%AD%90&qrst=1&wq=%E7%B2%BD%E5%AD%90&stock=1&page=" url_list = [x + str(i) for i in range(1,200,2)] res = pd.DataFrame(columns=['名称','价格','品牌','类别']) # 这里进行“翻页”操作 for url in url_list: res0 = get_CI(url) res = pd.concat([res,res0]) time.sleep(3) # 保存数据 res.to_csv('aliang.csv',encoding='utf_8_sig')最终爬取到的数据,长这样。数据清洗从上图可以看到,整个数据算是很整齐的,不是特别乱,我们只做一些简单的操作即可。先使用pandas库,来读取数据。import pandas as pd df = pd.read_excel("粽子.xlsx",index_col=False) df.head()结果如下:我们分别针对 “品牌”、“类别‘两个字段,去掉中括号。df["品牌"] = df["品牌"].apply(lambda x: x[1:-1]) df["类别"] = df["类别"].apply(lambda x: x[1:-1]) df.head()结果如下:① 粽子品牌排名前10的店铺df["品牌"].value_counts()[:10]结果如下:② 粽子口味排名前5的味道def func1(x): if x.find("甜") > 0: return "甜粽子" else: return x df["类别"] = df["类别"].apply(func1) df["类别"].value_counts()[1:6]结果如下:
1. 演示数据本文的所有演示数据,均是基于下方的四张表。下面这四张表大家应该不陌生,这就是网传50道经典MySQL面试题中使用到的几张原表。关于下方各表之间的关联关系,我就不给大家说明了,仔细观察字段名,应该就可以发现。2. pandasql的使用1)简介pandas中的DataFrame是一个二维表格,数据库中的表也是一个二维表格,因此在pandas中使用sql语句就显得水到渠成,pandasql使用SQLite作为其操作数据库,同时Python自带SQLite模块,不需要安装,便可直接使用。这里有一点需要注意的是:使用pandasql读取DataFrame中日期格式的列,默认会读取年月日、时分秒,因此我们要学会使用sqlite中的日期处理函数,方便我们转换日期格式,下方提供sqlite中常用函数大全,希望对你有帮助。sqlite函数大全:http://suo.im/5DWraE导入相关库:import pandas as pd from pandasql import sqldf2)声明全局变量的2种方式① 在使用之前,声明该全局变量;② 一次性声明好全局变量;① 在使用之前,声明该全局变量df1 = pd.read_excel("student.xlsx") df2 = pd.read_excel("sc.xlsx") df3 = pd.read_excel("course.xlsx") df4 = pd.read_excel("teacher.xlsx") global df1 global df2 global df3 global df4 query1 = "select * from df1 limit 5" query2 = "select * from df2 limit 5" query3 = "select * from df3" query4 = "select * from df4" sqldf(query1) sqldf(query2) sqldf(query3) sqldf(query4)部分结果如下:② 一次性声明好全局变量df1 = pd.read_excel("student.xlsx") df2 = pd.read_excel("sc.xlsx") df3 = pd.read_excel("course.xlsx") df4 = pd.read_excel("teacher.xlsx") pysqldf = lambda q: sqldf(q, globals()) query1 = "select * from df1 limit 5" query2 = "select * from df2 limit 5" query3 = "select * from df3" query4 = "select * from df4" sqldf(query1) sqldf(query2) sqldf(query3) sqldf(query4)部分结果如下:3)写几个简单的SQL语句① 查看sqlite的版本student = pd.read_excel("student.xlsx") pysqldf = lambda q: sqldf(q, globals()) query1 = """ select sqlite_version(*) """ pysqldf(query1)结果如下:② where筛选student = pd.read_excel("student.xlsx") pysqldf = lambda q: sqldf(q, globals()) query1 = """ select * from student where strftime('%Y-%m-%d',sage) = '1990-01-01' """ pysqldf(query1)结果如下:③ 多表连接student = pd.read_excel("student.xlsx") sc = pd.read_excel("sc.xlsx") pysqldf = lambda q: sqldf(q, globals()) query2 = """ select * from student s join sc on s.sid = sc.sid """ pysqldf(query2)部分结果如下:④ 分组聚合student = pd.read_excel("student.xlsx") sc = pd.read_excel("sc.xlsx") pysqldf = lambda q: sqldf(q, globals()) query2 = """ select s.sname as 姓名,sum(sc.score) as 总分 from student s join sc on s.sid = sc.sid group by s.sname """ pysqldf(query2)结果如下:⑤ union查询student = pd.read_excel("student.xlsx") pysqldf = lambda q: sqldf(q, globals()) query1 = """ select * from student where strftime('%Y-%m',sage) = '1990-01' union select * from student where strftime('%Y-%m',sage) = '1990-12' """ pysqldf(query1)结果如下:
登录MySQL数据库摩天轮主页链接:https://www.modb.pro/在进入实训平台之前,我们需要先登录。接着,进入该链接https://www.modb.pro/market/150159?cp,就可以直接进入数据库在线实训平台了。主界面大致如下:登录MySQL服务器:mysql -uroot -p --输入数据库列表页面中的密码--密码在数据库列表页面中:登陆成功后,界面如图所示:MySQL数据库的使用1. 查看系统有哪些数据库mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.00 sec)当然,这是系统自带的数据库,我们最好不要使用。因此我们可以创建一个属于自己的数据库。2. 创建数据库mysql> create database huang; Query OK, 1 row affected (0.01 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | huang | | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.00 sec)在这里,我们创建了数据自己的数据库huang,接着再次查看系统中的数据库,此时已经新增了一个数据库。3. 使用数据库mysql> use huang; Database changed必须要使用这一行代码,表示后续我们想要操作这个数据库。否则系统不知道你操作哪个数据库,就会报错。4. 创建一张表这里我们想要创建一个学生表,一共有4个字段。建表语句如下:mysql> create table student( -> sid varchar(20), -> sname varchar(20), -> sage datetime, -> ssex varchar(10) -> )charset=utf8; Query OK, 0 rows affected, 1 warning (0.04 sec)建表完成之后,可以查看该数据库有哪些表。mysql> show tables; +-----------------+ | Tables_in_huang | +-----------------+ | student | +-----------------+ 1 row in set (0.00 sec)此时,我们有了自己的数据库haung,也在该数据库中创建了自己的表student。5. 往表中插入数据插入数据的语句如下:insert into student values ('01' , '赵雷' , '1990-01-01' , '男'), ('02' , '钱电' , '1990-12-21' , '男'), ('03' , '孙风' , '1990-12-20' , '男'), ('04' , '李云' , '1990-12-06' , '男'), ('05' , '周梅' , '1991-12-01' , '女'), ('06' , '吴兰' , '1992-01-01' , '女'), ('07' , '郑竹' , '1989-01-01' , '女'), ('09' , '张三' , '2017-12-20' , '女'), ('10' , '李四' , '2017-12-25' , '女'), ('11' , '李四' , '2012-06-06' , '女'), ('12' , '赵六' , '2013-06-13' , '女'), ('13' , '孙七' , '2014-06-01' , '女');6. MySQL数据查询查询1990年出生的学生名单。select * from student where year(sage)="1990";本文主要为大家讲述如何使用墨天轮平台发布的数据库在线实训平台,具体学习操作,还得看你们自己啦!
Ⅱ fetchall():一次获取所有记录;import pymysql db = pymysql.connect(host='localhost',user='root',db='huangwei',password='123456',port=3306,charset='utf8') cursor = db.cursor() cursor.execute('select name,age from person') aa = cursor.fetchall() # print(aa) for a,b in aa: c = "我的名字叫{},今年{}岁".format(a,b) display(c) db.close()结果如下:Ⅲ 使用pandas中的read_sql()方法,将提取到的数据直接转化为DataFrame进行操作;import pymysql import pandas as pd db = pymysql.connect(host='localhost',user='root',db='huangwei',password='123456',port=3306,charset='utf8') cursor = db.cursor() df1 = pd.read_sql("select * from student where ssex='男'",db) display(df1) df2 = pd.read_sql("select * from student where ssex='女'",db) display(df2)结果如下:3. Python操作MongoDB数据库这一部分主要带大家对比学习:关系型数据和非关系型数据库的不同之处。咱们了解一下即可,不必过深研究,因为数据分析师基本不会使用这种数据库。Python操作MongoDB使用的是pymongo库。需要我们使用如下命令提前安装:pip insatll pymongo更多细节参考:Python操作MongoDB详解!① Python链接MongoDB服务器from pymongo import MongoClient conn = MongoClient("localhost",27017)② Python怎么获取MongoDB中的数据?Ⅰ 查询部分文档;res = collection.find({"age": {"$gte": 19}}) for row in res: print(row)Ⅱ 查询所有文档;res = collection.find() for row in res: print(row)Ⅲ 统计查询;res = collection.find().count() print(res)Ⅳ 根据 id 查询;这里需要引入第三方库。from bson.objectid import ObjectId res = collection.find({"_id":ObjectId("5cc506289e1d88c95465488e")}) print(res[0])Ⅴ 升序排序;res = collection.find().sort("age") for row in res: print(row)Ⅵ 降序排序;这里也需要引入第三方库。import pymongo res = collection.find().sort("age",pymongo.DESCENDING) for row in res: print(row)Ⅶ 分页查询res = collection.find().limit(3).skip(5) for row in res: print(row)
1. Python操作Oracle数据库这一部分的难点在于:环境配置有点繁琐。不用担心,我为大家写了一篇关于Oracle环境配置的文章。Python操作Oracle使用的是cx_Oracle库。需要我们使用如下命令提前安装:pip insatll cx_Oracle① Python链接Oracle服务器的3种方式# ① 用户名、密码和监听写在一起 import cx_Oracle db = cx_Oracle.connect('scott/a123456@DESKTOP-V4LKB10:1521/orcl') # ② 用户名、密码和监听分开写 import cx_Oracle db = cx_Oracle.connect("scott","a123456","192.168.2.1:1521/orcl") # ③ 配置监听并连接 import cx_Oracle moniter = cx_Oracle.makedsn('192.168.2.1',1521,'orcl') db = cx_Oracle.connect('scott','a123456',moniter)② Python怎么获取Oracle中的数据?这里有三种常用的方法,分别为大家进行介绍。Ⅰ fetchone():一次获取一条记录; import cx_Oracle # 注意:一定要加下面这两行代码,负责会中文乱码; import os os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' db = cx_Oracle.connect("scott","a123456","192.168.2.1:1521/orcl") cursor = db.cursor() cursor.execute('select count(*) from emp1') aa = cursor.fetchone() print(aa) cursor.execute('select ename,deptno,sal from emp1') for i in range(aa[0]): a,b,c = cursor.fetchone() d = "我的名字叫{},所在部门是{},工资是{}美元".format(a,b,c) display(d) db.close()结果如下:Ⅱ fetchall():一次获取所有记录;import cx_Oracle # 注意:一定要加下面这两行代码,负责会中文乱码; import os os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' db = cx_Oracle.connect("scott","a123456","192.168.2.1:1521/orcl") cursor = db.cursor() cursor.execute('select ename,deptno,sal from emp1') aa = cursor.fetchall() # print(aa) for a,b,c in aa: d = "我的名字叫{},所在部门是{},工资是{}美元".format(a,b,c) display(d) db.close()结果如下:Ⅲ 使用pandas中的read_sql()方法,将提取到的数据直接转化为DataFrame进行操作;import cx_Oracle import pandas as pd import os os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' db = cx_Oracle.connect("scott","a123456","192.168.2.1:1521/orcl") cursor = db.cursor() df1 = pd.read_sql("select * from emp where deptno=20",db) display(df1) df2 = pd.read_sql("select * from emp where deptno=30",db) display(df2)结果如下:2. Python操作MySQL数据库MySQL数据库应该是国内应用最多的数据库。大多数公司一般都是使用的该数据库。这也就是很多学生在毕业之前都会选择学习该数据库知识,用于面试。Python操作MySQL使用的是cx_Oracle库。需要我们使用如下命令提前安装:pip insatll pymysql更多细节参考:Python操作Oracle详解!① Python链接MySQL服务器import pymysql db = pymysql.connect(host='localhost',user='root',password='123456',port=3306,db='spiders',charset=' utf8')这里面有六个参数,需要为大家一一介绍一下:参数host:mysql服务器所在的主机的ip;参数user:用户名;参数password:密码;参数port:连接的mysql主机的端口,默认是3306;参数db:连接的数据库名;参数charset:当读取数据出现中文会乱码的时候,需要我们设置一下编码;我们使用python操作数据库的时候,那么python就相当于是client,我们是用这个client来操作mysql的server服务器,python3默认采用的utf8字符集,我的mysql服务器默认采用latin1字符集,因此mysql中创建的每张表,都是建表的时候加了utf8编码的,因此这里设置的应该就是connection连接器的编码;② Python怎么获取MySQL中的数据?Ⅰ fetchone():一次获取一条记录; import pymysql db = pymysql.connect(host='localhost',user='root',db='huangwei',password='123456',port=3306,charset='utf8') cursor = db.cursor() cursor.execute('select count(*) from person') aa = cursor.fetchone() print(aa) cursor.execute('select name,age from person') for i in range(aa[0]): a,b = cursor.fetchone() c = "我的名字叫{},今年{}岁".format(a,b) display(c) db.close()结果如下:
Math模块中,有很多基础的数学知识,我们必须要掌握的,例如:指数、对数、三角或幂函数等。因此,特意借着这篇文章,为大家讲价一些该库。由于该math模块与 Python 版本一起打包,因此您不必单独安装它,,直接导入:import mathmath模块常数Pythonmath模块提供了多种预定义常量。访问这些常量提供了几个优点。一方面,您不必手动将它们硬编码到您的应用程序中,这为您节省了大量时间。另外,它们在整个代码中提供一致性。该模块包括几个著名的数学常数和重要值:圆周率πTau (τ)欧拉数e无限不是数字 (NaN)1. 圆周率Pi (π) 是圆的周长 ( c ) 与其直径 ( d )的比值:π = c/d对于任何圆,该比率始终相同。Pi 是一个无理数,这意味着它不能表示为一个简单的分数。因此,pi 的小数位数是无限的,但可以近似为 22/7,即 3.141。您可以按如下方式访问 pi:>>> math.pi 3.141592653589793如您所见,在 Python 中 pi 值保留为小数点后十五位。提供的位数取决于底层 C 编译器。Python 默认打印前 15 位数字,并math.pi始终返回一个浮点值。那么 pi 可以通过哪些方式对您有用呢?您可以使用 2π r计算圆的周长,其中r是圆的半径:>>> r = 3 >>> circumference = 2 * math.pi * r >>> f"Circumference of a Circle = 2 * {math.pi:.4} * {r} = {circumference:.4}" 'Circumference of a Circle = 2 * 3.142 * 3 = 18.85'您可以使用它math.pi来计算圆的周长。您还可以使用公式 π r ²计算圆的面积,如下所示:>>> r = 5 >>> area = math.pi * r * r >>> f"Area of a Circle = {math.pi:.4} * {r} * {r} = {area:.4}" 'Area of a Circle = 3.142 * 5 * 5 = 78.54'2. Tau (τ)Tau (τ) 是圆的周长与其半径的比值。这个常数等于 2π,或大约 6.28。与 pi 一样,tau 是一个无理数,因为它只是 pi 乘以 2。许多数学表达式使用 2π,而使用 tau 可以帮助简化方程。例如,我们可以用 tau 代替 tau 并使用更简单的方程 τ r,而不是用 2π r计算圆的周长。然而,使用 tau 作为圆常数仍存在争议。您可以根据需要自由使用 2π 或 τ。您可以使用 tau 如下:>>> math.tau 6.283185307179586像math.pi,math.tau返回十五位数字并且是一个浮点值。您可以使用 tau 计算具有 τ r的圆的周长,其中r是半径,如下所示:>>> r = 3 >>> circumference = math.tau * r >>> f"Circumference of a Circle = {math.tau:.4} * {r} = {circumference:.4}" 'Circumference of a Circle = 6.283 * 3 = 18.85'您可以使用math.tau代替2 * math.pi来整理包含表达式 2π 的方程。3. 欧拉数欧拉数 ( e ) 是一个常数,它是自然对数的底数,自然对数是一种常用于计算增长率或衰减率的数学函数。与 pi 和 tau 一样,欧拉数是一个具有无限小数位的无理数。e的值通常近似为 2.718。欧拉数是一个重要的常数,因为它有许多实际用途,例如计算人口随时间的增长或确定放射性衰变率。您可以从math模块中访问欧拉数,如下所示:>>> math.e 2.7182818284590454. 无限无穷大不能由数字定义。相反,它是一个数学概念,代表永无止境或无限的事物。无穷大可以朝任一方向发展,正向或负向。当您想将给定值与绝对最大值或最小值进行比较时,您可以在算法中使用无穷大。Python中正无穷大和负无穷大的取值如下:>>> f"Positive Infinity = {math.inf}" 'Positive Infinity = inf' >>> f"Negative Infinity = {-math.inf}" 'Negative Infinity = -inf'无穷大不是数值。相反,它被定义为math.inf. Python 在 3.5 版中引入了这个常量,相当于float(“inf”):>>> float("inf") == math.inf True既float(“inf”)和math.inf表示无穷大的概念,使得math.inf大于任何数值:>>> x = 1e308 >>> math.inf > x True上面代码中,math.inf大于x10 308(浮点数的最大大小)的值,为双精度数。同样,-math.inf小于任何值:>>> y = -1e308 >>> y > -math.inf True负无穷小于 的值y,即 -10 308。没有数字可以大于无穷大或小于负无穷大。这就是为什么数学运算 withmath.inf不会改变无穷大的值:>>> math.inf + 1e308 inf >>> math.inf / 1e308 inf5. 不是数字不是数字或 NaN 并不是真正的数学概念。它起源于计算机科学领域,作为对非数字值的引用。NaN值可以是由于无效的输入,或者它可以指示一个变量即应该是数值已经由文本字符或符号损坏。检查值是否为 NaN 始终是最佳实践。如果是,那么它可能会导致您的程序中出现无效值。Python 在 3.5 版本中引入了 NaN 常量。您可以观察以下值math.nan:>>> math.nan nanNaN 不是数值。你可以看到,价值math.nan是nan,相同的值float(“nan”)。算术函数1. factorial()仅仅为了得到一个数的阶乘而实现自己的函数既耗时又低效。更好的方法是使用math.factorial().。以下是如何使用 找到数字的阶乘math.factorial():>>> math.factorial(7) 50402. ceil()math.ceil()将返回大于或等于给定数字的最小整数值。如果数字是正小数或负小数,则函数将返回下一个大于给定值的整数值。例如,输入 5.43 将返回值 6,输入 -12.43 将返回值 -12。math.ceil()可以将正实数或负实数作为输入值,并且将始终返回整数值。当您向 输入整数值时ceil(),它将返回相同的数字:>>> math.ceil(6) 6 >>> math.ceil(-11) -113. floor()floor()将返回小于或等于给定数字的最接近的整数值。此函数的行为与 相反ceil()。例如,输入 8.72 将返回 8,输入 -12.34 将返回 -13。floor()可以将正数或负数作为输入,并返回一个整数值。如果您输入一个整数值,则该函数将返回相同的值:>>> math.floor(4) 4 >>> math.floor(-17) -174. trunc()当您得到一个带小数点的数字时,您可能只想保留整数部分并消除小数部分。该math模块有一个被调用的函数trunc(),它可以让你做到这一点。删除十进制值是一种四舍五入。使用trunc(),负数总是向上舍入到零,正数总是向下舍入到零。以下是该trunc()函数如何舍入正数或负数:>>> math.trunc(12.32) 12 >>> math.trunc(-43.24) -435. isclose()例如,采用以下一组数字:2.32、2.33 和 2.331。当你用两个小数点来衡量接近度时,2.32 和 2.33 是接近的。但实际上,2.33 和 2.331 更接近。因此,亲近是一个相对的概念。如果没有某种阈值,您就无法确定接近度。幸运的是,该math模块提供了一个名为的函数isclose(),可让您为接近度设置自己的阈值或容忍度。它返回True如果两个数字是你建立亲密,否则返回公差范围内False。让我们看看如何使用默认容差比较两个数字:相对容差或rel_tol是相对于输入值的幅度被认为“接近”的最大差异。这是公差的百分比。默认值为 1e-09 或 0.000000001。绝对容差或abs_tol是被视为“接近”的最大差异,而不管输入值的大小。默认值为 0.0。isclose使用上面的表达式来确定两个数字的接近程度。您可以替换自己的值并观察任何两个数字是否接近。在以下情况下,6 和 7不接近:>>> math.isclose(6, 7) False数字 6 和 7 不被视为接近,因为相对容差设置为九位小数。但是,如果你输入6.999999999和7相同的误差下,那么他们被认为是接近:>>> math.isclose(6.999999999, 7) True幂函数power 函数将任何数字x作为输入,将x提高到某个n 次幂,然后返回x n作为输出。Python 的math模块提供了几个与幂的功能。在本节中,您将了解幂函数、指数函数和平方根函数。您可以使用math.pow()来获取数字的幂。math.pow() 需要两个参数,第一个参数是基值,第二个参数是幂值。>>> math.pow(2, 5) 32.0 >>> math.pow(5, 2.4) 47.591348467896961. exp()math模块提供了一个函数 ,exp()可让您计算数字的自然指数。您可以按如下方式找到该值:>>> math.exp(21) 1318815734.4832146 >>> math.exp(-1.2) 0.301194211912202142. 对数函数log()有两个论点。第一个是强制性的,第二个是可选的。使用一个参数,您可以获得输入数字的自然对数(以e为底):>>> math.log(4) 1.3862943611198906 >>> math.log(3.4) 1.2237754316221157math模块还提供了两个单独的函数,可让您计算以 2 和 10 为底的对数值:log2() 用于计算以 2 为底的对数值。 log10() 用于计算以 10 为底的对数值。 >>> math.log2(math.pi) 1.6514961294723187 >>> math.log(math.pi, 2) 1.651496129472319 >>> math.log10(math.pi) 0.4971498726941338 >>> math.log(math.pi, 10) 0.4971498726941338其他重要的math模块功能math.gcd():计算两个数字的最大公约数;math.fsum():在不使用循环的情况下找到可迭代值的总和;math.sqrt():求任何正实数(整数或小数)的平方根;math.radians():返回度数输入的弧度值;math.degrees():将弧度转换为度数;math.sin()、math.cos()、math.tan():计算正弦、余弦、正切;
前几天,在一个群里面,看到一位朋友,说自己接到了阿里的面试,人家问了一些关于pandas的使用。其中一个问题是:pandas中合并数据的5中方法。今天借着这个机会,就为大家盘点一下pandas中合并数据的5个函数。但是对于每个函数,我这里不打算详细说明,具体用法大家可以参考pandas官当文档。join主要用于基于索引的横向合并拼接;merge主要用于基于指定列的横向合并拼接;concat可用于横向和纵向合并拼接;append主要用于纵向追加;combine可以通过使用函数,把两个DataFrame按列进行组合。joinjoin是基于索引的横向拼接,如果索引一致,直接横向拼接。如果索引不一致,则会用Nan值填充。索引一致x = pd.DataFrame({'A': ['A0', 'A1', 'A2'], 'B': ['B0', 'B1', 'B2']}, index=[0, 1, 2]) y = pd.DataFrame({'C': ['C0', 'C2', 'C3'], 'D': ['D0', 'D2', 'D3']}, index=[0, 1, 2]) x.join(y)结果如下:索引不一致x = pd.DataFrame({'A': ['A0', 'A1', 'A2'], 'B': ['B0', 'B1', 'B2']}, index=[0, 1, 2]) y = pd.DataFrame({'C': ['C0', 'C2', 'C3'], 'D': ['D0', 'D2', 'D3']}, index=[1, 2, 3]) x.join(y)结果如下:mergemerge是基于指定列的横向拼接,该函数类似于关系型数据库的连接方式,可以根据一个或多个键将不同的DatFrame连接起来。该函数的典型应用场景是,针对同一个主键存在两张不同字段的表,根据主键整合到一张表里面。可以指定不同的how参数,表示连接方式,有inner内连、left左连、right右连、outer全连,默认为inner;x = pd.DataFrame({'姓名': ['张三', '李四', '王五'], '班级': ['一班', '二班', '三班']}) y = pd.DataFrame({'专业': ['统计学', '计算机', '绘画'], '班级': ['一班', '三班', '四班']}) pd.merge(x,y,how="left")结果如下:concatconcat函数既可以用于横向拼接,也可以用于纵向拼接。纵向拼接x = pd.DataFrame([['Jack','M',40],['Tony','M',20]], columns=['name','gender','age']) y = pd.DataFrame([['Mary','F',30],['Bob','M',25]], columns=['name','gender','age']) z = pd.concat([x,y],axis=0)结果如下:横向拼接x = pd.DataFrame({'姓名': ['张三', '李四', '王五'], '班级': ['一班', '二班', '三班']}) y = pd.DataFrame({'专业': ['统计学', '计算机', '绘画'], '班级': ['一班', '三班', '四班']}) z = pd.concat([x,y],axis=1)结果如下:appendappend主要用于纵向追加数据。x = pd.DataFrame([['Jack','M',40],['Tony','M',20]], columns=['name','gender','age']) y = pd.DataFrame([['Mary','F',30],['Bob','M',25]], columns=['name','gender','age']) x.append(y)结果如下:combineconbine可以通过使用函数,把两个DataFrame按列进行组合。x = pd.DataFrame({"A":[3,4],"B":[1,4]}) y = pd.DataFrame({"A":[1,2],"B":[5,6]}) x.combine(y,lambda a,b:np.where(a>b,a,b))结果如下:注:上述函数,用于返回对应位置上的最大值。
对于很多新手朋友来说,觉得学习Python是一件难事。今天黄同学为大家介绍一款神器,它能够帮助你了解计算机运行每一行代码时会发生什么(如下图所示)。这对于我们更好的了解Python运行和调试代码,确实有很大的帮助。看看官网是怎么说的官网:https://pythontutor.com/这款神器叫做Python tutor,它就是用来可视化执行代码的。不管你是学习Python、Java、C、C++、JavaScript或Ruby。Python Tutor能够帮助我们克服学习编程的一个基本障碍: 了解计算机运行每一行代码时会发生什么。您可以使用它在 Web 浏览器中编写Python、Java、C、C++、JavaScript 和Ruby代码,并逐步查看其执行情况。180 多个国家/地区的超过 1000 万人使用Python Tutor可视化了 1 亿多段代码,通常作为教科书、讲座和在线教程的补充。 据我们所知,它是计算教育中使用最广泛的程序可视化工具。如何使用它首先,你可以选择你想要执行的代码语言,我使用的是Python。从上图可以看出,这个界面超级简单,一共有3个部分,分别介绍如下:① 选择语言;② 代码输入框;③ 两种模式Visualize Execution和Live Programming Mode;关于①②大家一看便知,下面我们来讲讲这两种模式。Visualize Execution模式:写完程序需要自己手动去执行,进而看到程序执行的每一步发生了什么情况;Live Programming Mode模式:不用手动执行程序,每写一行程序,系统会自动执行并可视化;一般来说,最好使用Visualize Execution模式。我们既然使用这个工具,就是想看清楚代码的执行过程,因此还是自己动手一步步执行,观察执行结果比较好。好记性不如烂笔头,我们不过多的说,直接为大家做个演示。def func(x): if x < 18: print("未成年") return "未成年" else: print("成年") return "成年" x = 20 func(x)比如有上面一段代码,我们来看看执行情况整个程序数变动的过程活生生呈现你眼前,够明了了吧。
前言用过Pandas和openpyxl库的同学都知道,这两个库是相互互补的。Pandas绝对是Python中处理Excel最快、最好用的库,但是使用 openpyxl 的一些优势是能够轻松地使用样式、条件格式等自定义电子表格。如果你又想轻松的使用Pandas处理Excel数据,又想为Excel电子表格添加一些样式,应该怎么办呢?但是您猜怎么着,您不必担心挑选。事实上,openpyxl 支持将数据从 Pandas DataFrame 转换为工作簿,或者相反,将 openpyxl 工作簿转换为 Pandas DataFrame。DataFrame转工作簿我们先创建一个DataFrame:import pandas as pd data = { "姓名": ["张三", "李四"], "性别": ["男", "女"], "年龄": [15, 25], } df = pd.DataFrame(data) df结果如下:如果想要给表头设置为红色字体,并居中,应该如何设置呢?from openpyxl import Workbook from openpyxl.utils.dataframe import dataframe_to_rows from openpyxl.styles import Font from openpyxl.styles import Alignment wb = Workbook() ws = wb.active for row in dataframe_to_rows(df, index=False, header=True): ws.append(row) font = Font(name="微软雅黑",size=10, bold=True,italic=False,color="FF0000") alignment = Alignment(horizontal="center",vertical="center") for i in range(1,df.shape[1]+1): cell = ws.cell(row=1, column=i) print(cell.value) cell.font = font cell.alignment = alignment wb.save("pandas.xlsx")结果如下:工作簿转DataFrame如果有这样一份数据,我们想将其转换为DataFrame,应该怎么做?其实这个有点多此一举,我们直接使用pandas读取后,处理完数据,在进行样式设计不就行了吗?为何一开始非要使用openpyxl读取工作簿呢?哈哈,但是既然openpyxl中提供了这种方法,我们就来看看。import pandas as pd from openpyxl import load_workbook workbook = load_workbook(filename="df_to_openpyxl.xlsx") sheet = workbook.active values = sheet.values df = pd.DataFrame(values) df结果如下:
re库在Python中,re库又叫做正则表达式库,也属于Python标准库之一,不用安装就可以使用。什么是正则表达式?正则表达式是一组由字母和符号组成的特殊文本,可以帮助我们从某个复杂的字符串中,提取出满足我们要求的特殊文本。用一个形象的比喻大致体会一下正则匹配的过程。苹果相当于写的“正则表达式”,字符串相当于“水果市场”,“正则匹配的过程”就相当于拿着苹果去“水果市场”找苹果的过程,每找到一个就返回一个,否则就什么也没有。常用操作符介绍正则表达式之所以这么强大,是因为拥有这么多专用操作符。为了方便大家记忆,我特意将操作符分为三类:第一,元字符;第二,量化符;第三,特殊符;1. 常用元字符所谓“元字符”,指的是那些不仅仅可以表示字符本身含义、并且还可以表示其他特殊含义的字符。常用的元字符有. [ ] () ^ $ | \ ? * +{ }共11种,为了更清楚地说明每个元字符的含义,我这里整理了一张表格供大家参考。可以看到,上面一共说明了7种元字符的含义,还有4种并没有说明。那是为了方便大家记忆,我特意将上述最后4个元字符分类到了“量化符”中,这个将在下面一小节中进行讲述。2. 常用量化符所为“量化符”,指的就是将紧挨着量化符前面的那个字符,匹配0次、1次或者多次,详细说明见下表。3. 常用特殊符所为“特殊符”,指的就是由转义字符加某些字母组合而成的具有特殊意义的特殊字符,详细说明见下表。常用方法介绍在re库中,一共提供了三个函数用于查找匹配,分别是match()、search()还有findall(),下面我们分别对他们进行讲述。1. 三大函数含义对比在这三个函数中,用的最多的是findall()这个函数,其次是search()函数,match()函数则用的很少。下面我们一一说明它的含义:match(pattern,string):匹配字符串的开头,如果开头匹配不上,则返回Noneseach(pattern,string):扫描整个字符串,匹配后立即返回,不在往后面匹配;findll(pattern,string):扫描整个字符串,以列表形式返回所有的匹配值;其中,pattern表示用于匹配的正则表达式,string表示待匹配的字符串。2. 三大函数用法对比前面我们已经介绍了这三个函数的具体含义,现在用一个案例对比说明它们的不同之处。导入相关库。import re如果有如下两个字符串。s = "黄同学喜欢唱歌,黄同学喜欢写作,黄同学喜欢吃火锅!" s1 = "喜欢唱歌,喜欢写作,喜欢吃火锅"① 使用match()函数首先我们使用直接匹配s字符串中的“喜欢”二字。re.match("喜欢",s)这行代码没有返回结果,表示返回结果是None值,那是由于match()只匹配开头,如果开头不是“喜欢”二字,那么就返回None。re.match("喜欢",s) == None返回结果是:True。如果我们再使用match()函数,匹配s1字符串中的“喜欢”二字。re.match("喜欢",s1)返回结果是:<re.Match object; span=(0, 2), match=‘喜欢’>。上述结果得到的是一个匹配对象,如果我们想要获取其中的匹配值,就必须调用匹配对象的group()方法,获取具体的匹配值。re.match("喜欢",s1).group()返回结果是:’喜欢’② 使用search()函数接着我们使用直接匹配s字符串中的“喜欢”二字。re.search("喜欢",s)返回结果是:<re.Match object; span=(3, 5), match=‘喜欢’>。上述结果同样返回的是一个匹配对象,仍然需要调用group()方法,获取到具体的匹配值。re.search("喜欢",s).group()返回结是:‘喜欢’③ 使用finall()函数最后我们再使用直接匹配s字符串中的“喜欢”二字。re.findall("喜欢",s)返回结果是:[‘喜欢’, ‘喜欢’, ‘喜欢’]3. 其他常用方法除了上述三个用于查找匹配的函数之外,还有用于切分的split()函数,有用于替换的sub()函数。另外还有两个常用修饰符re.I和re.S,简单了解一下。下面我们一一介绍它们的含义:split(pattern,string):按照某个匹配的正则表达式,将整个字符串切分后,以列表返回;sub(pattern,repl,string):按照某个匹配的正则表达式,将整个字符串的某个字串替换为另外一个字串;re.I:让正则表达式自动忽略大小写;re.S:让“.”能够匹配包括换行符在内的任意字符;其中,pattern表示用于匹配的正则表达式,string表示待匹配的字符串,repl表示替换后的字串。假如有这样3个字符串:s = "赵1钱2孙4李8周16吴32郑64王128黄" s1 = "Huang是huang" s2 = "黄\n同学"需求1:将字符串s按照数字切分,以一个汉字组成的列表返回。我们知道\d是匹配某一个数字,但是上述字符串里面,有2位的数字还有3位的数字,于是你会想到使用\d+表示匹配>=1个数字,因此整个代码如下:re.split("\d+",s)返回结果是:[‘赵’, ‘钱’, ‘孙’, ‘李’, ‘周’, ‘吴’, ‘郑’, ‘王’, ‘黄’]。需求2:将字符串s中的数字部分,全都替换为空。同样我们仍然用\d+表示匹配>=1个数字,这道题的代码如下:re.sub("\d+"," ",s)返回结果是:‘赵 钱 孙 李 周 吴 郑 王 黄’需求3:将字符串s1中的h匹配出来,不区分大小写;如果不加re.I,系统会将它们看待成不同的字符。re.findall("h",s1)返回结果是:[‘h’]如果加了re.I,系统会忽略大小写,那么h和H就是同一个字符。re.findall("h",s1,re.I)返回结果是:[‘H’, ‘h’]需求4:将字符串s2整个匹配出来,包括换行符;如果不加re.S,“.”不能匹配“\n”换行符。re.findall(".+",s2)返回结果是:[‘黄’, ‘同学’]如果加了re.S,“.”此时能够匹配“\n”换行符。re.findall(".+",s2,re.S)返回结果是:[‘黄\n同学’]
由于这是一个表格型的数据,也没什么反扒措施,为了节省时间,直接上pandas库吧,我只需要5行代码就行啦!import pandas as pd import csv for i in range(1,16): # 爬取全部页 tb = pd.read_html(f'https://www.phb123.com/renwu/fuhao/shishi_{i}.html')[0] tb.to_csv(r'福布斯排行榜.csv', mode='a', encoding='utf_8_sig', index=0)结果如下:太尴尬了,标题行都在,那就有14个表头了,我们读取一下,去掉重复行吧!df = pd.read_csv("福布斯排行榜.csv",header=None) df.drop_duplicates(inplace=True) df.to_excel("福布斯排行榜.xlsx",index=None)直接使用drop_duplicates()函数,实现去重操作,并重新保存了一个新文件。好了,开始我们的数据探索吧!df1 = pd.read_excel("福布斯排行榜.xlsx",header=1) df1结果如下:1. 排行榜世界前10x = df1.head(10) x结果如下:2. 上榜人数最多的前10个国家df1.groupby("国家/地区")["名字"].count().sort_values(ascending=False)[:10].to_frame().reset_index()结果如下:3. 排行榜中国前10y = df1[df1["国家/地区"] == "中国"] y.head(10)结果如下:其实不管是中国前十,还是世界前十,基本都是一些咱们耳熟能详的企业。不得不说,美国佬上榜的人数确实多。好了,了解一下就好,在心里激励一下自己吧!成不了别人,更应该加油。就当作是周末的一个鸡汤吧!
4、可视化展示关于可视化部分,使用的是pyecharts库。这部分一共分以下8个主题:① 2020东京奥运会各国奖牌分布图;② 2020东京奥运会奖牌榜详情;③ 2020东京奥运会奖牌榜总数前十名;④ 2020东京奥运会金牌榜总数前十名;⑤ 2020东京奥运会中国各项目获奖详情;⑥ 中国选手每日获得奖牌数;⑦ 中国选手每日获得金牌数;⑧ 中国选手夺金详细数据;① 2020东京奥运会各国金牌分布图② 2020东京奥运会奖牌榜详情③ 2020东京奥运会奖牌榜总数前十名④ 2020东京奥运会金牌榜总数前十名⑤ 2020东京奥运会中国各项目获奖详情
1、项目背景奥运会刚刚过去,你是否已经看过2020东京奥运会呢?本文将手把手带你爬取奥运会相关信息,并利用可视化大屏为你展示奥运详情。让一个没关注过奥运会的朋友,也能够秒懂奥运会。学完本文后,你将学会如下可视化大屏的制作。2、奥运会相关信息爬取爬取字段: 国家、国家ID、排名、金牌数、银牌数、铜牌数、奖牌总数、项目名、运动员、获奖类型、获奖时间;爬取说明: 基于两个接口的数据爬取【json格式的数据】,直接采用键值对的方式获取相关数据;使用工具: Pandas+requests本文是基于两个接口的数据爬取,相对容易的多。# 这个链接主要展示:各国的金银铜牌及其总数! https://app-sc.miguvideo.com/vms-livedata/olympic-medal/total-table/15/110000004609 # 这个链接主要展示:每个参赛队员的参赛项目和获得的奖牌情况! https://app-sc.miguvideo.com/vms-livedata/olympic-medal/total-table/15/110000004609① 导入相关库import requests import pandas as pd from pprint import pprintrequests库用于发起网页请求,获取网页中的源代码;pandas库用于存储和读取获取到的信息;pprint库是漂亮的打印,对于json格式的数据,能够很好的展示结构,方便我们解析;② 爬虫讲解url = 'https://app-sc.miguvideo.com/vms-livedata/olympic-medal/total-table/15/110000004609' data = requests.get(url).json() pprint(data)三行代码就可以获取到网页的源代码,利用pprint库,可以清晰的展示json结构,对于我们解析数据很有帮助。从图中可以很清晰地看到,我们要的数据,都存在于body键下面的allMedalData键中,allMedalData键的值是一个列表,里面有很多字典组成的键值对信息,就是我们要爬取的数据。直接利用键获取对应的值信息,代码如下:df1 = pd.DataFrame() for info in data1['body']['allMedalData']: name = info['countryName'] name_id = info['countryId'] rank = info['rank'] gold = info['goldMedalNum'] silver = info['silverMedalNum'] bronze = info['bronzeMedalNum'] total = info['totalMedalNum'] # 组织数据 orangized_data = [[name,name_id,rank,gold,silver,bronze,total]] # 然后追加df df1 = df1.append(orangized_data) df1.columns = ['名称', 'ID', '排名', '金牌', '银牌', '铜牌', '奖牌总数'] df1结果如下:对于另外一个网页,我们采取同样的方式。url = 'https://app-sc.miguvideo.com/vms-livedata/olympic-medal/detail-total/15/110000004609' data2 = requests.get(url).json() pprint(data2)
在读取到Excel文件或csv文件后,往往会出现数据显示不全(如图)等问题,有时候会影响我们对数据的判断。使用这个函数后,能够帮助我们更好的显示数据,帮助我们更快的认识数据,能够节省不少时间。接下来,我们来为大家分别讲述set_option()函数中,几个超级好用的技巧。第一组创建数据源的代码如下:df = pd.DataFrame({ 'a':[[1]*20] + [i for i in range(2,101)], 'b':[2]*100, 'c':[3]*100, 'd':[4]*100, 'e':[5]*100, 'f':[6]*100, 'g':[7]*100, 'h':[8]*100, 'i':[9]*100, 'j':[10]*100, 'k':[11]*100, 'l':[12]*100, 'm':[13]*100, 'n':[14]*100, 'o':[15]*100, 'p':[16]*100, 'r':[17]*100, 's':[18]*100, 't':[19]*100, 'u':[20]*100, 'v':[21]*100, 'w':[22]*100, 'x':[23]*100, 'y':[24]*100, 'z':[25]*100}) df结果如下:1. 显示所有行pd.set_option('display.max_rows', None)结果如下:2. 显示所有列pd.set_option('display.max_columns', None)结果如下:3. 显示列中单独元素的最大长度pd.set_option('max_colwidth', None)结果如下:第二组创建数据源的代码如下:df = pd.DataFrame(np.random.rand(3, 30), columns=list(range(30))) df结果如下:1. 换行显示、每行最大显示宽度这个操作,需要几行代码配合操作。其中:pd.set_option(‘expand_frame_repr’,True):True表示列可以换行显示。设置成False的时候不允许换行显示;pd.set_option(‘display.max_columns’, None):显示所有列;pd.set_option(‘display.width’, 80):横向最多显示多少个字符;pd.set_option('expand_frame_repr', True) pd.set_option('display.max_columns', None) pd.set_option('display.width', 80) df = pd.DataFrame(np.random.rand(3, 30), columns=list(range(30))) print(df)结果如下:这可能是jupyter notebook显示输出的特殊性,上述代码,如果将这个print()函数去掉,直接使用df显示输出,你会发现,换行显示没用。pd.set_option('expand_frame_repr', True) pd.set_option('display.max_columns', None) pd.set_option('display.width', 80) df = pd.DataFrame(np.random.rand(3, 30), columns=list(range(30))) df结果如下:
sviewgui介绍sviewgui是一个基于 PyQt 的 GUI,用于 csv 文件或 Pandas 的 DataFrame 的数据可视化。此 GUI 基于 matplotlib,您可以通过多种方式可视化您的 csv 文件。主要特点:Ⅰ 散点图、线图、密度图、直方图和箱线图类型;Ⅱ 标记大小、线宽、直方图的 bin 数量、颜色图的设置(来自 cmocean);Ⅲ 将图另存为可编辑的 PDF;Ⅳ 绘制图形的代码可用,以便它可以在 sviewgui 之外重用和修改;这个包用法超级简单,它只有一种方法:buildGUI()。此方法可以传入零个或一个参数。您可以使用 csv 文件的文件路径作为参数,或者使用 pandas 的DataFrame对象作为参数。类似代码写法如下:# 第一种形式 import sviewgui.sview as sv sv.buildGUI() # 第二种形式 import sviewgui.sview as sv FILE_PATH = "User/Documents/yourdata.csv" sv.buildGUI(FILE_PATH) # 第三种形式 import sviewgui.sview as sv import pandas as pd FILE_PATH = "User/Documents/yourdata.csv" df = pd.read_csv(FILE_PATH) sv.buildGUI(df)上面代码,只是用于帮助我们打开这个GuI可视化界面。最后强调一点,由于这个库是基于matplotlib可视化的,因此seaborn风格同样适用于这里,因为seaborn也是基于matplotlib可视化的。sviewgui安装这个库的依赖库相当多,因此大家直接采用下面这行代码安装sviewgui库。pip install sviewgui -i https://pypi.tuna.tsinghua.edu.cn/simple/ --ignore-installed后面这个--ignore-installed,我最开始是没加的,但是报错了,大致错误如下:ERROR: Cannot uninstall 'certifi'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.大家直到加这个就行,不用管为什么,因为我也不知道!sviewgui使用上面我为大家介绍了3种打开GUI图形界面窗口的代码,这里仅介绍下面这种方法:import sviewgui.sview as sv sv.buildGUI()、截图如下:当你在命令行输入上述代码后,会驱动后台打开这个图形化界面窗口,初始化状态大致是这样的:点击上述select,可以选择数据源:然后我们可以点击左侧菜单栏,生成对应的图形。但是有一点,貌似不支持中文!!!如果你觉得这里的参数,不足以完善你想要的图形,你可以复制图形所对应的Python代码,简单修改即可。然后,你拿着下面的代码,简单修改,就可以生成漂亮的Matplotlib图形了。import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import cmocean #2021/07/13 08:03:18 #- Import CSV as DataFrame ---------- FILE_PATH = 'C:/Users/Administrator/Desktop/plot.csv' DATA = pd.read_csv(FILE_PATH) #- Axes Setting ---------- fig, ax = plt.subplots() ax.set_title( "x-y") ax.set_xlabel( "x") ax.set_ylabel( "x" ) ax.set_xlim(min(DATA['x'].replace([np.inf, -np.inf], np.nan ).dropna() ) - abs( min(DATA['x'].replace([np.inf, -np.inf], np.nan ).dropna() )/10), max(DATA['x'].replace([np.inf, -np.inf], np.nan).dropna()) + abs(max(DATA['x'].replace([np.inf, -np.inf], np.nan).dropna())/10) ) ax.set_ylim( min(DATA['x'].replace([np.inf, -np.inf], np.nan ).dropna() ) - abs( min(DATA['x'].replace([np.inf, -np.inf], np.nan ).dropna() )/10), max(DATA['x'].replace([np.inf, -np.inf], np.nan).dropna()) + abs(max(DATA['x'].replace([np.inf, -np.inf], np.nan).dropna())/10) ) #- PLOT ------------------ ax.plot( DATA["x"].replace([np.inf, -np.inf], np.nan), DATA["x"].replace([np.inf, -np.inf], np.nan), linewidth = 3.0, alpha =1.0, color = "#005AFF" ) plt.show()
collections是python的标准库,它提供了一些解决特定问题的容器,也就是说有些问题虽然可以用list,tuple,dict解决,但解决起来太麻烦,而这些问题又经常遇到,所以他们就把这些问题的通用方法整理了出来,放到collections库中让人使用。collections中一共有9种容器,其中counter、defaultdict、deque、namedtuple、orderdict比较常用。今天我们单独来讲讲Counter的用法!Counter目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。因此,我们可以通过字典的取数方式,进行取数。在使用之前,我们需要先导入这个库,导入方法如下:from collections import Counter使用Counter类,我们需要先实例化一个Counter类,我们先实例化一个空的Counter类。c1 = Counter() c1结果如下:我们可以往括号中传入参数,来帮助我们实现不同情况下的 “值计数”。Counter类的创建我们可以往Counter类中,分别传入字符串、列表、元组、字典等,创建一个Counter类。1. 传入一个字符串c2 = Counter("hello huang") c2结果如下:2. 传入一个列表lis = [i for i in "chinese"] c3 = Counter(lis) c3结果如下:3. 传入一个字典import random dic = {k: random.randint(1,4) for k in "abcdefg"} c4 = Counter(dic) c4结果如下:4. 关键字参数c5 = Counter(a=7,b=8) c5结果如下:Counter类中计数元素值的访问和访问字典类似,但是和字典唯一不同的是,如果所访问的键不存在时,返回0,而不是KeyError。c = Counter("hello huang") c["h"]结果如下:Counter类中计数元素的修改关于Counter类中的计数元素,既可以做加减法、还可以做集合运算、也可以删除。1. 加减法① 加法我们既可以使用update函数,完成这个操作。还可以使用+号,完成这个操作。② 减法我们既可以使用subtract函数,完成这个操作。但是-号用法就不同了,它应该属于集合运算,只统计在集合a中,而不在集合b中的值。2. 集合运算上面的-号就是一个集合运算,我在为大家介绍一下与&、|或操作。① 与&&操作,是找两个collection中都有的键最小的键值。c1 = Counter("chinese") c2 = Counter("where") c1 & c2结果如下:② |或|操作,是找两个collection中的键最大的键值(可以只有一个collection有这个键,但是结果中的键值必须大于零,小于零的被舍弃)。c1 = Counter("chinese") c2 = Counter("where") c1 | c2结果如下:3. 删除操作删除元素使用的是del函数。c = Counter("where") del c["r"] c结果如下:Counter类中其它常用函数1. most_common(n)找出重复次数最多的前n个。c = Counter("aabbbcccddddeeeee") c.most_common(2)结果如下:2. key和value用于获取Collections键和键值的集合。c = Counter("chinese") c.keys() c.values()结果如下:当然,我们也可以使用dict()函数将collection中的内容转化为字典,我们也可以使用list()函数将collection中的键转化为list,这里不在讲述,大家自行下去学习。
1. 页面分析我爬取的页面是腾讯体育,链接如下:https://nba.stats.qq.com/player/list.htm观察上图:左边展示的分别是NBA的30支球队,右边就是每只球队对应球员的详细信息。此时思路就很清晰了,我们每点击一支球员,右侧就会出现该球队的球员信息。整个爬虫思路简化如下:① 获取每支球员页面的url;② 利用Python代码获取每个网页中的数据;③ 将获取到的数据,整理后存储至不同的数据库;那么,现在要做的就是找到每支球员页面的url,去发现它们的关联。我们每点击一支球队,复制它的url,下面我复制了三支球队的页面url,如下所示:# 76人 https://nba.stats.qq.com/player/list.htm#teamId=20 # 火箭 https://nba.stats.qq.com/player/list.htm#teamId=10 # 热火 https://nba.stats.qq.com/player/list.htm#teamId=14观察上述url,可以发现:url基本一模一样,除了参数teamId对应的数字不一样,完全可以猜测出,这就是每支球队对应的编号,30支球队30个编号。只要是涉及到“腾讯”二字,基本都是动态网页,我之前碰到过好多次。基础方法根本获取不到数据,不信可以查看网页源码试试:点击鼠标右键——>点击查看网页源代码。接着,将网页中的某个数据(你要获取的)复制,然后再源代码页面中,点击crtl + f,调出“搜索框”,将复制的数据粘贴进去。如果和上图一样,出现0条记录,则基本可以判断该网页属于动态网页,直接获取源码,一定找不到你要的数据。因此如果你想要获取页面中的数据,使用selenuim自动化爬虫,是其中一种办法。2. 数据爬取关于selenium的的使用配置,我在一篇文章中详细讲述过,贴上这个链接供大家参考:《https://mp.weixin.qq.com/s/PUPmpbiCJqRW8Swr1Mo2UQ》我喜欢用xpath,对于本文数据的获取,我都将使用它。关于xpath的使用,那就是另一篇文章了,这里就不详细讲述。说了这么多,咋们直接上代码吧!【代码中会有注释】from selenium import webdriver # 创建浏览器对象,该操作会自动帮我们打开Google浏览器窗口 browser = webdriver.Chrome() # 调用浏览器对象,向服务器发送请求。该操作会打开Google浏览器,并跳转到“百度”首页 browser.get("https://nba.stats.qq.com/player/list.htm#teamId=20") # 最大化窗口 browser.maximize_window() # 获取球员中文名 chinese_names = browser.find_elements_by_xpath('//div[@class="players"]//tr[@class="show"]/td[2]/a') chinese_names_list = [i.text for i in chinese_names] # 获取球员英文名 english_names = browser.find_elements_by_xpath('//div[@class="players"]//tr[@class="show"]/td[3]/a') english_names_list = [i.get_attribute('title') for i in english_names] # 获取属性 # 获取球员号码 numbers = browser.find_elements_by_xpath('//div[@class="players"]//tr[@class="show"]/td[4]') numbers_list = [i.text for i in numbers_list] # 获取球员位置 locations = browser.find_elements_by_xpath('//div[@class="players"]//tr[@class="show"]/td[5]') locations_list = [i.text for i in locations_list] # 获取球员身高 heights = browser.find_elements_by_xpath('//div[@class="players"]//tr[@class="show"]/td[6]') heights_list = [i.text for i in heights_list] # 获取球员体重 weights = browser.find_elements_by_xpath('//div[@class="players"]//tr[@class="show"]/td[7]') weights_list = [i.text for i in weights_list] # 获取球员年龄 ages = browser.find_elements_by_xpath('//div[@class="players"]//tr[@class="show"]/td[8]') ages_list = [i.text for i in ages_list] # 获取球员球龄 qiu_lings = browser.find_elements_by_xpath('//div[@class="players"]//tr[@class="show"]/td[9]') qiu_lings_list = [i.text for i in qiu_lings_list]这里只爬取了一支球队,剩下29支球队球员数据的爬取任务交给你们。整个代码部分,基本上大同小异,我写了一个,你们照葫芦画瓢。【就一个循环,还不简单呀!】3. 存储至txt将数据保存到txt文本的操作非常简单,txt几乎兼容所有平台,唯一的缺点就是不方便检索。要是对检索和数据结构要求不高,追求方便第一的话,请采用txt文本存储。注意:txt中写入的是str字符串。txt文档写入数据的规则是这样的:从头开始,从左至右一直填充。当填充至最右边后,会被挤到下一行。因此,如果你想存入的数据规整一点,可以自动填入制表符“\t”和换行符“\n”。以本文为例,将获取到的数据,存储到txt文本中。for i in zip(chinese_names_list,english_names_list,numbers_list,locations_list,heights_list,weights_list,ages_list,qiu_lings_list): with open("NBA.txt","a+",encoding="utf-8") as f: # zip函数,得到的是一个元组,我们需要将它转换为一个字符串 f.write(str(i)[1:-1]) # 自动换行,好写入第2行数据 f.write("\n") f.write("\n")部分截图如下:4. 存储至excelexcel有两种格式的文件,一种是csv格式,一种是xlsx格式。将数据保存至excel,当然是使用pandas库更方便。import pandas as pd # 一定要学会组织数据 df = pd.DataFrame({"中文名": chinese_names_list, "英文名": english_names_list, "球员号码": numbers_list, "位置": locations_list, "身高": heights_list, "体重": weights_list, "年龄": ages_list, "球龄": qiu_lings_list}) # to_excel()函数 df.to_excel("NBA.xlsx",encoding="utf-8",index=None)结果如下:5. 存储至mysqlMySQL是一个关系型数据库,数据是采用类excel的二维表来保存数据的,即行、列组成的表,每一行代表一条记录,每一列代表一个字段。关于Python操作MySQL数据库,我曾经写了一篇博客,大家可以参考以下:http://blog.csdn.net/weixin_41261833/article/details/103832017为了让大家更明白这个过程,我这里分布为大家讲解:① 创建一个表nba我们想要往数据库中插入数据,首先需要建立一张表,这里命名为nba。import pymysql # 1. 连接数据库 db = pymysql.connect(host='localhost',user='root', password='123456',port=3306, db='demo', charset='utf8') # 2. 创建一个表 # 创建一个游标对象; cursor = db.cursor() # 建表语句; sql = """ create table NBA( chinese_names_list varchar(20), english_names_list varchar(20), numbers_list varchar(20), locations_list varchar(20), heights_list varchar(20), weights_list varchar(20), ages_list varchar(20), qiu_lings_list varchar(20) )charset=utf8 """ # 执行sql语句; cursor.execute(sql) # 断开数据库的连接; db.close()、② 往表nba中插入数据import pymysql # 1. 组织数据 data_list = [] for i in zip(chinese_names_list,english_names_list,numbers_list,locations_list,heights_list,weights_list,ages_list,qiu_lings_list): data_list.append(i) # 2. 连接数据库 db = pymysql.connect(host='localhost',user='root', password='123456',port=3306, db='demo', charset='utf8') # 创建一个游标对象; cursor = db.cursor() # 3. 插入数据 sql = 'insert into nba(chinese_names_list,english_names_list,numbers_list,locations_list,heights_list,weights_list,ages_list,qiu_lings_list) values(%s,%s,%s,%s,%s,%s,%s,%s)' try: cursor.executemany(sql,data_list) db.commit() print("插入成功") except: print("插入失败") db.rollback() db.close()结果如下:
② 将同一个文件,移动到不同目录下,如果没有指定新文件名,效果相当于移动。此操作,仅相当于把sum.txt移动到aa目录下。[root@image_boundary Desktop]# mv bb/sum.txt aa/③ 将同一个文件,移动到不同目录下,可以不用修改文件名。如果指定了新文件名,效果相当于移动+重命名。[root@image_boundary Desktop]# mv bb/sum.txt aa/sum.txt "把bb目录下的sum.txt文件,移动到aa目录下,并重命名为sum1.txt。" [root@image_boundary Desktop]# mv bb/sum.txt aa/sum1.txt8)head/tail:展示开头或者结尾的若干行,默认10行-n :指定行数;head :查看文件中所有内容;tail :查看文件中所有内容;head -n:查看前n行数据;tail -n:查看后n行数据;“在计划任务那里会用下面这个参数。”“在hadoop集群里面,查看log日志文件的时候,会用到。”tail -f:查看新追加内容;操作如下:[root@image_boundary Desktop]# ll total 8 drwxr-xr-x. 2 root root 4096 Oct 15 22:35 aa drwxr-xr-x. 2 root root 4096 Oct 15 22:30 bb [root@image_boundary Desktop]# head -3 aa/sum.txt aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb ccccccccccccccccc [root@image_boundary Desktop]# tail -3 aa/sum.txt mmmmmmmmmmmmmmmmm nnnnnnnnnnnnnnnnn ooooooooooooooooo9)cat/tac:查看文件内容-n:显示文件行号。(这是cat常用的)cat :查看文件中所有内容,正着查看。tac :查看文件中所有内容,倒着查看。操作如下:[root@image_boundary Desktop]# cat -n aa/sum.txt 1 1 2 2 3 3 4 4cat配合EOF命令,有一个比较厉害的操作:10)more:分屏显示,每次显示一屏q键:退出more命令。Space键:显示文本的下一屏内容。Enter键:只显示文本的下一行内容。h键:显示帮助屏,该屏上有相关的帮助信息。b键:显示上一屏内容。11)less:分屏上下翻页浏览文件内容q键:退出less命令。G:跳到文件末尾gg:跳到文件首行按e键:向上滚动一行按y键:向下滚动一行操作如下:less -N aa/sum.txt 此参数会显示文件内容的行数结果如下:12)echo:输出字符串或者变量-e:处理特殊的符号。eg:写了-e,就会把\n当成换行符,否则不会。 echo $PWD :输出变量的绝对路径 ">表示覆盖源文件中的内容" echo aa > a.txt ">>表示追加到源文件末尾" echo aa >> a.txt操作如下:[root@image_boundary Desktop]# echo "aa\nbb" aa\nbb [root@image_boundary Desktop]# clear "-e参数,表示让系统能够识别特殊字符" [root@image_boundary Desktop]# echo -e "aa\nbb" aa bb [root@image_boundary Desktop]# echo -e "aa\tbb" aa bb ================================================== "echo $PWD表示输出当前文件夹的绝对路经,很有用。" [root@image_boundary Desktop]# echo $PWD /root/Desktop [root@image_boundary Desktop]# cd aa [root@image_boundary aa]# echo $PWD /root/Desktop/aa [root@image_boundary aa]# cd ../bb [root@image_boundary bb]# echo $PWD /root/Desktop/bb ================================================= [root@image_boundary Desktop]# echo -e '666\n888' > ./aa/aa.txt [root@image_boundary Desktop]# echo -e '中国人' >> ./aa/aa.txt13)ln:创建硬链接和软链接硬链接类似于【复制】;软连接类似于【创建快捷方式】(常用);为f1 创建硬链接 f2 : ln f1 f2为f1 创建软链接(也叫符号链接) f3 : ln -s f1 f3操作如下:[root@image_boundary Desktop]# ll total 4 drwxr-xr-x. 2 root root 4096 Oct 15 23:28 aa "创建一个文件test.txt" [root@image_boundary Desktop]# cd aa [root@image_boundary aa]# touch test.txt "创建一个硬链接,相当于是复制了该文件" [root@image_boundary aa]# ln test.txt test "创建一个软连接,相当于给该文件创建了一个快捷方式" [root@image_boundary aa]# ln -s test.txt s_test [root@image_boundary aa]# echo "I am a student" >> test.txt [root@image_boundary aa]# cat s_test I am a student [root@image_boundary aa]# cat test I am a student "删除源文件test.txt后" [root@image_boundary aa]# rm -rf test.txt "软连接文件(快捷方式)会消失" [root@image_boundary aa]# cat s_test cat: s_test: No such file or directory "但是这个硬链接(复制)不会消失" [root@image_boundary aa]# cat test I am a student14)alias:查看某些命令的别名“定义别名的意义在于,可以用别名,代替某些组合命令,减少敲代码;”查看别名:alias定义别名:alias la= ‘ll -a’取消别名:unalias la操作如下:[root@image_boundary Desktop]# alias alias cp='cp -i' alias l.='ls -d .* --color=auto' alias ll='ls -l --color=auto' alias ls='ls --color=auto' alias mv='mv -i' alias rm='rm -i' alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'10、其他常用命令clear 或 ctrl+l :清屏 history :显示历史代码命令 su :切换用户。$普通用户;#管理员root用户 hostname :显示主机名 sudo :以root用户权限执行一次命令(目前不太明白这个) exit :退出当前登录状态。当前是普通用户切换到root用户;当前是root用户就切换到普通用户。 who :显示目前有哪些用户登入系统 | :管道符,表示把前面命令内容的输出,当做后面命令的输入。11、案例讲解操作如下:"首先,创建这3个文件夹;" [root@image_boundary Desktop]# mkdir myFile [root@image_boundary Desktop]# mkdir myPic [root@image_boundary Desktop]# mkdir backup [root@image_boundary Desktop]# ll total 16 drwxr-xr-x. 2 root root 4096 Oct 15 23:36 aa drwxr-xr-x. 2 root root 4096 Oct 15 23:57 backup drwxr-xr-x. 2 root root 4096 Oct 15 23:56 myFile drwxr-xr-x. 2 root root 4096 Oct 15 23:56 myPic "分别在myFile、backup分别创建一个a.txt;" [root@image_boundary Desktop]# cd myFile [root@image_boundary myFile]# touch a.txt [root@image_boundary myFile]# cd .. [root@image_boundary Desktop]# cd backup [root@image_boundary backup]# mkdir a.txt "删除backup这个文件夹及其其中的内容;" [root@image_boundary Desktop]# rm -rf backup "将同一个文件夹移动到同级目录下,相当于修改名字;" [root@image_boundary Desktop]# mv ./myFile ./File "将File目录下的a.txt文件,移动到myPic目录下;" [root@image_boundary Desktop]# cp ./File/a.txt ./myPic/
9、文件命令1)mkdir:创建目录-p:递归创建目录操作如下:[root@image_boundary Desktop]# ll total 8 drwxr-xr-x. 2 root root 4096 Oct 15 20:02 aa drwxr-xr-x. 2 root root 4096 Oct 15 20:05 bb [root@image_boundary Desktop]# mkdir cc [root@image_boundary Desktop]# ll total 12 drwxr-xr-x. 2 root root 4096 Oct 15 20:02 aa drwxr-xr-x. 2 root root 4096 Oct 15 20:05 bb drwxr-xr-x. 2 root root 4096 Oct 15 20:21 cc # 不写-p会报错。 [root@image_boundary Desktop]# mkdir dd/ee mkdir: cannot create directory `dd/ee': No such file or directory # 参数-p表示递归产生一个目录。 # 创建一个递归目录dd/ee。 [root@image_boundary Desktop]# mkdir -p dd/ee [root@image_boundary Desktop]# cd dd [root@image_boundary dd]# ll total 4 drwxr-xr-x. 2 root root 4096 Oct 15 20:22 ee2)touch:创建文件[root@image_boundary Desktop]# ll total 16 drwxr-xr-x. 2 root root 4096 Oct 15 20:02 aa drwxr-xr-x. 2 root root 4096 Oct 15 20:05 bb drwxr-xr-x. 2 root root 4096 Oct 15 20:21 cc drwxr-xr-x. 3 root root 4096 Oct 15 20:22 dd [root@image_boundary Desktop]# cd cc [root@image_boundary cc]# ll total 0 [root@image_boundary cc]# touch sum.txt [root@image_boundary cc]# ll total 4 -rw-r--r--. 1 root root 0 Oct 15 20:28 sum.txt3)file:查看文件类型-b:不显示文件名,只显示文件类型。操作如下:"file 文件名:可以显示其到底是一个文件,还是一个目录" [root@image_boundary ~]$ file aa aa: directory [root@image_boundary cc]# ll total 0 -rw-r--r--. 1 root root 0 Oct 15 20:28 sum.txt "查看当前文件夹的类型(这里指的就是cc):文件夹" [root@image_boundary cc]# file . .: directory "如果sum.txt中没有内容,显示empty" [root@image_boundary cc]# file sum.txt ./sum.txt: empty "如果sum.txt中有内容,显示sum.txt的文件类型" [root@image_boundary cc]# file sum.txt ./sum.txt: ASCII text [root@image_boundary cc]# file -b sum.txt ASCII text4)rmdir:删除空目录-p:递归删除空目录操作如下:"注意以下两个命令的区别" rmdir dd/ee/ff 表示删除dd下面ee下面的这一个空目录ff。 rmdir -p dd/ee/ff 表示同时递归删除dd/ee/ff这3个目录。5)rm:删除文件或目录rm 文件名-i:询问。(这个是默认情况,不写就是表示要询问)-r:递归删除。-f:强制删除(不提示删除)。“下面这条命令:慎用!!!除非真的知道你在干嘛。”rm -rf 目录/文件操作如下:[root@image_boundary bb]# ll total 12 -rw-r--r--. 1 root root 149 Oct 15 20:00 a.txt -rw-r--r--. 1 root root 95 Oct 15 20:02 b.txt -rw-r--r--. 1 root root 138 Oct 15 20:02 c.txt [root@image_boundary bb]# rm a.txt rm: remove regular file `a.txt'? n [root@image_boundary bb]# ll total 12 -rw-r--r--. 1 root root 149 Oct 15 20:00 a.txt -rw-r--r--. 1 root root 95 Oct 15 20:02 b.txt -rw-r--r--. 1 root root 138 Oct 15 20:02 c.txt [root@image_boundary bb]# rm a.txt rm: remove regular file `a.txt'? y [root@image_boundary bb]# ll total 8 -rw-r--r--. 1 root root 95 Oct 15 20:02 b.txt -rw-r--r--. 1 root root 138 Oct 15 20:02 c.txt "rm -rf bb会删除bb目录下所有的目录和文件,问都不问,毫不留情。一定不要轻易使用该命令" [root@image_boundary Desktop]# ll total 8 drwxr-xr-x. 2 root root 4096 Oct 15 20:53 bb drwxr-xr-x. 2 root root 4096 Oct 15 20:30 cc [root@image_boundary Desktop]# rm -rf bb [root@image_boundary Desktop]# ll total 4 drwxr-xr-x. 2 root root 4096 Oct 15 20:30 cc6)cp:复制文件或目录注意:某个文件或目录被复制后,原始文件或目录依然存在。cp 源文件(目录) 目标文件(目录)-i:提示。-r/-R参数:当【复制目录】的时候,必须用到这个参数。-r/-R:递归复制目录。-f参数:在搭建集群时,修改时区的时候用到-f:覆盖已存在的目标文件,而不给出提示。① 同一文件,复制到同一目录下,需要改名;否则,会报错。[root@image_boundary Desktop]# ll total 8 drwxr-xr-x. 2 root root 4096 Oct 15 21:00 aa drwxr-xr-x. 3 root root 4096 Oct 15 21:00 bb [root@image_boundary Desktop]# cd aa [root@image_boundary aa]# ll total 4 -rw-r--r--. 1 root root 21 Oct 15 21:00 sum.txt -rw-r--r--. 1 root root 0 Oct 15 20:59 sum.txt~ "把当前目录下的sum.txt文件,复制到当前目录下。" "假如不修改文件名,会报错。" [root@image_boundary aa]# cp sum.txt sum.txt cp: `sum.txt' and `sum.txt' are the same file "修改文件名后,才不会报错。" [root@image_boundary aa]# cp sum.txt sum1.txt [root@image_boundary aa]# ll total 8 -rw-r--r--. 1 root root 21 Oct 15 21:04 sum1.txt -rw-r--r--. 1 root root 21 Oct 15 21:00 sum.txt -rw-r--r--. 1 root root 0 Oct 15 20:59 sum.txt~② 同一文件,复制到不同目录下,不需要改名;[root@image_boundary Desktop]# ll total 8 drwxr-xr-x. 2 root root 4096 Oct 15 21:04 aa drwxr-xr-x. 3 root root 4096 Oct 15 21:00 bb "将aa目录下的sum.txt文件,复制到bb目录下,不需要修改名称。" [root@image_boundary Desktop]# cp aa/sum.txt bb/ [root@image_boundary Desktop]# cd bb [root@image_boundary bb]# ll total 8 drwxr-xr-x. 2 root root 4096 Oct 15 21:01 bbb -rw-r--r--. 1 root root 21 Oct 15 21:07 sum.txt③ 递归复制bb目录中的东西(既包括文件,也包括目录),到aa目录中去。"由于复制目录,因此必须使用参数【-r/-R】" [root@image_boundary Desktop]# ll total 8 drwxr-xr-x. 2 root root 4096 Oct 15 21:52 aa drwxr-xr-x. 3 root root 4096 Oct 15 21:07 bb "将bb目录复制到aa目录下。" "注意:复制目录的时候,必须要使用参数-r或者-R" [root@image_boundary Desktop]# cp -r bb aa/ [root@image_boundary Desktop]# cd aa [root@image_boundary aa]# ll total 4 drwxr-xr-x. 3 root root 4096 Oct 15 21:53 bb -rw-r--r--. 1 root root 0 Oct 15 20:59 sum.txt~7)mv:移动某个文件或目录-i:提示。-f:强制移动。-u:新覆盖旧,不存在时移动。① 将同一个文件,移动到同级目录下,必须修改文件名,效果相当于重命名。[root@image_boundary Desktop]# ll total 8 drwxr-xr-x. 2 root root 4096 Oct 15 21:55 aa drwxr-xr-x. 2 root root 4096 Oct 15 21:54 bb [root@image_boundary Desktop]# mv bb/sum.txt bb/sum1.txt
2022年06月