首页 文章 精选 留言 我的

精选列表

搜索[D3地图可视化],共10000篇文章
优秀的个人博客,低调大师

nginxWebUI 1.0.5 发布,nginx 可视化网页配置工具

功能说明 本项目可以使用WebUI配置nginx的各项功能, 包括http协议转发, tcp协议转发, 反向代理, 负载均衡, ssl证书自动申请、续签、配置等, 最终生成nginx.conf文件并覆盖nginx的默认配置文件, 完成nginx的最终功能配置. 部署此项目后, 配置nginx再也不用上网各种搜索, 再也不用手动申请和配置ssl证书, 只需要在本项目中进行增删改查就可方便的配置nginx。 nginx本身功能复杂, 本项目并不能涵盖nginx所有功能, 但支持配置的功能已经涵盖90%的nginx使用, 更高级的功能配置可根据需要在最终生成的nginx.conf中进行手动编写。 技术说明 本项目是基于springBoot的web系统, 数据库使用sqlite, 因此服务器上不需要安装任何数据库 其中orm使用了本人自己开源的sqlHelper项目作为orm, 使用sqlite作为数据库, 项目启动时会释放一个.sqlite.db到系统用户文件夹中, 注意进行备份 sqlHelper是一个可以像mongodb一样使用sql数据库的orm, 解放开发者对sql数据库表结构的维护工作, 支持sqlite, mysql, postgresql三种数据库, 有兴趣的可以了解一下https://gitee.com/cym1102/sqlHelper 本系统支持在系统内通过Let's encrypt申请和续签证书, 使用acme.sh脚本进行自动化申请, 开启续签的证书将在每天凌晨2点进行续签, 只有超过60天的证书才会进行续签. 本次更新内容 本次更新功能较多, 如果有bug请在评论区进行回复 添加tcp/ip转发配置支持, 可能需要重新编译安装nginx,通过添加–with-stream参数指定安装stream模块 支持ssl证书的申请和自动续签, 使用Let's encrypt和acme.sh进行签发 支持windows下nginx配置, 但不支持在windows下申请ssl证书 编译包下载地址 https://gitee.com/cym1102/nginxWebUI/releases

优秀的个人博客,低调大师

nginxWebUI 1.0.2 发布,nginx 可视化网页配置工具

功能说明 本项目是基于 springBoot 的 web 系统,数据库使用 sqlite,因此服务器上不需要安装任何数据库。 其中 orm 使用了本人自己开源的 sqlHelper项目作为 orm,使用 sqlite 作为数据库,项目启动时会释放一个 .sqlite.db 到系统用户文件夹中。 本项目可以使用 WebUI 配置 nginx 的各项功能,包括端口转发、反向代理、ssl 证书配置、负载均衡等,最终生成 nginx.conf 配置文件并覆盖目标配置文件,完成 nginx 的功能配置。 nginx 本身功能复杂,本项目并不能涵盖 nginx 所有功能,只能配置常用功能,更高级的功能配置仍然需要在最终生成的 nginx.conf 中进行手动编写。 安装教程见nginxWebUI 更新说明 完善不少html界面功能 http可以配多个参数 server可以配多个location upstream可以配负载均衡策略 sqlHelper升级到0.0.6

优秀的个人博客,低调大师

nginxWebUI 1.0.0 发布,nginx 可视化网页配置工具

功能说明 本项目是基于 springBoot 的 web 系统,数据库使用 sqlite,因此服务器上不需要安装任何数据库。 其中 orm 使用了本人自己开源的 sqlHelper 项目作为 orm,使用 sqlite 作为数据库,项目启动时会释放一个 .sqlite.db 到系统用户文件夹中。 sqlHelper是一个可以像 mongodb 一样使用 sql 数据库的 orm,解放开发者对 sql 数据库表结构的维护工作。 本项目可以使用 WebUI 配置 nginx 的各项功能,包括端口转发、反向代理、ssl 证书配置、负载均衡等,最终生成 nginx.conf 配置文件并覆盖目标配置文件,完成 nginx 的功能配置。 nginx 本身功能复杂,本项目并不能涵盖 nginx 所有功能,只能配置常用功能,更高级的功能配置仍然需要在最终生成的 nginx.conf 中进行手动编写。 安装教程见 https://gitee.com/cym1102/nginxWebUI

优秀的个人博客,低调大师

智能可视化搭建系统 Atom 服务架构演变

作者:凹凸曼 - Manjiz Atom 是什么?Atom 是集结业内各色资深电商行业设计师,提供一站式专业智能页面和小程序设计服务的平台。经过 2 年紧凑迭代,项目越来越庞大,需求不断变更优化,内部逻辑错综复杂,维护成本急剧拉升。同时,Atom 将要承载的业务越来越多,要向更多的内部用户和商家提供服务,为了适应这些变化,架构升级成为当时紧迫的事项,我们将解构服务端模块,让服务轻量化、模块化,更便捷地拓展业务场景。 Atom 服务端经历了三个版本的迭代,本文着重剖析第三个版本。 架构 1.0 这是 Atom 最古老的一个版本,在这一版本中,只规划了频道页的功能,目的是把开发人员从繁复的频道页开发中解放出来,因为功能目的纯粹,所以系统复杂度较低,服务端直接使用了 Koa 框架上手开发,这是一个单体架构的服务,所有的代码都在一个进程中运行。 在部署方面,运用的是非常原始的手工操作:开发人员登入机器,拉取代码后进行类似本地环境的安装启动,然后在不同机器重复这个过程。 另外,Quark 的旧版本使用的是具名组件,具名组件一定程度限制了 Quark 自身的扩展性,这里不作展开。 架构 2.0 从频道页搭建平台到多场景页面搭建平台,Atom 用了不到一年时间,更丰富的组件,更多的模板,更多的场景,更多参与进来的设计师,更多的用户,产品开发逐渐专业化,简单的手工运维已经不再适用,于是前端和服务端都进行了一次大换血,服务端用 Salak 重构,Salak 是个非常好上手的服务端框架,同时为我们带来了接口文档的自动化生成功能,前端和服务端都改为依靠 Talos(一容器式部署内部平台)来部署。服务端逐渐迈入工业时代。 然而,这个阶段仍然没解决粗放的开发方式,缺乏宏观上的规划,日益暴露了以下这些问题: 高度集中 90% 以上服务集中于一个单体架构中,业务越来越复杂,代码量越来越大,代码的可读性、可维护性和可扩展性下降,开发人员接入成本剧增,业务扩展的代价成指数上升,持续交付能力难以维持。随着用户越来越多,程序承受的并发越来越高,单体架构的应用的并发能力有限。由于系统复杂度的提高,测试的难度也越来越大。 耦合度高 单体中的各个模块间互相依赖,互相影响,互相掣肘,导致代码重用性低,新功能开发往往由于忌惮耦合逻辑中的隐藏彩蛋,而选择重新编写,这不是我们希望看到的! 逻辑混乱 除了耦合导致的逻辑混乱,Atom 作为一个从零成长起来的平台,本身就淤积了大量的历史需求,有些是不再使用的,有些是几乎不被使用的,这些代码逻辑给开发人员一个极大的挑战:在进行代码维护的时候不敢轻易改动代码。另外在迭代中需要向下兼容,让服务端有沉重的历史包袱。 代码冗余 由于框架在前期没有定义好规范标准,在开发过程比较严格遵守代码校验,代码的逻辑、常量等等重复定义,这也同时让项目变得难以维护,比如修改一个常量需要在保证没有遗漏的前提同时修改多处。 新架构目标 根据原有架构的优劣,我们设置了本次架构升级的目标: 服务模块化 服务通用化 插拔式站点 插拔式场景 标准与规范 名词解释: 站点:即把服务端与平台解耦,从原来的服务即平台,到可以为互相隔离的多个平台提供相同的服务。 场景:为应对不同业务类型而设定的概念,不同场景有不同的管理方式和流程等。 整体架构 整体架构分为 Web 应用层、接口层、服务层 和 数据层 4 部分,这样拆分能做到入口统一,在部署上的单点部署让发布更加的便捷,独立部署则降低对服务整体的影响: Web 应用层:包括 Atom 平台及其他的平台应用 接口层:提供网关服务,应用层的请求经由网关作权限控制及请求转发 服务层: 服务通信:异步通信使用 MQ,RPC 通信使用 HTTP 业务模块:核心代码,拆解众多小模块应用 基础服务:统一把控用户与权限 服务管理:提升服务的稳定性、健壮性、灵活性 数据层:核心数据存储 其中网关作为整个服务端的流量入口,对所有流量进行处理,拦截非法请求,解析登录态并传递到下游,校验接口权限以及超时响应等,统一把控,同时减轻下游的压力。 实施 计划/筹备/评估 在正式进入升级开发前,小组通过会议探讨架构升级的必要性和可行性,促使我们进行升级的直接原因是平台新增的站点需求和场景需求,如要在原有架构上实现这个需求,势必会在原已混乱的逻辑上增添更多的耦合逻辑,而间接原因,亦即升级必要性,则是要让系统模块化、标准化、通用化,让系统的逻辑更加清晰,提升整个系统的可维护性。 经过我们反复的探讨,对原系统按照功能进行分割,在功能的基础上再按照通用性进行进一步拆分,附加新架构的支撑性工作,评估这些工作的工作量和预计用时,最后对任务进行分配下达。 实施 模块化 为什么要模块化?随着平台越做越大,我们想要让各个部分的功能更加独立、明确、清晰,把各部分之间的影响降到最低,对各部分单独运维,避免牵一发而动全身的情况。 这次升级按照功能和通用性把项目划分为 10+ 个模块:如专门负责编译的模块,专门负责模板管理的模块,负责定时任务的模块,作为入口的网关等等。 其中拆分出来若干通用服务,通用服务作为独立于 Atom 系统之外的服务,可以为 Atom 以及其他系统提供服务。 对项目进行模块拆解,最为头疼的是斩断关联逻辑,模块的剥离和修复必然会导致一个问题——相同的代码在不同的模块重复出现。为了解决这个问题,我们把部分这些代码放到工具 npm 包中,这些代码包括了:常量、TypeScript 类型定义、权限映射、Mongoose Schema 定义、Salak 插件和工具方法等等。 另一个问题,在原架构中,模块间可以通过代码直接调用,那新架构中如何“还原”这个功能?为了保证解耦度,新架构中仅有少数需要即时调用的功能在模块间通过接口进行直接调用,其他的都是通过 MQ 消息队列和数据库进行互通。 对于 MQ 通信,这里举个例子:编译。服务端编译通常需要的时间比较长,长时间占用连接对服务性能有所影响,而且编译结果并不需要同步响应,对编译模块来说,如果来者不拒,对服务有不小的压力,于是我们决定使用消息队列来完成各个模块之间的通信: 由项目模块通过接口直接调用发布模块发起发布操作; 发布模块向消息池推送一条“我要编译”; 编译模块接收到消息后由自身情况判断是否可以进入编译,否则先不予以响应; 编译的各个状态也通过消息推送; 最后项目模块在接收到编译状态的消息后作各种处理。 通用化 前面提到在模块化的工作中,我们拆出了 4 个通用的服务模块,通用服务独立于 Atom 系统之外,可以为 Atom 以及其他系统提供服务。模块的通用化是出于两点考虑: 丰富部门的服务,减少重复开发功能 排除 Atom 非核心代码,让系统瘦身 伴随而来的一个问题值得我们思考,如何考量一个功能是否值得抽离通用化?我们应该尽量避免陷入一个误区:系统模块化就是把系统拆得越细越好。如果拆分过细,势必增加运维工作量。在拆分模块的时候,我们考量的是一个模块内的功能是否完整且独立,以及部门或公司对这个通用服务的需求度,真正地做到低耦合高内聚。 标准化 代码层面,下面做了个简单的对比: 对比项 旧架构 新架构 主要语言 JavaScript TypeScript 代码检测 未遵守 必需 接口名称 花样百出 统一形式 接口输出 百花齐放 统一形式 TypeScript 的好,前端人都知道,它为我们带来了自动补全、可选的类型系统,使我们能够用上更加新的 JavaScript 特性等等,更多可以参考《为什么选择 TypeScript》。出现后面三点的原因是什么?旧架构经历了从零到一的过程,项目在最初规划欠缺以及中后期没有足够的时间对系统进行修正,时间和需求的变更的双重作用导致代码淤积。 为此,我们在新架构的开发中就强调代码的标准化,对每次提交都要经过代码检测,然后是对五花八门的接口进行统一: 接口路径统一:旧架构中,一个列表接口的路径可能是 /xxx/list,也可能是 /xxx/xxxes 等等,我们在新架构中基于 RESTful API 规则,用资源名词组成的路径和语义化的 HTTP 协议统一接口的定义; 参数名统一:比如列表入参中每页数量可能叫 pageSize 也可能叫 count,于是我们把它统一成一个名字,要求在开发中遵守这个约定; 输出统一:在数据输出到前端前对数据进行处理筛选,剔除包括 _id 和 __v 等无关数据,在输出形式上也做了统一,要求输出中所有的 _id 都替换以 id 的名字出现等等。 代码标准化的好处是让代码更加好维护,开发人员很快就能定位到对应的接口代码,对前端而言则减少对接口的识别记忆。 插拔式站点 前面提到,这次架构升级的直接原因是站点需求和场景需求。如果在旧架构下迭代站点需求,只会进一步增加耦合度。为此,我们增加了站点管理模块,在几乎所有的数据项中增加了站点字段,给几乎所有的数据库查询都带上了站点参数。通过这些努力,现在新增站点只需要通过站点模块新增站点,再做一些初始化配置即可完成。 站点概念除对 Atom 功能有了更高要求,也对原来的权限体系形成了新的挑战。在升级前的版本中用户的权限仅有一个集合,要实现每个站点拥有不同的权限只能从两个角度出发: 权限含义拆分(为每个站点分别提供一套独立的权限) 用户权限增加一层抽象(用户的权限改变为多个集合根据站点进行切换) 在比较了两种修改形式后,拆分权限含义虽然在理解上比较容易代码也改动不多。但却大大提升了维护权限表的难度,相当于新增场景就需要增加一套权限,无法做到可插拔。最后在网关层增加了根据用户访问站点 切换权限集合的逻辑。 插拔式场景 场景是站点下面一个纬度,现有活动、频道、心理学测试、SNS、店铺几大场景,如果在旧架构下新增一个场景,需要排期进行开发,而且代码上恐怕也会增加不少针对不同场景的 if-else。为了更便捷省心地扩展和维护场景,我们对场景相关的代码从资源管理的角度做了拆解。 ATOM下每个场景拥有的资源主要有 模板/项目/标签/权限 四种: 标签 页面 | | 模板------>项目 权限 首先介绍项目模块目录的结构,项目模块的代码基于 策略模式 组织,每个场景的业务逻辑拆分到单独文件,由调度器直接调用,避免不同场景间逻辑掺杂。 调度器文件命名为 base_资源_service 场景策略文件命名为 场景小写_资源_service 通用策略文件命名为 common_资源_service 当用户查询进来时,调度器根据查询的条件直接调用对应策略文件中的方法(一般不允许直接调用指定场景的策略除非确认不会关联到其他场景的数据),当调度器没有没有找到对应场景下的策略时,默认会调用 common_service 的逻辑,所以各场景需要继承 common_service。以页面管理服务为例,调度器为 src/service/page 目录下的 base_page_service,通用逻辑为 common_page_service,频道页场景逻辑为 ch_page_service。 出于对场景下公有方法的统一抽象,服务中常用的 CRUD 方法接口 放置在 AbstractServiceClass 文件中 ├── src │ ├── service │ │ └── {resource} │ │ ├── base_{resource}_service 策略文件调用器,controller/mq 直接调用 │ │ ├── common_{resource}_service 通用策略文件,例如列表查询共用的参数处理 │ │ └── {scene}_{resource}_service 场景策略文件,场景特殊的 部署 数据迁移 鉴于这次升级的巨变,在新旧版本间的切换务必慎重,除了前端与服务端为此做的大量的联调外,我们还对数据进行了兼容性迁移,主要做法是通过迁移脚本把旧数据根据新架构的需要做多重处理,尔后写入新数据库中。 不中断部署 在单体架构中,每一次服务的发布部署都会造成几分钟的空窗。 为避免这种情况,在生产环境,我们保证每个模块至少拥有两个容器,在部署的时候,把部分容器从负载均衡摘除,然后循环检测容器是否还有流量,直至没有流量进来才进行更新操作,服务启动后重新添加到负载均衡,然后对剩下的容器进行同样的操作,这样做的好处是,保证了整个部署过程,服务是不中断的,避免了部署过程中的空档情况。 运维 为避免再重蹈旧架构下糟糕的运维体验及项目代码管理,我们为新架构梳理了一个运维文档,包括快速接入、开发、调试、部署方方面面的细节都尽可能详尽地记录下来。 为系统增加了监控,监控每个接口的性能和可用性。 效果 经过这次升级,基本达成计划中的效果: 清晰:逻辑梳理、去除冗余、TS 重构、ESNext 模块化:解耦 10+ 模块,独立运作;HTTP、MQ、数据层等多通信方式 标准化:强代码规范;接口统一;响应统一 通用化:4+ 通用模块,平台无关;抽取公共库、配置、插件、中间件等 易迁移:一键初始化;一键、单点、独立部署;入口统一 易扩展:+新增站点拓展能力;调整场景拓展;节省人力时间成本 95%+ 易维护:追加日志;一键部署;不中断部署 易对接:完备的 Joi 文档;详尽的接口变更记录;尽可能的向上兼容 工具/方法/协作 工具对项目的顺利进行有非常重要的影响,因此在这次升级中,我们尝试了多种工具。 为了保证项目成员对自己负责模块有清晰的了解以及对模块的改造有明确的图样,团队引入流程图工具用于梳理旧架构的模块并分工,梳理勾画新架构各个模块内部的逻辑等等。 在排期方面,我们实践使用到了甘特图,用甘特图按照模块对任务进行拆分,然后指派给对应的负责人并设置计划的进行时间,每天同步整体的进度,从甘特图可以清晰地了解项目的资源分配与排期,也能看到项目计划与实际的对照,有助于项目整体的进度把控。 甘特图对项目升级的任务进行了初步的划分,对于更细化的划分,我们放到了 IssueBoard,IssueBoard 像是一个简化版的任务看板,但对我们来说已经绰绰有余了,另外,选择它的理由还包括:它支持跟 git 提交进行联动,适合开发人员使用,可以通过每次提交来关闭相应的 Issue。 总结反思 在这次升级过程中,也暴露了一些不足,主要体现在排期与预期以及在前期的沟通上。 排期与预期 在升级筹划初期的排期过于乐观,而且在升级过程中没有再进行修正,当然这是客观原因造成的,团队要在有限的需求空窗期内完成升级以避免同时维护两个版本,这导致的后果是团队必须每天比计划花更多的时间。 沟通 在服务端进行升级时,没有跟前端沟通具体的细节,而这次升级又是非完全向下兼容的,所以在联调的时候给造成前端一定的困扰和不便。 参考 Atom:https://ling.jd.com/atom Salak:https://salakjs.github.io/docs/docs/zh-cn/introduction.html RESTful API:http://www.ruanyifeng.com/blog/2014/05/restful_api.html 原文地址:https://aotu.io/notes/2020/04/21/atom-services-upgrade/ 欢迎关注凹凸实验室博客:aotu.io 或者关注凹凸实验室公众号(AOTULabs),不定时推送文章:

优秀的个人博客,低调大师

Python数据分析及可视化-小测验

本文中测验需要的文件夹下载链接: https://pan.baidu.com/s/1OqFM2TNY75iOST6fBlm6jw 密码: rmbt 下载压缩包后解压如下图所示: image.png 首先将5题的文件复制形成副本,如下图所示: image.png 在资源管理器的路径中输入cmd,如下图所示: image.png 在上图中输入后,按Enter键运行进入cmd窗口。 在cmd窗口中输入并运行命令: jupyter notebook,如下图所示: image.png 在上图中输入后,按Enter键运行自动打开浏览器并且进入jupyter notebook编程界面。 在jupyter notebook中,点击 第一题,ipynb和 第一题-副本.ipynb。 浏览器会新建两个标签页,如下图所示: image.png 在两个标签页中,读者可以对照题目要求完成做题。 下面是5道题目作者的答案和解析。 1.第一大题 1.1 第一步:导入相应的模块 最后2行代码可以使作图时不出现编码错误,分别用来正常显示中文标签和正常显示负号。 import pandas as pd from pandas import Series,DataFrame import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus']=False #用来正常显示负号 1.2 第二步:利用pandas读取datasets目录下chipo.csv并显示前十行数据(赋值给变量chipo) csv文件默认的分隔符是逗号,pd.read_csv方法中sep关键字参数的默认值也为逗号,所以可以不写sep关键字。 显示前十行数据用chipo.head(10)即可。 chipo = pd.read_csv('datasets/chipo.csv') chipo.head(10) 1.3 第三步:根据列名为item_name中每种商品出现的频率,绘制出柱状图 给出的答案示例是购买次数排名第2-6名的商品的作图结果。chipo.item_name.value_counts()是对商品购买次数进行统计,返回的结果降序排列,数据类型为Series。plt.xticks()方法中可以填入1个参数或者多个参数,下面代码中采用的是填入3个参数。 x_list是x轴标记点,数据类型为列表;xticks_list是x轴标记点显示值,数据类型为列表; rotation设置为90,是x轴标记点显示值以右边为轴逆时针旋转90度。 plt.bar方法中指定每根柱子的颜色,这样才可以画出示例答案的效果。 mostOrder_list = chipo.item_name.value_counts().iloc[5:0:-1] xticks_list = mostOrder_list.index x_list = range(len(xticks_list)) y_list = mostOrder_list.values plt.bar(x_list, y_list, width=0.5, color=['b', 'orange', 'g', 'r', 'purple']) plt.xticks(x_list, xticks_list, rotation=90) plt.title('购买次数最多的商品排名') plt.xlabel('商品名称') plt.ylabel('出现的订单次数') plt.show() 上面这段代码的运行结果如: 柱形图.png 1.4 第四步:根据订单编号(order_id)进行分组,求出每个订单花费的总金额,例如订单编号为1的总金额为11.56美元。然后根据每笔订单的总金额和每笔订单购买商品的总数量画出散点图(总金额为x轴,商品总数为y轴)。 先将chipo这个变量深度拷贝给c变量,这样可以避免影响原数据,使代码每次都能成功运行。 item_price这个单词是一个条目的价格,不是单个商品的单价。 我们平时超市购物的单子的最后price那一列也是算的这一个条目的价格,比如2个相同的商品算1个条目。 c = chipo.copy() c.quantity = c.quantity.astype('int') c.item_price = c.item_price.str.strip('$').astype('float') order_group = c.groupby('order_id') x_list = order_group.item_price.sum() y_list = order_group.quantity.sum() plt.scatter(x_list, y_list, color='g') plt.xlabel('订单总价') plt.ylabel('商品总数') plt.title('每笔订单总金融和购买商品数量关系') plt.show() 上面这段代码的运行结果如下: 散点图.png 2.第二大题 2.1 第一步:导入相应的模块 最后2行代码可以使作图时不出现编码错误,分别用来正常显示中文标签和正常显示负号。 import pandas as pd from pandas import Series,DataFrame import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus']=False #用来正常显示负号 2.2 第二步:利用pandas读取datasets目录下special_top250.csv并显示前五行数据(赋值给变量top250) csv文件默认的分隔符是逗号,pd.read_csv方法中sep关键字参数的默认值也为逗号,所以可以不写sep关键字。 显示前五行数据用chipo.head()即可。 top250 = pd.read_csv('datasets/special_top250.csv') top250.head() 2.3 第三步:在同一个图中绘制出电影时长和电影排名的散点图关系及电影时长的频率分布直方图,分50组,如下图所示: x_series = top250.movie_duration y_series = top250.num plt.figure(figsize=(14,6)) plt.subplot(121) plt.scatter(x_series, y_series) plt.xlabel('电影时长') plt.ylabel('电影排名') plt.gca().invert_yaxis() plt.subplot(122) plt.hist(x_series,bins=50) plt.show() 上面一段代码的运行结果如下: image.png 2.4 第四步:由上图中电影时长的频率分布直方图,并不能比较准确的反映出每个分组下电影的数量,请根据以下提示,绘制如下图所示根据电影时长分组的柱状图 bins = [0,80,120,140,180,1000] tags = ['偏短','标准','正常','偏长','超长'] 2.5 第五步:具体显示每个分组下的电影数量 在pandas官网中查询pandas.cut函数中的参数,其中参数bins是数据区间分割值,参数labels是数据按照区间分类后的标签,如下图所示。如果参数bins和labels都是可迭代对象,则bins比labels长度大1。 pandas.cut用法官方文档.png 将电影时长分类后赋值给duration_labeled_series变量,数据类型为Series。查看其中的值,如下图所示: image.png 对duration_labeled_series变量统计每个分类出现的次数,使用value_counts方法。 duration_series = top250.movie_duration duration_labeled_series = pd.cut(duration_series, bins=bins, labels=tags) duration_labeled_series.value_counts() 2.6 第六步:绘制出结果图 duration_stat_series = duration_labeled_series.value_counts(sort=False) duration_stat_series.plot(kind='bar') plt.show() 上面一段代码的运行结果如下: image.png 3.第三大题 3.1 第一步:导入相关模块 最后2行代码可以使作图时不出现编码错误,分别用来正常显示中文标签和正常显示负号。 import pandas as pd from pandas import Series,DataFrame import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus']=False #用来正常显示负号 3.2 第二步:加载datasets下的tips.csv文件数据,并显示前五行记录 csv文件默认的分隔符是逗号,pd.read_csv方法中sep关键字参数的默认值也为逗号,所以可以不写sep关键字。 显示前五行数据用chipo.head()即可。 tip_df = pd.read_csv('datasets/tips.csv') tip_df.head() 3.3 第三步:绘制消费金额频率分布直方图 plt.hist方法中参数bins用来指定出现多少根柱子,参数width用来指定每根柱子的宽度。 plt.hist(tip_df.total_bill, bins=10, width=4) plt.xlabel('消费总金额') plt.ylabel('频率') plt.show() 上面一段代码的运行结果如下图所示: 直方图.png 3.4 第四步:绘制总消费金额与小费金额的散点图关系 利用plt.scatter方法画出散点图 plt.scatter(tip_df.total_bill, tip_df.tip) plt.xlabel('总消费金额') plt.ylabel('小费金额') plt.show() 上面一段代码的运行结果如下: 散点图.png 3.5 第五步:在同一图中绘制出吸烟顾客与不吸烟顾客的消费金额与小费之间的散点图关系 观察示例答案中左右两幅图,不同的地方有:处于画板的位置、标题、散点颜色。 定义函数drawScatter用于绘制散点图,传入4个参数:数据group、处于画板的位置subplot、标题title、散点颜色。 def drawScatter(group, subplot, title, color): plt.subplot(subplot) plt.xlabel('消费总金额') plt.ylabel('小费金额') plt.title(title) plt.scatter(group.total_bill, group.tip, color=color) plt.figure(figsize=(12,6)) for name,group in tip_df.groupby('smoker'): if name == 'Yes': drawScatter(group, 121, '吸烟顾客', 'green') else: drawScatter(group, 122, '不吸烟顾客', 'blue') plt.show() 上面一段代码的运行结果如下: 组合散点图.png 3.6 第六步:在同一图中绘制出女性与男性中吸烟与不吸烟顾客的消费金额与小费之间的散点图关系 在有2组散点的散点图当中,第1组散点默认为橘黄色,第2组散点默认为天蓝色。 def drawScatter2(df, subplot, title, sex): plt.subplot(subplot) plt.title(title) for name, group in df.groupby('smoker'): if name == 'Yes': plt.scatter(group.total_bill, group.tip, label=sex+'吸烟顾客') else: plt.scatter(group.total_bill, group.tip, label=sex+'不吸烟顾客') plt.legend() plt.figure(figsize=(12,6)) for name,group in tip_df.groupby('sex'): if name == 'Male': drawScatter2(group, 121, 'sex=Male', '男性') else: drawScatter2(group, 122, 'sex=Female', '女性') plt.show() 上面一段代码的运行结果如下图所示: 组合散点图.png 4.第四大题 4.1 第一步:导入相应的模块 import os import re import numpy as np import pandas as pd from bs4 import BeautifulSoup 4.2 第二步:读取nlp文件夹下的labeledTraniData.tsv文件 df = pd.read_csv("nlp/labeledTrainData.tsv", sep='\t', escapechar='\\') print('记录数: {}'.format(len(df))) df.head() 4.3 第三步:请按如下步骤,对影评数据做预处理,大概有以下环节: 去掉html标签 移除标点 切分成单词列表 去掉停用词 重组为新的句子 def display(text, title): print(title) print("\n----------我是分割线-------------\n") print(text) 4.4 第四步:提取出原始数据中的第一行review列中的文本数据,并用display函数进行输出显示 text1 = df.iloc[1]['review'] display(text1, '原始数据') 4.5 第五步:用BeautifulSoup将第四步中获取到的数据中的html标签去除 text2 = BeautifulSoup(text1, 'lxml').text display(text2, '去掉HTML标签的数据') 4.6 第六步:将第五步数据中的标点符号去掉(用正则) text3 = re.sub('[^\w\s]', '',text2) display(text3, '去掉标点的数据') 4.7 第七步:将第六步的数据全部转换成小写并转换成列表 text4 = text3.lower() word_list = text4.split(' ') display(word_list, '纯词列表数据') 4.8 第八步:去掉第七步数据中的英文停用词 4.8.1 加载英文停用词 with open('nlp/stopwords.txt') as file: stopword_list = [k.strip() for k in file.readlines()] 4.8.2 利用加载的英文停用词,去除第七部数据中的英文停用词 new_word_list = [k for k in word_list if k not in stopword_list] display(new_word_list, '去掉停用词数据') 4.8.3 为确保所加载的英文停用词没有重复数据,请对8-1中加载的英文停用词去重 stopword_list = list(set(stopword_list)) 4.9 第九步:将第五步到第八步的过程总结归纳为一个函数,名为clean_text,参数为text即输入到函数中的文本 这个函数就是对前面零散步骤的总结,所以前面的大部分代码可以直接复制过来。 with open('nlp/stopwords.txt') as file: stopword_list = [k.strip() for k in file.readlines()] stopword_list = list(set(stopword_list)) def clean_text(text1): text2 = BeautifulSoup(text1, 'lxml').text text3 = re.sub('[^\w\s]', '',text2) text4 = text3.lower() word_list = text4.split(' ') new_word_list = [k for k in word_list if k not in stopword_list] return ' '.join(new_word_list) 4.10 第十步:用apply方法,将第九步中定义的函数应用到第二步加载的df中,并生成一列清洗之后的数据列,名为clean_review df['clean_review'] = df.review.apply(clean_text) df.head() 上面一段代码的运行结果如下图所示: 第4题最终结果.png 5.第五大题 5.1 第一步:导入相关模块 最后2行代码可以使作图时不出现编码错误,分别用来正常显示中文标签和正常显示负号。 import pandas as pd from pandas import Series,DataFrame import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus']=False #用来正常显示负号 5.2 第二步:加载datasets目录下US_Baby_names_right.csv文件数据并查看数据的基本信息 baby_df = pd.read_csv('datasets/US_Baby_names_right.csv') baby_df.info() 5.3 第三步:写出删除 Unname:0和Id列数据的两种方法,第二种注释即可 new_df = baby_df.drop(['Unnamed: 0', 'Id'], axis=1) # del baby_df['Unnamed: 0'] # del baby_df['Id'] new_df.head() 5.4 第四步:写出能够判断出数据集中男孩多还是女孩多的代码并给出结论 baby_df.Gender.value_counts() 5.5 第五步:按照Name字段将数据集进行分组并求和赋值给变量names,最后输出前五行 names = new_df.groupby('Name').sum() names.head() 5.6 第六步:按照每个名字被使用的次数(Count)对第五步中结果进行降序排序,得出最受欢迎的的五个名字 sorted_names = names.sort_values(by='Count', ascending=False) sorted_names.head() 5.7 第七步:在数据集中,共出现了多少个名字?(不包含重复项,至少使用两种方法) 第1种方法: len(baby_df.Name.unique()) 第2种方法: len(names) 第3种方法: baby_df.Name.value_counts().count() 5.8 第八步:出现次数最少的名字共有几个? min_count = sorted_names.iloc[-1]['Count'] len(names[names.Count == min_count]) 5.9 第九步:根据names变量中的数据,删除掉Year列数据后,得出如下所示的基本统计参数 names.drop('Year', axis=1).describe()

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册