diff --git a/.gitignore b/.gitignore
index da4f18b4..714fa7e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
-.vscode
+.idea
+.vscode
.github
img/*.html
notebook
+venv
diff --git a/README.md b/README.md
index 4bec438b..91ab7d1f 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+
@@ -7,1717 +8,295 @@
-
-
+
## 介绍
-告别枯燥,告别枯燥,致力于打造 Python 经典小例子、小案例。 如果转载本库小例子、小案例,请备注下方链接:Python小例子 https://github.com/jackzhenguo/python-small-examples
-
-查看完整的旧版本:[改版前V3.0](V3.md)
-
-## 贡献
-
-欢迎贡献小例子到此库
+告别枯燥,告别枯燥,致力于打造 Python 经典小例子、小案例。
## License
-允许按照要求转载,但禁止用于任何商用目的。
-
-## Python 原创教程
-这是经过很久打磨的一个Python教程,全部是个人原创,已首发在公众号,并且托管在我的[个人网站](http://www.zglg.work/python-level/)。想系统入门Python的欢迎学习:
-
-[Python进阶完整教程](http://www.zglg.work/python-level/)
-
-
-
-适合小白的 Python 系统入门课程
-
-- [0 Python引言](http://www.zglg.work/Python-20-topics/intro-python/)
-- [1 数字专题](http://www.zglg.work/Python-20-topics/python-number/)
-- [2 字符串专题](http://www.zglg.work/?page_id=540)
-- 3 列表专题
- - [3.1 列表基础](http://www.zglg.work/?page_id=563)
- - [3.2 列表进阶](http://www.zglg.work/?page_id=575)
-- 4 流程控制专题
- - [4.1 流程控制基础](http://www.zglg.work/?page_id=618)
- - [4.2 流程控制进阶](http://www.zglg.work/?page_id=621)
-- 5 编程风格
- - [5.1 基本编程习惯](http://www.zglg.work/?page_id=654)
- - [5.2 EAFP 防御编程风格](http://www.zglg.work/?page_id=657)
- - [5.3 LBYL 防御编程风格](http://www.zglg.work/?page_id=659)
-- 6 Python 函数
- - [6.1 函数组成](http://www.zglg.work/?page_id=883)
- - [6.2 引用传参](http://www.zglg.work/?page_id=885)
- - [6.3 默认参数与关键字参数](http://www.zglg.work/?page_id=887)
- - [6.4 可变参数](http://www.zglg.work/?page_id=889)
- - [6.6 偏函数](http://www.zglg.work/?page_id=892)
- - [6.7 递归函数](http://www.zglg.work/?page_id=894)
- - [6.8 匿名函数](http://www.zglg.work/?page_id=896)
- - [6.9 高阶函数](http://www.zglg.work/?page_id=898)
- - [6.10 嵌套函数](http://www.zglg.work/?page_id=900)
-- 7 面向对象编程基础
- - [7.1 类定义](http://www.zglg.work/?page_id=904)
- - [7.2 对象或实例](http://www.zglg.work/?page_id=906)
- - [7.3 打印对象](http://www.zglg.work/?page_id=908)
- - [7.4 属性](http://www.zglg.work/?page_id=910)
- - [7.5 private,protected,public](http://www.zglg.work/?page_id=913)
- - [7.6 继承](http://www.zglg.work/?page_id=916)
- - [7.7 多态](http://www.zglg.work/?page_id=918)
-
-后续章节正在整理推送中。
-
-
-
-## Python 小例子
-
-| 小例子 | 链接 | 标签 | 版本 | 难度 |
-| ---- | ---------------------------------- | ---- | ---- | ---- |
-| 1 | [实现 relu](md/1.md) | max | V4.0 | ⭐️⭐️ |
-| 2 | [进制转化](md/2.md) | bin,oct,hex | V4.0 | ⭐️⭐️ |
-| 3 | [整数和ASCII互转](md/3.md) | chr,ord | V1.0 | ⭐️⭐️ |
-| 4 | [元素都为真检查](md/4.md) | all | V2.0 | ⭐️⭐️⭐️ |
-| 5 | [至少一个为真检查](md/5.md) | any | V2.0 | ⭐️⭐️⭐️ |
-| 6 | [判断是真是假](md/6.md) | bool | V2.0 | ⭐️⭐️⭐️ |
-| 7 | [创建复数](md/7.md) | complex | V1.0 | ⭐️⭐️⭐️ |
-| 8 | [取商和余数](md/8.md) | divmod | V1.0 | ⭐️⭐️ |
-| 9 | [转为浮点类型](md/9.md) | float | V1.0 | ⭐️⭐️ |
-| 10 | [转为整型](md/10.md) | int | V1.0 | ⭐️ |
-| 11 | [次幂](md/11.md) | pow | V1.0 | ⭐️ |
-| 12 | [四舍五入](md/12.md) | round | V1.0 | ⭐️ |
-| 13 | [链式比较](md/13.md) | compare | V1.0 | ⭐️⭐️ |
-| 14 | [字符串转字节](md/14.md) | bytes,utf-8 | V1.0 | ⭐️⭐️ |
-| 15 | [任意对象转为字符串](md/15.md) | str | V1.0 | ⭐️⭐️ |
-| 16 | [执行字符串表示的代码](md/16.md) | compile | V1.0 | ⭐️⭐️⭐️ |
-| 17 | [计算表达式](md/17.md) | eval | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 18 | [字符串格式化](md/18.md) | format | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 19 | [拿来就用的排序函数](md/19.md) | sorted | V1.0 | ⭐️⭐️⭐️ |
-| 20 | [求和函数](md/20.md) | sum | V1.0 | ⭐️⭐️ |
-| 21 | [nonlocal用于内嵌函数中](md/21.md) | nonlocal | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 22 | [global 声明全局变量](md/22.md) | global | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 23 | [交换两元素](md/23.md) | pack,unpack | V1.0 | ⭐️⭐️ |
-| 24 | [操作函数对象](md/24.md) | operator | V2.0 | ⭐️⭐️⭐️⭐️ |
-| 25 | [生成逆序序列](md/25.md) | range | V1.0 | ⭐️⭐️ |
-| 26 | [函数的五类参数使用例子](md/26.md) | variable parameter | V2.0 | ⭐️⭐️⭐️⭐️ |
-| 27 | [使用slice对象](md/27.md) | slice | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 28 | [lambda 函数](md/28.md) | lambda | V3.0 | ⭐️⭐️⭐️⭐️ |
-| 29 | [转为字典](md/29.md) | dict | V1.0 | ⭐️⭐️ |
-| 30 | [冻结集合](md/30.md) | frozenset | V1.0 | ⭐️⭐️ |
-| 31 | [转为集合类型](md/31.md) | set | V1.0 | ⭐️⭐️ |
-| 32 | [转元组](md/32.md) | tuple | V1.0 | ⭐️⭐️ |
-| 33 | [对象是否可调用](md/33.md) | callable | V2.5 | ⭐️⭐️⭐️⭐️ |
-| 34 | [ascii 展示对象](md/34.md) | `__repr__` | V2.5 | ⭐️⭐️⭐️ |
-| 35 | [类方法](md/35.md) | classmethod | V1.5 | ⭐️⭐️⭐️ |
-| 36 | [动态删除属性](md/36.md) | delattr,hasattr | V1.5 | ⭐️⭐️ |
-| 37 | [一键查看对象所有方法](md/37.md) | dir | V1.5 | ⭐️⭐️ |
-| 38 | [动态获取对象属性](md/38.md) | getattr | V1.5 | ⭐️⭐️ |
-| 39 | [对象是否有某个属性](md/39.md) | hasattr | V1.5 | ⭐️⭐️⭐️ |
-| 40 | [对象门牌号](md/40.md) | id | V1.0 | ⭐️ |
-| 41 | [实例和对象关系判断](md/41.md) | isinstance | V1.5 | ⭐️⭐️⭐️ |
-| 42 | [issubclass父子关系鉴定](md/42.md) | issubclass | V1.5 | ⭐️⭐️⭐️ |
-| 43 | [所有对象之根](md/43.md) | object | V1.0 | ⭐️ |
-| 44 | [创建属性的两种方法](md/44.md) | property | V2.5 | ⭐️⭐️⭐️⭐️⭐️ |
-| 45 | [查看对象类型](md/45.md) | type | V1.0 | ⭐️ |
-| 46 | [元类使用介绍](md/46.md) | type,`__class__` | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 47 | [枚举对象](md/47.md) | enumerate | V1.0 | ⭐️⭐️⭐️ |
-| 48 | [查看变量所占字节数](md/48.md) | getsizeof | V1.0 | ⭐️⭐️⭐️ |
-| 49 | [过滤器filter](md/49.md) | filter | V1.5 | ⭐️⭐️⭐️ |
-| 50 | [返回对象哈希值](md/50.md) | hash | V1.0 | ⭐️⭐️ |
-| 51 | [help 一键帮助](md/51.md) | help | V1.0 | ⭐️ |
-| 52 | [获取用户输入](md/52.md) | input | V1.0 | ⭐️ |
-| 53 | [创建迭代器](md/53.md) | iter,`__iter__` | V1.5 | ⭐️⭐️⭐️ |
-| 54 | [文件读写和mode 取值表](md/54.md) | open,read,write,with,mode | V2.0 | ⭐️⭐️⭐️ |
-| 55 | [创建range序列](md/55.md) | range | V1.0 | ⭐️⭐️ |
-| 56 | [反向迭代器reversed](md/56.md) | reversed | V1.0 | ⭐️⭐️ |
-| 57 | [zip迭代器](md/57.md) | zip | V1.5 | ⭐️⭐️⭐️ |
-| 58 | [operator使用举例](md/58.md) | operator | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 59 | [传输json对象](md/59.md) | json | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 60 | [不用else和if实现计算器](md/60.md) | operator | V1.0 | ⭐️⭐️⭐️ |
-| 61 | [去最求平均](md/61.md) | list,sort,round | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 62 | [打印99乘法表](md/62.md) | for,range,format | V1.0 | ⭐️⭐️⭐️ |
-| 63 | [递归版flatten函数](md/63.md) | recursion,list,isinstance | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 64 | [列表等分为n份](md/64.md) | list,ceil | V1.0 | ⭐️⭐️⭐️ |
-| 65 | [压缩列表](md/65.md) | list,filter | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 66 | [求更长的列表](md/66.md) | max,lambda | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 67 | [求列表众数](md/67.md) | max,lambda,count | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 68 | [所有多个列表的最大值](md/68.md) | max,lambda | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 69 | [列表检查重复](md/69.md) | set | V1.0 | ⭐️⭐️⭐️ |
-| 70 | [一行代码实现列表反转](md/70.md) | reverse | V1.0 | ⭐️⭐️ |
-| 71 | [浮点数等差数列](md/71.md) | range,float | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 72 | [按条件分组](md/72.md) | lambda | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 73 | [map实现向量运算](md/73.md) | map,lambda | V1.0 | ⭐️⭐️⭐️ |
-| 74 | [值最大的字典](md/74.md) | max,lambda | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 75 | [合并两个字典](md/75.md) | ** | V1.0 | ⭐️⭐️⭐️ |
-| 76 | [Topn 字典](md/76.md) | heapq,nlargest | V1.0 | ⭐️⭐️⭐️ |
-| 77 | [判断是否为异位词](md/77.md) | collections,Counter | V1.0 | ⭐️⭐️⭐️ |
-| 78 | [逻辑上合并字典](md/78.md) | ChainMap | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 79 | [带名字的元组](md/79.md) | namedtuple | V1.0 | ⭐️⭐️⭐️ |
-| 80 | [sample 样本抽样](md/80.md) | random,sample | V1.0 | ⭐️⭐️⭐️ |
-| 81 | [重洗数据集](md/81.md) | shuffle | V1.0 | ⭐️⭐️⭐️ |
-| 82 | [10个均匀分布的坐标点](md/82.md) | random,uniform | V1.0 | ⭐️⭐️⭐️ |
-| 83 | [10个高斯分布的坐标点](md/83.md) | random,gauss | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 84 | [chain串联小容器为大容器](md/84.md) | itertools,chain | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 85 | [product 使用案例](md/85.md) | product | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 86 | [反转字符串的两个方法](md/86.md) | reversed | V1.0 | ⭐️⭐️ |
-| 87 | [join 串联字符串](md/87.md) | join | V1.0 | ⭐️⭐️ |
-| 88 | [字符串字节长度](md/88.md) | encode | V1.0 | ⭐️⭐️ |
-| 89 | [正则中字符 `r`作用](md/89.md) | re,r | V3.0 | ⭐️⭐️⭐️ |
-| 90 | [正则原子操作](md/90.md) | re | V3.0 | ⭐️⭐️⭐️ |
-| 91 | [正则中的转义](md/91.md) | re,\ | V3.0 | ⭐️⭐️⭐️ |
-| 92 | [正则最普通查找](md/92.md) | re,findall | V3.0 | ⭐️⭐️⭐️ |
-| 93 | [使用通用字符查找](md/93.md) | re,\s,\w,\d | V3.0 | ⭐️⭐️⭐️ |
-| 94 | [使用元字符查找](md/94.md) | re,+,* | V3.0 | ⭐️⭐️⭐️ |
-| 95 | [捕获子串](md/95.md) | () | V3.0 | ⭐️⭐️⭐️⭐️ |
-| 96 | [贪心捕获和非贪心捕获](md/96.md) | re | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 97 | [使用正则做密码安全检查](md/97.md) | re | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 98 | [爬取百度首页标题](md/98.md) | re | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 99 | [批量转化为驼峰格式(Camel)](md/99.md) | re | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 100 | [是否互为排序词](md/100.md) | collections,defaultdict | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 101 | [str1是否由str2旋转而来](md/101.md) | str | V1.0 | ⭐️⭐️⭐️ |
-| 102 | [使用正则判断是否为正浮点数](md/102.md) | str,re,float | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 103 | [获取文件后缀名](md/103.md) | os,splitext | V1.0 | ⭐️⭐️ |
-| 104 | [获取路径中的文件名](md/104.md) | os,split | V1.0 | ⭐️⭐️ |
-| 105 | [批量修改文件后缀](md/105.md) | argparse,listdir | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 106 | [xls批量转换成xlsx](md/106.md) | os,listdir,splitext | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 107 | [获取指定后缀名的文件](md/107.md) | os,listdir,splitext | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 108 | [批量压缩文件](md/108.md) | zipfile | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 109 | [32位加密](md/109.md) | hashlib | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 110 | [年的日历图](md/110.md) | calendar | V1.0 | ⭐️⭐️ |
-| 111 | [判断是否为闰年](md/111.md) | calendar | V1.0 | ⭐️⭐️⭐️ |
-| 112 | [判断月有几天](md/112.md) | calendar,datetime | V1.0 | ⭐️⭐️⭐️ |
-| 113 | [月的第一天](md/113.md) | datetime | V1.0 | ⭐️⭐️ |
-| 114 | [月的最后一天](md/114.md) | calendar,datetime | V1.0 | ⭐️⭐️ |
-| 115 | [获取当前时间](md/115.md) | time,datetime | V1.0 | ⭐️⭐️ |
-| 116 | [字符时间转时间](md/116.md) | time,datetime | V1.0 | ⭐️⭐️ |
-| 117 | [时间转字符时间](md/117.md) | time,datetime | V1.0 | ⭐️⭐️ |
-| 118 | [默认启动主线程](md/118.md) | threading | V1.0 | ⭐️⭐️ |
-| 119 | [创建线程](md/119.md) | threading | V1.0 | ⭐️⭐️ |
-| 120 | [交替获得CPU时间片](md/120.md) | threading | V1.0 | ⭐️⭐️⭐️ |
-| 121 | [多线程抢夺同一个变量](md/121.md) | threading | V1.0 | ⭐️⭐️⭐️ |
-| 122 | [多线程变量竞争引起的问题](md/122.md) | threading | V1.0 | ⭐️⭐️⭐️ |
-| 123 | [多线程锁](md/123.md) | threading,lock | V1.0 | ⭐️⭐️⭐️ |
-| 124 | [时间转数组及常用格式](md/124.md) | time,datetime,format | V1.0 | ⭐️⭐️⭐️ |
-| 125 | [寻找第n次出现位置](md/125.md) | enumerator | V1.0 | ⭐️⭐️⭐️ |
-| 126 | [斐波那契数列前n项](md/126.md) | yield,range | V1.0 | ⭐️⭐️⭐️ |
-| 127 | [找出所有重复元素](md/127.md) | calendar,datetime | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 128 | [联合统计次数](md/128.md) | Counter | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 129 | [groupby单字段分组](md/129.md) | itertools, groupby,lambda | V1.0 | ⭐️⭐️⭐️ |
-| 130 | [groupby多字段分组](md/130.md) | itemgetter,itertools,groupby | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 131 | [itemgetter和key函数](md/131.md) | operator,itemgetter,itertools | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 132 | [sum函数计算和聚合同时做](md/132.md) | sum,generator | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-| 133 | [获得某天后的1~n天](md/133.md) | Calendar,monthrange | V4.0 | ⭐️⭐️⭐️ |
-| 134 | [list分组(生成器版)](md/134.md) | yield,generator | V1.0 | ⭐️⭐️⭐️ |
-| 135 | [列表全展开(生成器版)](md/135.md) | list,yield,generator | V1.0 | ⭐️⭐️⭐️ |
-| 136 | [测试函数运行时间的装饰器](md/136.md) | decorator | V1.0 | ⭐️⭐️⭐️⭐️ |
-| 137 | [统计异常次数装饰器](md/137.md) | decorator,nonlocal | V1.5 | ⭐️⭐️⭐️⭐️ |
-| 138 | [通俗理解装饰器](md/138.md) | decorator | V1.0 | ⭐️⭐️⭐️ |
-| 139 | [定制递减迭代器](md/139.md) | Iterator | V3.0 | ⭐️⭐️⭐️⭐️ |
-| 140 | [turtle绘制奥运五环图](md/140.md) | turtle | V1.0 | ⭐️⭐️⭐️ |
-| 141 | [turtle绘制漫天雪花](md/141.md) | turtle | V1.0 | ⭐️⭐️⭐️ |
-| 142 | [Python词云图](md/142.md) | WordCloud | V1.0 | ⭐️⭐️⭐ |
-| 143 | [Plotly柱状图和折线图](md/143.md) | plotly | V1.0 | ⭐️⭐ |
-| 144 | [seaborn热力图](md/144.md) | seaborn | V1.0 | ⭐️⭐ |
-| 145 | [Pyecharts仪表盘](md/145.md) | pyecharts | V1.0 | ⭐️⭐ |
-| 146 | [Pyecharts漏斗图](md/146.md) | pyecharts | V1.0 | ⭐️⭐ |
-| 147 | [Pyecharts水球图](md/147.md) | pyecharts | V1.0 | ⭐️⭐ |
-| 148 | [Pyecharts饼图](md/148.md) | pyecharts | V1.0 | ⭐️⭐ |
-| 149 | [Pyecharts极坐标图](md/149.md) | pyecharts | V1.0 | ⭐️⭐ |
-| 150 | [Pyecharts词云图](md/150.md) | pyecharts | V1.0 | ⭐️⭐ |
-| 151 | [Pyecharts热力图](md/151.md) | pyecharts | V1.0 | ⭐️⭐ |
-| 152 | [matplotlib绘制动图](md/152.md) | matplotlib | V1.0 | ⭐️⭐ |
-| 153 | [seaborn pairplot图](md/153.md) | seaborn | V1.0 | ⭐️⭐⭐⭐ |
-| 154 | [含单个元素的元组](md/154.md) | tuple | V1.0 | ⭐️⭐ |
-| 155 | [默认参数设为空](md/155.md) | function | V1.0 | ⭐️⭐⭐ |
-| 156 | [共享变量未绑定之坑](md/156.md) | global | V1.0 | ⭐️⭐⭐ |
-| 157 | [lambda自由参数之坑](md/157.md) | lambda | V1.0 | ⭐️⭐⭐ |
-| 158 | [各种参数使用之坑](md/158.md) | function paremeter | V1.0 | ⭐️⭐⭐ |
-| 159 | [列表删除之坑](md/159.md) | list | V1.0 | ⭐️⭐ |
-| 160 | [列表快速复制之坑](md/160.md) | list | V1.0 | ⭐️⭐⭐ |
-| 161 | [字符串驻留](md/161.md) | str | V1.0 | ⭐️⭐⭐⭐⭐ |
-| 162 | [相同值的不可变对象](md/162.md) | mutable | V1.0 | ⭐️⭐⭐ |
-| 163 | [对象销毁顺序](md/163.md) | OOP del | V1.0 | ⭐️⭐⭐⭐ |
-| 164 | [充分认识for](md/164.md) | for | V1.0 | ⭐️⭐⭐ |
-| 165 | [认识执行时机](md/165.md) | generator | V1.0 | ⭐️⭐⭐⭐⭐ |
-| 166 | [创建空集合错误](md/166.md) | set | V1.0 | ⭐️⭐ |
-| 167 | [pyecharts传入Numpy数据绘图失败](md/167.md) | numpy pyecharts | V1.0 | ⭐️⭐⭐ |
-| 168 | [优化代码异常输出包](md/168.md) | debugger | V1.0 | ⭐️⭐⭐ |
-| 169 | [图像处理包pillow](md/169.md) | pillow | V1.0 | ⭐️⭐⭐ |
-| 170 | [一行代码找到编码](md/170.md) | chardet | V1.0 | ⭐️⭐⭐ |
-| 171 | [子类继承父类的静态方法吗?](md/171.md) | staticmethod | V1.0 | ⭐️⭐⭐ |
-| 172 | [NumPy 的pad填充方法](md/172.md) | NumPy pad | V1.0 | ⭐️⭐⭐⭐ |
-| 173 | [创建下对角线为1、2、3、4的对角矩阵](md/173.md) | NumPy diag | V1.0 | ⭐️⭐⭐ |
-| 174 | [cut 数据分箱](md/174.md) | Pandas cut | v1.0 | ⭐️⭐⭐ |
-| 175 | [丢弃空值和填充空值](./md/175.md) | Pandas dropna fillna | v1.0 | ⭐️⭐⭐ |
-| 176 | [一行代码让 pip 安装加速 100 倍](md/176.md) | pip install | v1.0 | ⭐️⭐⭐ |
-| 177 | [数据分析神器:deepnote](./md/177.md) | deepnote | v1.0 | ⭐️⭐⭐ |
-| 178 | [apply 方法去掉特殊字符](./md/178.md) | pandas apply | v1.0 | ⭐️⭐⭐ |
-| 179 | [使用map对列做特征工程](./md/179.md) | pandas map | v1.0 | ⭐️⭐⭐ |
-| 180 | [category列转数值](./md/180.md) | pandas category | v1.0 | ⭐️⭐⭐ |
-| 181 | [rank排名](./md/181.md) | pandas rank | v1.0 | ⭐️⭐⭐|
-| 182 | [完成数据下采样,调整步长由小时为天](./md/182.md) | pandas resample | v1.0 | ⭐️⭐⭐ |
-| 183 | [如何用 Pandas 快速生成时间序列数据](./md/183.md) | pandas util | v1.0 | ⭐️⭐⭐ |
-| 184 | [如何快速找出 DataFrame 所有列 null 值个数](./md/184.md) | pandas isnull sum | v1.0 | ⭐️⭐⭐ |
-| 185 | [重新排序 DataFrame 的列](./md/185.md) | pandas dataframe | v1.0 | ⭐️⭐⭐ |
-| 186 | [使用 count 统计词条 出现次数](./md/186.md) | pandas count | v1.0 | ⭐️⭐⭐ |
-| 187 | [split 求时分(HH:mm)的分钟差](./md/187.md) | pandas split | v1.0 | ⭐️⭐⭐ |
-| 188 | [melt透视数据小技巧](./md/188.md) | pandas melt | v1.0 | ⭐️⭐⭐ |
-| 189 | [pivot 透视小技巧](./md/189.md) | pandas melt | v1.0 | ⭐️⭐⭐ |
-| 190 | [p随机读取文件的K行,生成N个](./md/190.md) | pandas sample | v1.0 | ⭐️⭐⭐ |
-| 191 | [格式化Pandas的时间列](md/191.md) | pandas apply | v1.0 | ⭐️⭐⭐⭐ |
-| 192 | [创建SQLite连接](md/192.md) | SQLite | v1.0 | ⭐️⭐⭐⭐ |
-| 193 | [json对象转python对象](md/193.md) | python json | v1.0 | ⭐️⭐⭐⭐ |
-| 194 | [python对象转json对象](md/194.md) | python json | v1.0 | ⭐️⭐⭐⭐ |
-| 195 | [发现列表前3个最大或最小数](md/195.md) | list heapq | v1.0 | ⭐️⭐⭐⭐ |
-| 196 | [使用堆排序列表为升序](md/196.md) | sort heapq | v1.0 | ⭐️⭐⭐⭐ |
-| 197 | [使用正则提取正整数和大于0的浮点数](md/197.md) | re findall | v2 | ⭐️⭐⭐⭐ |
-
-
-
-
-### Python 实战
-
-
-#### 221 自动群发邮件
-
-Python自动群发邮件
-
-```python
-import smtplib
-from email import (header)
-from email.mime import (text, application, multipart)
-import time
-
-def sender_mail():
- smt_p = smtplib.SMTP()
- smt_p.connect(host='smtp.qq.com', port=25)
- sender, password = '113097485@qq.com', "**************"
- smt_p.login(sender, password)
- receiver_addresses, count_num = [
- 'guozhennianhua@163.com', 'xiaoxiazi99@163.com'], 1
- for email_address in receiver_addresses:
- try:
- msg = multipart.MIMEMultipart()
- msg['From'] = "zhenguo"
- msg['To'] = email_address
- msg['subject'] = header.Header('这是邮件主题通知', 'utf-8')
- msg.attach(text.MIMEText(
- '这是一封测试邮件,请勿回复本邮件~', 'plain', 'utf-8'))
- smt_p.sendmail(sender, email_address, msg.as_string())
- time.sleep(10)
- print('第%d次发送给%s' % (count_num, email_address))
- count_num = count_num + 1
- except Exception as e:
- print('第%d次给%s发送邮件异常' % (count_num, email_address))
- continue
- smt_p.quit()
-
-sender_mail()
-```
-
-
-
-注意:
-发送邮箱是qq邮箱,所以要在qq邮箱中设置开启SMTP服务,设置完成时会生成一个授权码,将这个授权码赋值给文中的`password`变量
-
-#### 222 二分搜索
-
-二分搜索是程序员必备的算法,无论什么场合,都要非常熟练地写出来。
-
-小例子描述:
-在**有序数组**`arr`中,指定区间`[left,right]`范围内,查找元素`x`
-如果不存在,返回`-1`
-
-二分搜索`binarySearch`实现的主逻辑
-
-```python
-def binarySearch(arr, left, right, x):
- while left <= right:
-
- mid = int(left + (right - left) / 2); # 找到中间位置。求中点写成(left+right)/2更容易溢出,所以不建议这样写
-
- # 检查x是否出现在位置mid
- if arr[mid] == x:
- print('found %d 在索引位置%d 处' %(x,mid))
- return mid
-
- # 假如x更大,则不可能出现在左半部分
- elif arr[mid] < x:
- left = mid + 1 #搜索区间变为[mid+1,right]
- print('区间缩小为[%d,%d]' %(mid+1,right))
-
- # 同理,假如x更小,则不可能出现在右半部分
- elif x
-
-```python
-import requests
-from lxml import etree
-import pandas as pd
-import re
-
-url = 'http://www.weather.com.cn/weather1d/101010100.shtml#input'
-with requests.get(url) as res:
- content = res.content
- html = etree.HTML(content)
-```
-
-
-
-通过lxml模块提取值
-
-lxml比beautifulsoup解析在某些场合更高效
-
-```python
-location = html.xpath('//*[@id="around"]//a[@target="_blank"]/span/text()')
-temperature = html.xpath('//*[@id="around"]/div/ul/li/a/i/text()')
-```
-
-结果:
-
-```python
-['香河', '涿州', '唐山', '沧州', '天津', '廊坊', '太原', '石家庄', '涿鹿', '张家口', '保定', '三河', '北京孔庙', '北京国子监', '中国地质博物馆', '月坛公
-园', '明城墙遗址公园', '北京市规划展览馆', '什刹海', '南锣鼓巷', '天坛公园', '北海公园', '景山公园', '北京海洋馆']
-
-['11/-5°C', '14/-5°C', '12/-6°C', '12/-5°C', '11/-1°C', '11/-5°C', '8/-7°C', '13/-2°C', '8/-6°C', '5/-9°C', '14/-6°C', '11/-4°C', '13/-3°C'
-, '13/-3°C', '12/-3°C', '12/-3°C', '13/-3°C', '12/-2°C', '12/-3°C', '13/-3°C', '12/-2°C', '12/-2°C', '12/-2°C', '12/-3°C']
-```
-
-
-构造DataFrame对象
-
-```python
-df = pd.DataFrame({'location':location, 'temperature':temperature})
-print('温度列')
-print(df['temperature'])
-```
-
-正则解析温度值
-
-```python
-df['high'] = df['temperature'].apply(lambda x: int(re.match('(-?[0-9]*?)/-?[0-9]*?°C', x).group(1) ) )
-df['low'] = df['temperature'].apply(lambda x: int(re.match('-?[0-9]*?/(-?[0-9]*?)°C', x).group(1) ) )
-print(df)
-```
-
-详细说明子字符创捕获
-
-除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用`()`表示的就是要提取的分组(group)。比如:`^(\d{3})-(\d{3,8})$`分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码
-
-```python
-m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
-print(m.group(0))
-print(m.group(1))
-print(m.group(2))
-
-# 010-12345
-# 010
-# 12345
-```
-
-如果正则表达式中定义了组,就可以在`Match`对象上用`group()`方法提取出子串来。
-
-注意到`group(0)`永远是原始字符串,`group(1)`、`group(2)`……表示第1、2、……个子串。
-
-
-最终结果
-
-```kepython
-Name: temperature, dtype: object
- location temperature high low
-0 香河 11/-5°C 11 -5
-1 涿州 14/-5°C 14 -5
-2 唐山 12/-6°C 12 -6
-3 沧州 12/-5°C 12 -5
-4 天津 11/-1°C 11 -1
-5 廊坊 11/-5°C 11 -5
-6 太原 8/-7°C 8 -7
-7 石家庄 13/-2°C 13 -2
-8 涿鹿 8/-6°C 8 -6
-9 张家口 5/-9°C 5 -9
-10 保定 14/-6°C 14 -6
-11 三河 11/-4°C 11 -4
-12 北京孔庙 13/-3°C 13 -3
-13 北京国子监 13/-3°C 13 -3
-14 中国地质博物馆 12/-3°C 12 -3
-15 月坛公园 12/-3°C 12 -3
-16 明城墙遗址公园 13/-3°C 13 -3
-17 北京市规划展览馆 12/-2°C 12 -2
-18 什刹海 12/-3°C 12 -3
-19 南锣鼓巷 13/-3°C 13 -3
-20 天坛公园 12/-2°C 12 -2
-21 北海公园 12/-2°C 12 -2
-22 景山公园 12/-2°C 12 -2
-23 北京海洋馆 12/-3°C 12 -3
-```
-
-### 十、数据分析
-
-本项目基于Kaggle电影影评数据集,通过这个系列,你将学到如何进行数据探索性分析(EDA),学会使用数据分析利器`pandas`,会用绘图包`pyecharts`,以及EDA时可能遇到的各种实际问题及一些处理技巧。
-
-
-
-本项目需要导入的包:
-
-```python
-import pandas as pd
-import numpy as np
-import matplotlib.pyplot as plt
-from pyecharts.charts import Bar,Grid,Line
-import pyecharts.options as opts
-from pyecharts.globals import ThemeType
-```
-
-#### 1 创建DataFrame
-pandas中一个dataFrame实例:
-```python
-Out[89]:
- a val
-0 apple1 1.0
-1 apple2 2.0
-2 apple3 3.0
-3 apple4 4.0
-4 apple5 5.0
-```
-
-我们的**目标**是变为如下结构:
-```python
-a apple1 apple2 apple3 apple4 apple5
-0 1.0 2.0 3.0 4.0 5.0
-```
-
-乍看可使用`pivot`,但很难一步到位。
-
-所以另辟蹊径,提供一种简单且好理解的方法:
-
-```python
-In [113]: pd.DataFrame(index=[0],columns=df.a,data=dict(zip(df.a,df.val)))
-Out[113]:
-a apple1 apple2 apple3 apple4 apple5
-0 1.0 2.0 3.0 4.0 5.0
-```
-以上方法是重新创建一个DataFrame,直接把`df.a`所有可能取值作为新dataframe的列,index调整为`[0]`,注意类型必须是数组类型(array-like 或者 Index),两个轴确定后,`data`填充数据域。
-
-```python
-In [116]: dict(zip(df.a,df.val))
-Out[116]: {'apple1': 1.0, 'apple2': 2.0, 'apple3': 3.0, 'apple4': 4.0, 'apple5': 5.0}
-```
-
-
-
-#### 2 导入数据
-数据来自kaggle,共包括三个文件:
-
-1. movies.dat
-2. ratings.dat
-3. users.dat
-
-`movies.dat`包括三个字段:['Movie ID', 'Movie Title', 'Genre']
-
-使用pandas导入此文件:
-
-```python
-import pandas as pd
-
-movies = pd.read_csv('./data/movietweetings/movies.dat', delimiter='::', engine='python', header=None, names = ['Movie ID', 'Movie Title', 'Genre'])
-```
-
-导入后,显示前5行:
-
-```python
- Movie ID Movie Title \
-0 8 Edison Kinetoscopic Record of a Sneeze (1894)
-1 10 La sortie des usines Lumi猫re (1895)
-2 12 The Arrival of a Train (1896)
-3 25 The Oxford and Cambridge University Boat Race ...
-4 91 Le manoir du diable (1896)
-5 131 Une nuit terrible (1896)
-6 417 Le voyage dans la lune (1902)
-7 439 The Great Train Robbery (1903)
-8 443 Hiawatha, the Messiah of the Ojibway (1903)
-9 628 The Adventures of Dollie (1908)
- Genre
-0 Documentary|Short
-1 Documentary|Short
-2 Documentary|Short
-3 NaN
-4 Short|Horror
-5 Short|Comedy|Horror
-6 Short|Action|Adventure|Comedy|Fantasy|Sci-Fi
-7 Short|Action|Crime|Western
-8 NaN
-9 Action|Short
-```
-
-
-
-次导入其他两个数据文件
-
-`users.dat`:
-
-```python
-users = pd.read_csv('./data/movietweetings/users.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Twitter ID'])
-print(users.head())
-```
-
-结果:
-
-```python
- User ID Twitter ID
-0 1 397291295
-1 2 40501255
-2 3 417333257
-3 4 138805259
-4 5 2452094989
-5 6 391774225
-6 7 47317010
-7 8 84541461
-8 9 2445803544
-9 10 995885060
-```
-
-
-
-`rating.data`:
-
-```python
-ratings = pd.read_csv('./data/movietweetings/ratings.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Movie ID', 'Rating', 'Rating Timestamp'])
-print(ratings.head())
-```
-
-结果:
-
-```python
- User ID Movie ID Rating Rating Timestamp
-0 1 111161 10 1373234211
-1 1 117060 7 1373415231
-2 1 120755 6 1373424360
-3 1 317919 6 1373495763
-4 1 454876 10 1373621125
-5 1 790724 8 1374641320
-6 1 882977 8 1372898763
-7 1 1229238 9 1373506523
-8 1 1288558 5 1373154354
-9 1 1300854 8 1377165712
-```
-
- **read_csv 使用说明**
-
-说明,本次导入`dat`文件使用`pandas.read_csv`函数。
-
-第一个位置参数`./data/movietweetings/ratings.dat` 表示文件的相对路径
-
-第二个关键字参数:`delimiter='::'`,表示文件分隔符使用`::`
-
-后面几个关键字参数分别代表使用的引擎,文件没有表头,所以`header`为`None;`
-
-导入后dataframe的列名使用`names`关键字设置,这个参数大家可以记住,比较有用。
-
-
-
-Kaggle电影数据集第一节,我们使用数据处理利器 `pandas`, 函数`read_csv` 导入给定的三个数据文件。
-
-```python
-import pandas as pd
-
-movies = pd.read_csv('./data/movietweetings/movies.dat', delimiter='::', engine='python', header=None, names = ['Movie ID', 'Movie Title', 'Genre'])
-users = pd.read_csv('./data/movietweetings/users.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Twitter ID'])
-ratings = pd.read_csv('./data/movietweetings/ratings.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Movie ID', 'Rating', 'Rating Timestamp'])
-```
-
-用到的`read_csv`,某些重要的参数,如何使用在上一节也有所提到。下面开始数据探索分析(EDA)
-
-> 找出得分前10喜剧(comedy)
-
-
-
-#### 3 处理组合值
-
-表`movies`字段`Genre`表示电影的类型,可能有多个值,分隔符为`|`,取值也可能为`None`.
-
-针对这类字段取值,可使用Pandas中Series提供的`str`做一步转化,**注意它是向量级的**,下一步,如Python原生的`str`类似,使用`contains`判断是否含有`comedy`字符串:
-
-```python
-mask = movies.Genre.str.contains('comedy',case=False,na=False)
-```
-
-注意使用的两个参数:`case`, `na`
-
-case为 False,表示对大小写不敏感;
-na Genre列某个单元格为`NaN`时,我们使用的充填值,此处填充为`False`
-
-返回的`mask`是一维的`Series`,结构与 movies.Genre相同,取值为True 或 False.
-
-观察结果:
-
-```python
-0 False
-1 False
-2 False
-3 False
-4 False
-5 True
-6 True
-7 False
-8 False
-9 False
-Name: Genre, dtype: bool
-
-```
-
-
- #### 4 访问某列
-
-得到掩码mask后,pandas非常方便地能提取出目标记录:
-
-```python
-comedy = movies[mask]
-comdey_ids = comedy['Movie ID']
-
-```
-
-以上,在pandas中被最频率使用,不再解释。看结果`comedy_ids.head()`:
-
-```python
-5 131
-6 417
-15 2354
-18 3863
-19 4099
-20 4100
-21 4101
-22 4210
-23 4395
-25 4518
-Name: Movie ID, dtype: int64
-
-```
-
-
-
-1-4介绍`数据读入`,`处理组合值`,`索引数据`等, pandas中使用较多的函数,基于Kaggle真实电影影评数据集,最后得到所有`喜剧 ID`:
-
-```python
-5 131
-6 417
-15 2354
-18 3863
-19 4099
-20 4100
-21 4101
-22 4210
-23 4395
-25 4518
-Name: Movie ID, dtype: int64
-
-```
-
-下面继续数据探索之旅~
-
-#### 5 连接两个表
-
-拿到所有喜剧的ID后,要想找出其中平均得分最高的前10喜剧,需要关联另一张表:`ratings`:
-
-再回顾下ratings表结构:
-
-```python
- User ID Movie ID Rating Rating Timestamp
-0 1 111161 10 1373234211
-1 1 117060 7 1373415231
-2 1 120755 6 1373424360
-3 1 317919 6 1373495763
-4 1 454876 10 1373621125
-5 1 790724 8 1374641320
-6 1 882977 8 1372898763
-7 1 1229238 9 1373506523
-8 1 1288558 5 1373154354
-9 1 1300854 8 1377165712
-
-```
-
-
-pandas 中使用`join`关联两张表,连接字段是`Movie ID`,如果顺其自然这么使用`join`:
-
-```python
-combine = ratings.join(comedy, on='Movie ID', rsuffix='2')
-
-```
-
-左右滑动,查看完整代码
-
-大家可验证这种写法,仔细一看,会发现结果非常诡异。
-
-究其原因,这是pandas join函数使用的一个算是坑点,它在官档中介绍,连接右表时,此处右表是`comedy`,它的`index`要求是连接字段,也就是 `Movie ID`.
-
-左表的index不要求,但是要在参数 `on`中给定。
-
-**以上是要注意的一点**
-
-修改为:
-
-```python
-combine = ratings.join(comedy.set_index('Movie ID'), on='Movie ID')
-print(combine.head(10))
-
-```
-
-以上是OK的写法
-
-观察结果:
-
-```python
- User ID Movie ID Rating Rating Timestamp Movie Title Genre
-0 1 111161 10 1373234211 NaN NaN
-1 1 117060 7 1373415231 NaN NaN
-2 1 120755 6 1373424360 NaN NaN
-3 1 317919 6 1373495763 NaN NaN
-4 1 454876 10 1373621125 NaN NaN
-5 1 790724 8 1374641320 NaN NaN
-6 1 882977 8 1372898763 NaN NaN
-7 1 1229238 9 1373506523 NaN NaN
-8 1 1288558 5 1373154354 NaN NaN
-9 1 1300854 8 1377165712 NaN NaN
-
-```
-
-Genre列为`NaN`表明,这不是喜剧。需要筛选出此列不为`NaN` 的记录。
-
-#### 6 按列筛选
-
-pandas最方便的地方,就是向量化运算,尽可能减少了for循环的嵌套。
-
-按列筛选这种常见需求,自然可以轻松应对。
-
-为了照顾初次接触 pandas 的朋友,分两步去写:
-
-```python
-mask = pd.notnull(combine['Genre'])
-
-```
-
-结果是一列只含`True 或 False`的值
-
-```python
-result = combine[mask]
-print(result.head())
-
-```
-
-结果中,Genre字段中至少含有一个Comedy字符串,表明验证了我们以上操作是OK的。
-
-```python
- User ID Movie ID Rating Rating Timestamp Movie Title \
-12 1 1588173 9 1372821281 Warm Bodies (2013)
-13 1 1711425 3 1372604878 21 & Over (2013)
-14 1 2024432 8 1372703553 Identity Thief (2013)
-17 1 2101441 1 1372633473 Spring Breakers (2012)
-28 2 1431045 7 1457733508 Deadpool (2016)
-
- Genre
-12 Comedy|Horror|Romance
-13 Comedy
-14 Adventure|Comedy|Crime|Drama
-17 Comedy|Crime|Drama
-28 Action|Adventure|Comedy|Sci-Fi
-
-
-```
-
-
-
-截止目前已经求出所有喜剧电影`result`,前5行如下,Genre中都含有`Comedy`字符串:
-```python
- User ID Movie ID Rating Rating Timestamp Movie Title \
-12 1 1588173 9 1372821281 Warm Bodies (2013)
-13 1 1711425 3 1372604878 21 & Over (2013)
-14 1 2024432 8 1372703553 Identity Thief (2013)
-17 1 2101441 1 1372633473 Spring Breakers (2012)
-28 2 1431045 7 1457733508 Deadpool (2016)
+允许按照要求转载,但禁止用于任何商用目的。如果转载本库小例子、小案例,请备注下方链接:
- Genre
-12 Comedy|Horror|Romance
-13 Comedy
-14 Adventure|Comedy|Crime|Drama
-17 Comedy|Crime|Drama
-28 Action|Adventure|Comedy|Sci-Fi
-```
+[Python小例子所有汇总](https://ai-jupyter.com/python-small-examples/)
+### 更多教程
+[AI消息](https://ai-jupyter.com/)
-#### 7 按照Movie ID 分组
+[AI新闻报道](https://ai-jupyter.com/ai-news-all/)
-result中会有很多观众对同一部电影的打分,所以要求得分前10的喜剧,先按照`Movie ID`分组,然后求出平均值:
-```python
-score_as_movie = result.groupby('Movie ID').mean()
-```
+[AI大模型](https://ai-jupyter.com/ai-llm/)
-前5行显示如下:
-```python
- User ID Rating Rating Timestamp
-Movie ID
-131 34861.000000 7.0 1.540639e+09
-417 34121.409091 8.5 1.458680e+09
-2354 6264.000000 8.0 1.456343e+09
-3863 43803.000000 10.0 1.430439e+09
-4099 25084.500000 7.0 1.450323e+09
-```
+[AI工具集](https://ai-jupyter.com/ai-chatgpt/)
-#### 8 按照电影得分排序
+[ChatGPT4o免费使用六种方法](https://ai-jupyter.com/ai-chatgpt/)
-```python
-score_as_movie.sort_values(by='Rating', ascending = False,inplace=True)
-score_as_movie
-```
-前5行显示如下:
-```python
- User ID Rating Rating Timestamp
-Movie ID
-7134690 30110.0 10.0 1.524974e+09
-416889 1319.0 10.0 1.543320e+09
-57840 23589.0 10.0 1.396802e+09
-5693562 50266.0 10.0 1.511024e+09
-5074 43803.0 10.0 1.428352e+09
-```
-都是满分?这有点奇怪,会不会这些电影都只有几个人评分,甚至只有1个?评分样本个数太少,显然最终的平均分数不具有太强的说服力。
+[Python教程](https://ai-jupyter.com/python-packages/)
-所以,下面要进行每部电影的评分人数统计
+[数据分析教程](https://ai-jupyter.com/numpy-intro/)
-#### 9 分组后使用聚合函数
+[算法教程](https://ai-jupyter.com/algorithm-basic/)
-根据`Movie ID`分组后,使用`count`函数统计`每组个数`,只保留count列,最后得到`watchs2`:
+[AI教程](https://ai-jupyter.com/statistics/)
-```python
-watchs = result.groupby('Movie ID').agg(['count'])
-watchs2 = watchs['Rating']['count']
-```
-打印前20行:
-```python
-print(watchs2.head(20))
-```
-结果:
-```python
-Movie ID
-131 1
-417 22
-2354 1
-3863 1
-4099 2
-4100 1
-4101 1
-4210 1
-4395 1
-4518 1
-4546 2
-4936 2
-5074 1
-5571 1
-6177 1
-6414 3
-6684 1
-6689 1
-7145 1
-7162 2
-Name: count, dtype: int64
-```
-果然,竟然有这么多电影的评论数只有1次!样本个数太少,评论的平均值也就没有什么说服力。
+[Git教程](https://ai-jupyter.com/git/)
-查看`watchs2`一些重要统计量:
-```python
-watchs2.describe()
-```
-结果:
-```python
-count 10740.000000
-mean 20.192086
-std 86.251411
-min 1.000000
-25% 1.000000
-50% 2.000000
-75% 7.000000
-max 1843.000000
-Name: count, dtype: float64
-```
-共有10740部**喜剧**电影被评分,平均打分次数20次,标准差86,75%的电影样本打分次数小于7次,最小1次,最多1843次。
+[程序员](https://ai-jupyter.com/others/)
-#### 10 频率分布直方图
+[资料下载](https://ai-jupyter.com/python-20/)
-绘制评论数的频率分布直方图,便于更直观的观察电影被评论的分布情况。上面分析到,75%的电影打分次数小于7次,所以绘制打分次数小于20次的直方图:
-```python
-fig = plt.figure(figsize=(12,8))
-histn = plt.hist(watchs2[watchs2 <=19],19,histtype='step')
-plt.scatter([i+1 for i in range(len(histn[0]))],histn[0])
-```
-
-
-
-`histn`元祖表示个数和对应的被分割的区间,查看`histn[0]`:
-```python
-array([4383., 1507., 787., 541., 356., 279., 209., 163., 158.,
- 118., 114., 90., 104., 81., 80., 73., 62., 65.,
- 52.])
-```
-```python
-sum(histn[0]) # 9222
-```
-看到电影评论次数1到19次的喜剧电影9222部,共有10740部喜剧电影,大约`86%`的喜剧电影评论次数`小于20次`,有`1518`部电影评论数不小于20次。
-
-我们肯定希望挑选出被评论次数尽可能多的电影,因为难免会有水军和滥竽充数等`异常评论`行为。那么,如何准确的量化最小抽样量呢?
-
-
-
-#### 11 最小抽样量
-
-根据统计学的知识,最小抽样量和Z值、样本方差和样本误差相关,下面给出具体的求解最小样本量的计算方法。
-
-采用如下计算公式:
-
-$$ n = \frac{Z^2\sigma^2}{E^2} $$
-
-
-此处,$Z$ 值取为95%的置信度对应的Z值也就是1.96,样本误差取为均值的2.5%.
-
-根据以上公式,编写下面代码:
-
-```python
-n3 = result.groupby('Movie ID').agg(['count','mean','std'])
-n3r = n3[n3['Rating']['count']>=20]['Rating']
-```
-只计算影评超过20次,且满足最小样本量的电影。计算得到的`n3r`前5行:
-```python
- count mean std
-Movie ID
-417 22 8.500000 1.263027
-12349 68 8.485294 1.227698
-15324 20 8.350000 1.039990
-15864 51 8.431373 1.374844
-17925 44 8.636364 1.259216
-```
-进一步求出最小样本量:
-```python
-nmin = (1.96**2*n3r['std']**2) / ( (n3r['mean']*0.025)**2 )
-```
-`nmin`前5行:
-```python
-Movie ID
-417 135.712480
-12349 128.671290
-15324 95.349276
-15864 163.434005
-17925 130.668350
-```
-
-筛选出满足最小抽样量的喜剧电影:
-
-```python
-n3s = n3r[ n3r['count'] >= nmin ]
-```
-结果显示如下,因此共有`173`部电影满足最小样本抽样量。
-
-```python
-
-count mean std
-Movie ID
-53604 129 8.635659 1.230714
-57012 207 8.449275 1.537899
-70735 224 8.839286 1.190799
-75686 209 8.095694 1.358885
-88763 296 8.945946 1.026984
-... ... ... ...
-6320628 860 7.966279 1.469924
-6412452 276 7.510870 1.389529
-6662050 22 10.000000 0.000000
-6966692 907 8.673649 1.286455
-7131622 1102 7.851180 1.751500
-173 rows × 3 columns
-```
-
-#### 12 去重和连表
-
-按照平均得分从大到小排序:
-```python
-n3s_sort = n3s.sort_values(by='mean',ascending=False)
-```
-结果:
-```python
- count mean std
-Movie ID
-6662050 22 10.000000 0.000000
-4921860 48 10.000000 0.000000
-5262972 28 10.000000 0.000000
-5512872 353 9.985836 0.266123
-3863552 199 9.010050 1.163372
-... ... ... ...
-1291150 647 6.327666 1.785968
-2557490 546 6.307692 1.858434
-1478839 120 6.200000 0.728761
-2177771 485 6.150515 1.523922
-1951261 1091 6.083410 1.736127
-173 rows × 3 columns
-```
-仅靠`Movie ID`还是不知道哪些电影,连接`movies`表:
-```python
-ms = movies.drop_duplicates(subset=['Movie ID'])
-ms = ms.set_index('Movie ID')
-n3s_final = n3s_drops.join(ms,on='Movie ID')
-```
-
-#### 13 结果分析
-
-喜剧榜单前50名:
-```python
-Movie Title
-Five Minutes (2017)
-MSG 2 the Messenger (2015)
-Avengers: Age of Ultron Parody (2015)
-Be Somebody (2016)
-Bajrangi Bhaijaan (2015)
-Back to the Future (1985)
-La vita 鐚?bella (1997)
-The Intouchables (2011)
-The Sting (1973)
-Coco (2017)
-Toy Story 3 (2010)
-3 Idiots (2009)
-Green Book (2018)
-Dead Poets Society (1989)
-The Apartment (1960)
-P.K. (2014)
-The Truman Show (1998)
-Am鑼卨ie (2001)
-Inside Out (2015)
-Toy Story 4 (2019)
-Toy Story (1995)
-Finding Nemo (2003)
-Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb (1964)
-Home Alone (1990)
-Zootopia (2016)
-Up (2009)
-Monsters, Inc. (2001)
-La La Land (2016)
-Relatos salvajes (2014)
-En man som heter Ove (2015)
-Snatch (2000)
-Lock, Stock and Two Smoking Barrels (1998)
-How to Train Your Dragon 2 (2014)
-As Good as It Gets (1997)
-Guardians of the Galaxy (2014)
-The Grand Budapest Hotel (2014)
-Fantastic Mr. Fox (2009)
-Silver Linings Playbook (2012)
-Sing Street (2016)
-Deadpool (2016)
-Annie Hall (1977)
-Pride (2014)
-In Bruges (2008)
-Big Hero 6 (2014)
-Groundhog Day (1993)
-The Breakfast Club (1985)
-Little Miss Sunshine (2006)
-Deadpool 2 (2018)
-The Terminal (2004)
-```
-
-前10名评论数图:
-
-
-
-代码:
-```python
-x = n3s_final['Movie Title'][:10].tolist()[::-1]
-y = n3s_final['count'][:10].tolist()[::-1]
-bar = (
- Bar()
- .add_xaxis(x)
- .add_yaxis('评论数',y,category_gap='50%')
- .reversal_axis()
- .set_global_opts(title_opts=opts.TitleOpts(title="喜剧电影被评论次数"),
- toolbox_opts=opts.ToolboxOpts(),)
-)
-grid = (
- Grid(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
- .add(bar, grid_opts=opts.GridOpts(pos_left="30%"))
-)
-grid.render_notebook()
-```
-
-前10名得分图:
-
-
-
-代码:
-```python
-x = n3s_final['Movie Title'][:10].tolist()[::-1]
-y = n3s_final['mean'][:10].round(3).tolist()[::-1]
-bar = (
- Bar()
- .add_xaxis(x)
- .add_yaxis('平均得分',y,category_gap='50%')
- .reversal_axis()
- .set_global_opts(title_opts=opts.TitleOpts(title="喜剧电影平均得分"),
- xaxis_opts=opts.AxisOpts(min_=8.0,name='平均得分'),
- toolbox_opts=opts.ToolboxOpts(),)
-)
-grid = (
- Grid(init_opts=opts.InitOpts(theme=ThemeType.MACARONS))
- .add(bar, grid_opts=opts.GridOpts(pos_left="30%"))
-)
-grid.render_notebook()
-```
-
-
-
-#### 14 生成哑变量
-
-分类变量的数值化,是指将枚举类变量转化为indicator变量或称dummy变量。
-
-那么什么是`indicator变量`,看看如下例子,A变量解析为:`[1,0,0]`, B解析为:`[0,1,0]`, C解析为:`[0,0,1]`
-```python
-In [8]: s = pd.Series(list('ABCA'))
-In [9]: pd.get_dummies(s)
-Out[9]:
- A B C
-0 1 0 0
-1 0 1 0
-2 0 0 1
-3 1 0 0
-```
-
-如果输入的字符有4个唯一值,看到字符a被解析为[1,0,0,0],向量长度为4.
-
-```python
-In [5]: s = pd.Series(list('abaccd'))
-In [6]: pd.get_dummies(s)
-Out[6]:
- a b c d
-0 1 0 0 0
-1 0 1 0 0
-2 1 0 0 0
-3 0 0 1 0
-4 0 0 1 0
-5 0 0 0 1
-```
-
-也就是说dummy向量的长度等于输入字符串中,唯一字符的个数。
-
-#### 15 讨厌的SettingWithCopyWarning!!!
-
-Pandas 处理数据,太好用了,谁用谁知道!
-
-使用过 Pandas 的,几乎都会遇到一个警告:
-
-*SettingWithCopyWarning*
-
-非常烦人!
-
-尤其是刚接触 Pandas 的,完全不理解为什么弹出这么一串:
-
-```python
-d:\source\test\settingwithcopy.py:9: SettingWithCopyWarning:
-A value is trying to be set on a copy of a slice from a DataFrame.
-Try using .loc[row_indexer,col_indexer] = value instead
-
-See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
-```
-
-归根结底,是因为代码中出现`链式操作`...
-
-有人就问了,什么是`链式操作`?
-
-这样的:
-
-```python
-tmp = df[df.a<4]
-tmp['c'] = 200
-```
-
-先记住这个最典型的情况,即可!
-
-有的人就问了:出现这个 Warning, 需要理会它吗?
-
-如果结果不对,当然要理会;如果结果对,不care.
-
-举个例子~~
-
-```python
-import pandas as pd
-
-df = pd.DataFrame({'a':[1,3,5],'b':[4,2,7]},index=['a','b','c'])
-df.loc[df.a<4,'c'] = 100
-print(df)
-print('it\'s ok')
-
-tmp = df[df.a<4]
-tmp['c'] = 200
-print('-----tmp------')
-print(tmp)
-print('-----df-------')
-print(df)
-```
-
-输出结果:
-```python
- a b c
-a 1 4 100.0
-b 3 2 100.0
-c 5 7 NaN
-it's ok
-d:\source\test\settingwithcopy.py:9: SettingWithCopyWarning:
-A value is trying to be set on a copy of a slice from a DataFrame.
-Try using .loc[row_indexer,col_indexer] = value instead
-
-See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
- tmp['c'] = 200
------tmp------
- a b c
-a 1 4 200
-b 3 2 200
------df-------
- a b c
-a 1 4 100.0
-b 3 2 100.0
-c 5 7 NaN
-```
-
-it's ok 行后面的发生链式赋值,导致结果错误。因为 tmp 变了,df 没赋上值啊,所以必须理会。
-
-it's ok 行前的是正解。
-
-以上,链式操作尽量避免,如何避免?多使用 `.loc[row_indexer,col_indexer]`,提示告诉我们的~
-
-#### 16 NumPy 数据归一化、分布可视化
-
-仅使用 `NumPy`,下载数据,归一化,使用 `seaborn` 展示数据分布。
-
-**下载数据**
-
-```python
-import numpy as np
-
-url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
-wid = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[1])
-```
-仅提取 `iris` 数据集的第二列 `usecols = [1]`
-
-**展示数据**
-
-```python
-array([3.5, 3. , 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3. ,
- 3. , 4. , 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.6, 3.3, 3.4, 3. ,
- 3.4, 3.5, 3.4, 3.2, 3.1, 3.4, 4.1, 4.2, 3.1, 3.2, 3.5, 3.1, 3. ,
- 3.4, 3.5, 2.3, 3.2, 3.5, 3.8, 3. , 3.8, 3.2, 3.7, 3.3, 3.2, 3.2,
- 3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7, 2. , 3. , 2.2, 2.9, 2.9,
- 3.1, 3. , 2.7, 2.2, 2.5, 3.2, 2.8, 2.5, 2.8, 2.9, 3. , 2.8, 3. ,
- 2.9, 2.6, 2.4, 2.4, 2.7, 2.7, 3. , 3.4, 3.1, 2.3, 3. , 2.5, 2.6,
- 3. , 2.6, 2.3, 2.7, 3. , 2.9, 2.9, 2.5, 2.8, 3.3, 2.7, 3. , 2.9,
- 3. , 3. , 2.5, 2.9, 2.5, 3.6, 3.2, 2.7, 3. , 2.5, 2.8, 3.2, 3. ,
- 3.8, 2.6, 2.2, 3.2, 2.8, 2.8, 2.7, 3.3, 3.2, 2.8, 3. , 2.8, 3. ,
- 2.8, 3.8, 2.8, 2.8, 2.6, 3. , 3.4, 3.1, 3. , 3.1, 3.1, 3.1, 2.7,
- 3.2, 3.3, 3. , 2.5, 3. , 3.4, 3. ])
-
-```
-
-这是单变量(univariate)长度为 150 的一维 NumPy 数组。
-
-**归一化**
-
-求出最大值、最小值
-```python
-smax = np.max(wid)
-smin = np.min(wid)
-
-In [51]: smax,smin
-Out[51]: (4.4, 2.0)
-````
-归一化公式:
-```python
-s = (wid - smin) / (smax - smin)
-```
-只打印小数点后三位设置:
-```python
-np.set_printoptions(precision=3)
-```
-
-归一化结果:
-```markdown
-array([0.625, 0.417, 0.5 , 0.458, 0.667, 0.792, 0.583, 0.583, 0.375,
- 0.458, 0.708, 0.583, 0.417, 0.417, 0.833, 1. , 0.792, 0.625,
- 0.75 , 0.75 , 0.583, 0.708, 0.667, 0.542, 0.583, 0.417, 0.583,
- 0.625, 0.583, 0.5 , 0.458, 0.583, 0.875, 0.917, 0.458, 0.5 ,
- 0.625, 0.458, 0.417, 0.583, 0.625, 0.125, 0.5 , 0.625, 0.75 ,
- 0.417, 0.75 , 0.5 , 0.708, 0.542, 0.5 , 0.5 , 0.458, 0.125,
- 0.333, 0.333, 0.542, 0.167, 0.375, 0.292, 0. , 0.417, 0.083,
- 0.375, 0.375, 0.458, 0.417, 0.292, 0.083, 0.208, 0.5 , 0.333,
- 0.208, 0.333, 0.375, 0.417, 0.333, 0.417, 0.375, 0.25 , 0.167,
- 0.167, 0.292, 0.292, 0.417, 0.583, 0.458, 0.125, 0.417, 0.208,
- 0.25 , 0.417, 0.25 , 0.125, 0.292, 0.417, 0.375, 0.375, 0.208,
- 0.333, 0.542, 0.292, 0.417, 0.375, 0.417, 0.417, 0.208, 0.375,
- 0.208, 0.667, 0.5 , 0.292, 0.417, 0.208, 0.333, 0.5 , 0.417,
- 0.75 , 0.25 , 0.083, 0.5 , 0.333, 0.333, 0.292, 0.542, 0.5 ,
- 0.333, 0.417, 0.333, 0.417, 0.333, 0.75 , 0.333, 0.333, 0.25 ,
- 0.417, 0.583, 0.458, 0.417, 0.458, 0.458, 0.458, 0.292, 0.5 ,
- 0.542, 0.417, 0.208, 0.417, 0.583, 0.417])
-```
-
-**分布可视化**
-
-```python
-import seaborn as sns
-sns.distplot(s,kde=False,rug=True)
-```
-频率分布直方图:
-
-
-
-
-
-```python
-sns.distplot(s,hist=True,kde=True,rug=True)
-```
-带高斯密度核函数的直方图:
-
-
-
-
-
-**分布 fit 图**
-
-拿 `gamma` 分布去 fit :
-```python
-from scipy import stats
-sns.distplot(s, kde=False, fit = stats.gamma)
-```
-
-
-
-
-
-
-拿双 `gamma` 去 fit:
-```python
-from scipy import stats
-sns.distplot(s, kde=False, fit = stats.dgamma)
-```
-
-
-
-#### 17 Pandas 使用技巧
-
-对于动辄就几十或几百个 G 的数据,在读取的这么大数据的时候,我们有没有办法随机选取一小部分数据,然后读入内存,快速了解数据和开展 EDA ?
-
-使用 Pandas 的 skiprows 和 概率知识,就能做到。
-
-下面解释具体怎么做。
-
-如下所示,读取某 100 G 大小的 big_data.csv 数据
-
-1) 使用 skiprows 参数,
-
-2) x > 0 确保首行读入,
-
-3) np.random.rand() > 0.01 表示 99% 的数据都会被随机过滤掉
-
-言外之意,只有全部数据的 1% 才有机会选入内存中。
-
-```python
-import pandas as pd
-import numpy as np
-
-df = pd.read_csv("big_data.csv",
-skiprows =
-lambda x: x>0 and np.random.rand() > 0.01)
-
-print("The shape of the df is {}.
-It has been reduced 100 times!".format(df.shape))
-```
-
-使用这种方法,读取的数据量迅速缩减到原来的 1% ,对于迅速展开数据分析有一定的帮助。
-
-### 十一、一步一步掌握Flask web开发
-
-#### 1 Flask版 hello world
-
-Flask是Python轻量级web框架,容易上手,被广大Python开发者所喜爱。
-
-今天我们先从hello world开始,一步一步掌握Flask web开发。例子君是Flask框架的小白,接下来与读者朋友们,一起学习这个对我而言的新框架,大家多多指导。
-
-首先`pip install Flask`,安装Flask,然后import Flask,同时创建一个 `app`
-```python
-from flask import Flask
-
-App = Flask(__name__)
-```
-
-写一个index页的入口函数,返回hello world.
-
-通过装饰器:App.route('/')创建index页的路由或地址,一个`/`表示index页,也就是主页。
-
-```python
-@App.route('/')
-def index():
- return "hello world"
-```
-
-调用 `index`函数:
-```python
-if __name__ == "__main__":
- App.run(debug=True)
-```
-
-然后启动,会在console下看到如下启动信息,表明`服务启动成功`。
-```python
-* Debug mode: on
- * Restarting with stat
- * Debugger is active!
- * Debugger PIN: 663-788-611
- * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
-```
-
- 接下来,打开一个网页,相当于启动客户端,并在Url栏中输入:`http://127.0.0.1:5000/`,看到页面上答应出`hello world`,证明服务访问成功。
-
- 同时在服务端后台看到如下信息,表示处理一次来自客户端的`get`请求。
- ```python
- 27.0.0.1 - - [03/Feb/2020 21:26:50] "GET / HTTP/1.1" 200 -
- ```
-
- 以上就是flask的hello world 版
-
-#### 2 Flask之数据入库操作
-
-数据持久化就是将数据写入到数据库存储的过程。
-
-本例子使用`sqlite3`数据库。
-
-1)导入`sqlite3`,未安装前使用命令`pip install sqlite3`
-
-创建一个`py`文件:`sqlite3_started.py`,并写下第一行代码:
-```python
-import sqlite3
-```
-2)手动创建一个数据库实例`db`, 命名`test.db`
-
-3)创建与数据库实例`test.db`的连接:
-```python
-conn = sqlite3.connect("test.db")
-```
-
-4)拿到连接`conn`的cursor
-```python
-c = conn.cursor()
-```
-
-5)创建第一张表`books`
-
-共有四个字段:`id`,`sort`,`name`,`price`,类型分别为:`int`,`int`,`text`,`real`. 其中`id`为`primary key`. 主键的取值必须是唯一的(`unique`),否则会报错。
-
-
-```python
-c.execute('''CREATE TABLE books
- (id int primary key,
- sort int,
- name text,
- price real)''')
-```
-第一次执行上面语句,表`books`创建完成。当再次执行时,就会报`重复建表`的错误。需要优化脚本,检查表是否存在`IF NOT EXISTS books`,不存在再创建:
-```python
-c.execute('''CREATE TABLE IF NOT EXISTS books
- (id int primary key,
- sort int,
- name text,
- price real)''')
-```
-
-6)插入一行记录
-
-共为4个字段赋值
-
-```python
-c.execute('''INSERT INTO books VALUES
- (1,
- 1,
- 'computer science',
- 39.0)''')
-```
-
-7)一次插入多行记录
-
-先创建一个list:`books`,使用`executemany`一次插入多行。
-```python
-books = [(2, 2, 'Cook book', 68),
- (3, 2, 'Python intro', 89),
- (4, 3, 'machine learning', 59),
- ]
-
-
-c.executemany('INSERT INTO books VALUES (?, ?, ?, ?)', books)
-```
-
-8)提交
-
-提交后才会真正生效,写入到数据库
-
-```python
-conn.commit()
-```
-
-9)关闭期初建立的连接conn
-
-务必记住手动关闭,否则会出现内存泄漏
-```python
-conn.close()
-print('Done')
-```
-
-10)查看结果
-例子君使用`vs code`,在扩展库中选择:`SQLite`安装。
-
-
-
-新建一个`sq`文件:`a.sql`,内容如下:
-
-```sql
-SELECT * from books
-```
-右键`run query`,得到表`books`插入的4行记录可视化图:
-
-
-
-以上十步就是sqlite3写入数据库的主要步骤,作为Flask系列的第二篇,为后面的前端讲解打下基础。
-
-#### 3 Flask各层调用关系
-
-这篇介绍Flask和B/S模式,即浏览器/服务器模式,是接下来快速理解Flask代码的关键理论篇:**理解Views、models和渲染模板层的调用关系**。
-
-1) 发出请求
-
-当我们在浏览器地址栏中输入某个地址,按回车后,完成第一步。
-
-2) 视图层 views接收1)步发出的请求,Flask中使用解释器的方式处理这个求情,实例代码如下,它通常涉及到调用models层和模板文件层
-
-```python
-@main_blue.route('/', methods=['GET', 'POST'])
-def index():
- form = TestForm()
- print('test')
-```
-
-3) models层会负责创建数据模型,执行CRUD操作
-
-4) 模板文件层处理html模板
-
-5) 组合后返回html
-
-6) models层和html模板组合后返回给views层
-
-7)最后views层响应并渲染到浏览器页面,我们就能看到请求的页面。
-
-完整过程图如下所示:
-
-
-
-读者朋友们,如果你和例子君一样都是初学Flask编程,需要好好理解上面的过程。理解这些对于接下来的编程会有一定的理论指导,方向性指导价值。
-
-### Python 问答
-
-#### Python 如何生成二维码?
-
-
-
-
-
-## qrcode
-
-今天先来解答如何生成二维码。Python的`qrcode`包支持生成二维码。
-
-用法也很简单:
-
-```python
-import qrcode
-
-# 二维码内容
-data = "http://www.zglg.work/wp-content/uploads/2020/10/image-3.png"
-# 生成二维码
-img = qrcode.make(data=data)
-# 直接显示二维码
-img.show()
-# 保存二维码为文件
-img.save("我的微信.jpg")
-```
-
-生成的二维码如下:
-
-
-
-
-大家微信扫描后,会出现我的二维码。
+## Python 小例子
-另外,还可以设置二维码的颜色等样式:
+### 基本操作
-```python
-import qrcode
+| 小例子 | 链接 | 标签 | 版本 | 难度 |
+| ---- | ---------------------------------- | ---- | ---- | ---- |
+|1 | [常见算术运算](md/198.md)| 运算 | v1| ⭐⭐ |
+| 2 | [实现 relu](md/1.md) | max | V4.0 | ⭐️⭐️ |
+| 3 | [进制转化](md/2.md) | bin,oct,hex | V4.0 | ⭐️⭐️|
+| 4 | [整数和ASCII互转](md/3.md) | chr,ord | V1.0 | ⭐️⭐️ |
+| 5 | [元素都为真检查](md/4.md) | all | V2.0 | ⭐️⭐️⭐️ |
+| 6 | [至少一个为真检查](md/5.md) | any | V2.0 | ⭐️⭐️⭐️ |
+| 7 | [判断是真是假](md/6.md) | bool | V2.0 | ⭐️⭐️⭐️ |
+| 8 | [创建复数](md/7.md) | complex | V1.0 | ⭐️⭐️⭐️ |
+| 9 | [取商和余数](md/8.md) | divmod | V1.0 | ⭐️⭐️ |
+| 10 | [转为浮点类型](md/9.md) | float | V1.0 | ⭐️⭐️ |
+| 11 | [转为整型](md/10.md) | int | V1.0 | ⭐️ |
+| 12 | [次幂](md/11.md) | pow | V1.0 | ⭐️ |
+| 13 | [四舍五入](md/12.md) | round | V1.0 | ⭐️ |
+| 14 | [链式比较](md/13.md) | compare | V1.0 | ⭐️⭐️ |
+| 15 | [字符串转字节](md/14.md) | bytes,utf-8 | V1.0 | ⭐️⭐️ |
+| 16 | [任意对象转为字符串](md/15.md) | str | V1.0 | ⭐️⭐️ |
+| 17 | [执行字符串表示的代码](md/16.md) | compile | V1.0 | ⭐️⭐️⭐️ |
+| 18 | [计算表达式](md/17.md) | eval | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 19 | [字符串格式化](md/18.md) | format | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 20 | [交换两元素](md/23.md) | pack,unpack | V1.0 | ⭐️⭐️ |
+| 21 | [转为字典](md/29.md) | dict | V1.0 | ⭐️⭐️ |
+| 22 | [冻结集合](md/30.md) | frozenset | V1.0 | ⭐️⭐️ |
+| 23 | [转为集合类型](md/31.md) | set | V1.0 | ⭐️⭐️ |
+| 24 | [转元组](md/32.md) | tuple | V1.0 | ⭐️⭐️ |
+| 25 | [查看变量所占字节数](md/48.md) | getsizeof | V1.0 | ⭐️⭐️⭐️ |
+| 26 | [含单个元素的元组](md/154.md) | tuple | V1.0 | ⭐️⭐ |
+| 27 | [列表删除之坑](md/159.md) | list | V1.0 | ⭐️⭐ |
+| 28 | [列表快速复制之坑](md/160.md) | list | V1.0 | ⭐️⭐⭐ |
+| 29 | [发现列表前3个最大或最小数](md/195.md) | list heapq | v1.0 | ⭐️⭐⭐⭐ |
+| 30 | [字符串驻留](md/161.md) | str | V1.0 | ⭐️⭐⭐⭐⭐ |
+| 31 | [创建空集合错误](md/166.md) | set | V1.0 | ⭐️⭐ |
+| 32 | [充分认识for](md/164.md) | for | V1.0 | ⭐️⭐⭐ |
+| 33 | [认识执行时机](md/165.md) | generator | V1.0 | ⭐️⭐⭐⭐⭐ |
+
+
+### 函数和模块常见用法
-# 实例化二维码生成类
-qr = qrcode.QRCode(border=2)
-# 设置二维码数据
-data = "http://www.zglg.work/wp-content/uploads/2020/10/image-3.png"
-qr.add_data(data=data)
-# 启用二维码颜色设置
-qr.make(fit=True)
-img = qr.make_image(fill_color="orange", back_color="white")
+| 小例子 | 链接 | 标签 | 版本 | 难度 |
+| ---- | ---------------------------------- | ---- | ---- | ---- |
+| 1 | [操作函数对象](md/24.md) | operator | V2.0 | ⭐️⭐️⭐️⭐️ |
+| 2 | [创建range序列](md/55.md) | range | V1.0 | ⭐️⭐️ |
+| 3 | [生成逆序序列](md/25.md) | range | V1.0 | ⭐️⭐️ |
+| 4 | [拿来就用的排序函数](md/19.md) | sorted | V1.0 | ⭐️⭐️⭐️ |
+| 5 | [求和函数](md/20.md) | sum | V1.0 | ⭐️⭐️ |
+| 6 | [函数的五类参数使用例子](md/26.md) | variable parameter | V2.0 | ⭐️⭐️⭐️⭐️ |
+| 7 | [使用slice对象](md/27.md) | slice | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 8 | [lambda 函数](md/28.md) | lambda | V3.0 | ⭐️⭐️⭐️⭐️ |
+| 9 | [枚举对象](md/47.md) | enumerate | V1.0 | ⭐️⭐️⭐️ |
+| 10 | [过滤器filter](md/49.md) | filter | V1.5 | ⭐️⭐️⭐️ |
+| 11 | [返回对象哈希值](md/50.md) | hash | V1.0 | ⭐️⭐️ |
+| 12 | [带名字的元组](md/79.md) | namedtuple | V1.0 | ⭐️⭐️⭐️ |
+| 13 | [一行代码实现列表反转](md/70.md) | reverse | V1.0 | ⭐️⭐️ |
+| 14 | [反转字符串的两个方法](md/86.md) | reversed | V1.0 | ⭐️⭐️ |
+| 15 | [join 串联字符串](md/87.md) | join | V1.0 | ⭐️⭐️ |
+| 16 | [字符串字节长度](md/88.md) | encode | V1.0 | ⭐️⭐️ |
+| 17 | [groupby单字段分组](md/129.md) | itertools, groupby,lambda | V1.0 | ⭐️⭐️⭐️ |
+| 18 | [groupby多字段分组](md/130.md) | itemgetter,itertools,groupby | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 19 | [itemgetter和key函数](md/131.md) | operator,itemgetter,itertools | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 20 | [sum函数计算和聚合同时做](md/132.md) | sum,generator | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 21 | [默认参数设为空](md/155.md) | function | V1.0 | ⭐️⭐⭐ |
+| 22 | [各种参数使用之坑](md/158.md) | function paremeter | V1.0 | ⭐️⭐⭐ |
+| 23 | [lambda自由参数之坑](md/157.md) | lambda | V1.0 | ⭐️⭐⭐ |
+| 24 | [使用堆升序列表](md/196.md) | sort heapq | v1.0 | ⭐️⭐⭐⭐ |
+
+
+### 面向对象
+| 小例子 | 链接 | 标签 | 版本 | 难度 |
+| ---- | ---------------------------------- | ---- | ---- | ---- |
+| 1 | [所有对象之根](md/43.md) | object | V1.0 | ⭐️ |
+| 2 | [对象是否可调用](md/33.md) | callable | V2.5 | ⭐️⭐️⭐️⭐️ |
+| 3 | [ascii 展示对象](md/34.md) | `__repr__` | V2.5 | ⭐️⭐️⭐️ |
+| 4 | [类方法](md/35.md) | classmethod | V1.5 | ⭐️⭐️⭐️ |
+| 5 | [动态删除属性](md/36.md) | delattr,hasattr | V1.5 | ⭐️⭐️ |
+| 6 | [一键查看对象所有方法](md/37.md) | dir | V1.5 | ⭐️⭐️ |
+| 7 | [动态获取对象属性](md/38.md) | getattr | V1.5 | ⭐️⭐️ |
+| 8 | [对象是否有某个属性](md/39.md) | hasattr | V1.5 | ⭐️⭐️⭐️ |
+| 9 | [对象门牌号](md/40.md) | id | V1.0 | ⭐️ |
+| 10 | [实例和对象关系判断](md/41.md) | isinstance | V1.5 | ⭐️⭐️⭐️ |
+| 11 | [issubclass父子关系鉴定](md/42.md) | issubclass | V1.5 | ⭐️⭐️⭐️ |
+| 12 | [创建属性的两种方法](md/44.md) | property | V2.5 | ⭐️⭐️⭐️⭐️⭐️ |
+| 13 | [查看对象类型](md/45.md) | type | V1.0 | ⭐️ |
+| 14 | [元类使用介绍](md/46.md) | type,`__class__` | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 15 | [相同值的不可变对象](md/162.md) | mutable | V1.0 | ⭐️⭐⭐ |
+| 16 | [对象销毁顺序](md/163.md) | OOP del | V1.0 | ⭐️⭐⭐⭐ |
+| 17 | [子类继承父类的静态方法吗?](md/171.md) | staticmethod | V1.0 | ⭐️⭐⭐ |
+
+
+
+### 正则
+| 小例子 | 链接 | 标签 | 版本 | 难度 |
+| ---- | ---------------------------------- | ---- | ---- | ---- |
+| 1 | [正则中字符 `r`作用](md/89.md) | re,r | V3.0 | ⭐️⭐️⭐️ |
+| 2 | [正则原子操作](md/90.md) | re | V3.0 | ⭐️⭐️⭐️ |
+| 3 | [正则中的转义](md/91.md) | re,\ | V3.0 | ⭐️⭐️⭐️ |
+| 4 | [正则最普通查找](md/92.md) | re,findall | V3.0 | ⭐️⭐️⭐️ |
+| 5 | [使用通用字符查找](md/93.md) | re,\s,\w,\d | V3.0 | ⭐️⭐️⭐️ |
+| 6 | [使用元字符查找](md/94.md) | re,+,* | V3.0 | ⭐️⭐️⭐️ |
+| 7 | [捕获子串](md/95.md) | () | V3.0 | ⭐️⭐️⭐️⭐️ |
+| 8 | [贪心捕获和非贪心捕获](md/96.md) | re | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 9 | [使用正则做密码安全检查](md/97.md) | re | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 10 | [爬取百度首页标题](md/98.md) | re | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 11 | [批量转化为驼峰格式(Camel)](md/99.md) | re | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 12 | [使用正则判断是否为正浮点数](md/102.md) | str,re,float | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 13 | [使用正则提取正整数和大于0的浮点数](md/197.md) | re findall | v2 | ⭐️⭐⭐⭐ |
+
+### 装饰器迭代器生成器
+| 小例子 | 链接 | 标签 | 版本 | 难度 |
+| ---- | ---------------------------------- | ---- | ---- | ---- |
+| 1 | [通俗理解装饰器](md/138.md) | decorator | V1.0 | ⭐️⭐️⭐️ |
+| 2 | [测试函数运行时间的装饰器](md/136.md) | decorator | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 3 | [统计异常次数装饰器](md/137.md) | decorator,nonlocal | V1.5 | ⭐️⭐️⭐️⭐️ |
+| 4 | [定制递减迭代器](md/139.md) | Iterator | V3.0 | ⭐️⭐️⭐️⭐️ |
+| 5 | [创建迭代器](md/53.md) | iter,`__iter__` | V1.5 | ⭐️⭐️⭐️ |
+| 6 | [反向迭代器reversed](md/56.md) | reversed | V1.0 | ⭐️⭐️ |
+| 7 | [zip迭代器](md/57.md) | zip | V1.5 | ⭐️⭐️⭐️ |
+| 8 | [list分组(生成器版)](md/134.md) | yield,generator | V1.0 | ⭐️⭐️⭐️ |
+| 9 | [列表全展开(生成器版)](md/135.md) | list,yield,generator | V1.0 | ⭐️⭐️⭐️ |
+| 10 | [chain串联小容器为大容器](md/84.md) | itertools,chain | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 11 | [product 使用案例](md/85.md) | product | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 12 | [斐波那契数列前n项](md/126.md) | yield,range | V1.0 | ⭐️⭐️⭐️ |
+
+
+### 绘图
+| 小例子 | 链接 | 标签 | 版本 | 难度 |
+| ---- | ---------------------------------- | ---- | ---- | ---- |
+| 1 | [turtle绘制奥运五环图](md/140.md) | turtle | V1.0 | ⭐️⭐️⭐️ |
+| 2 | [turtle绘制漫天雪花](md/141.md) | turtle | V1.0 | ⭐️⭐️⭐️ |
+| 3 | [Python词云图](md/142.md) | WordCloud | V1.0 | ⭐️⭐️⭐ |
+| 4 | [Plotly柱状图和折线图](md/143.md) | plotly | V1.0 | ⭐️⭐ |
+| 5 | [seaborn热力图](md/144.md) | seaborn | V1.0 | ⭐️⭐ |
+| 6 | [Pyecharts仪表盘](md/145.md) | pyecharts | V1.0 | ⭐️⭐ |
+| 7 | [Pyecharts漏斗图](md/146.md) | pyecharts | V1.0 | ⭐️⭐ |
+| 8 | [Pyecharts水球图](md/147.md) | pyecharts | V1.0 | ⭐️⭐ |
+| 9 | [Pyecharts饼图](md/148.md) | pyecharts | V1.0 | ⭐️⭐ |
+| 10 | [Pyecharts极坐标图](md/149.md) | pyecharts | V1.0 | ⭐️⭐ |
+| 11 | [Pyecharts词云图](md/150.md) | pyecharts | V1.0 | ⭐️⭐ |
+| 12 | [Pyecharts热力图](md/151.md) | pyecharts | V1.0 | ⭐️⭐ |
+| 13 | [matplotlib绘制动图](md/152.md) | matplotlib | V1.0 | ⭐️⭐ |
+| 14 | [seaborn pairplot图](md/153.md) | seaborn | V1.0 | ⭐️⭐⭐⭐ |
+| 15 | [pyecharts传入Numpy数据绘图失败](md/167.md) | numpy pyecharts | V1.0 | ⭐️⭐⭐ |
+| 16 | [图像处理包pillow](md/169.md) | pillow | V1.0 | ⭐️⭐⭐ |
+
+### 数据分析
+| 小例子 | 链接 | 标签 | 版本 | 难度 |
+| ---- | ---------------------------------- | ---- | ---- | ---- |
+| 1 | [数据分析神器:deepnote](./md/177.md) | deepnote | v1.0 | ⭐️⭐⭐ |
+| 2 | [NumPy 的pad填充方法](md/172.md) | NumPy pad | V1.0 | ⭐️⭐⭐⭐ |
+| 3 | [创建下对角线为1、2、3、4的对角矩阵](md/173.md) | NumPy diag | V1.0 | ⭐️⭐⭐ |
+| 4 | [cut 数据分箱](md/174.md) | Pandas cut | v1.0 | ⭐️⭐⭐ |
+| 5 | [丢弃空值和填充空值](./md/175.md) | Pandas dropna fillna | v1.0 | ⭐️⭐⭐ |
+| 6 | [apply 方法去掉特殊字符](./md/178.md) | pandas apply | v1.0 | ⭐️⭐⭐ |
+| 7 | [使用map对列做特征工程](./md/179.md) | pandas map | v1.0 | ⭐️⭐⭐ |
+| 8 | [category列转数值](./md/180.md) | pandas category | v1.0 | ⭐️⭐⭐ |
+| 9 | [rank排名](./md/181.md) | pandas rank | v1.0 | ⭐️⭐⭐|
+| 10 | [完成数据下采样,调整步长由小时为天](./md/182.md) | pandas resample | v1.0 | ⭐️⭐⭐ |
+| 11 | [如何用 Pandas 快速生成时间序列数据](./md/183.md) | pandas util | v1.0 | ⭐️⭐⭐ |
+| 12 | [如何快速找出 DataFrame 所有列 null 值个数](./md/184.md) | pandas isnull sum | v1.0 | ⭐️⭐⭐ |
+| 13 | [重新排序 DataFrame 的列](./md/185.md) | pandas dataframe | v1.0 | ⭐️⭐⭐ |
+| 14 | [使用 count 统计词条 出现次数](./md/186.md) | pandas count | v1.0 | ⭐️⭐⭐ |
+| 15 | [split 求时分(HH:mm)的分钟差](./md/187.md) | pandas split | v1.0 | ⭐️⭐⭐ |
+| 16 | [melt透视数据小技巧](./md/188.md) | pandas melt | v1.0 | ⭐️⭐⭐ |
+| 17 | [pivot 透视小技巧](./md/189.md) | pandas melt | v1.0 | ⭐️⭐⭐ |
+| 18 | [p随机读取文件的K行,生成N个](./md/190.md) | pandas sample | v1.0 | ⭐️⭐⭐ |
+| 19 | [格式化Pandas的时间列](md/191.md) | pandas apply | v1.0 | ⭐️⭐⭐⭐ |
+
+### 其他常用
+| 小例子 | 链接 | 标签 | 版本 | 难度 |
+| ---- | ---------------------------------- | ---- | ---- | ---- |
+| 1 | [help 一键帮助](md/51.md) | help | V1.0 | ⭐️ |
+| 2 | [获取用户输入](md/52.md) | input | V1.0 | ⭐️ |
+| 3 | [文件读写和mode 取值表](md/54.md) | open,read,write,with,mode | V2.0 | ⭐️⭐️⭐️ |
+| 4 | [operator使用举例](md/58.md) | operator | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 5 | [传输json对象](md/59.md) | json | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 6 | [获取文件后缀名](md/103.md) | os,splitext | V1.0 | ⭐️⭐️ |
+| 7 | [获取路径中的文件名](md/104.md) | os,split | V1.0 | ⭐️⭐️ |
+| 8 | [批量修改文件后缀](md/105.md) | argparse,listdir | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 9 | [xls批量转换成xlsx](md/106.md) | os,listdir,splitext | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 10 | [获取指定后缀名的文件](md/107.md) | os,listdir,splitext | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 11 | [批量压缩文件](md/108.md) | zipfile | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 12 | [32位加密](md/109.md) | hashlib | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 13 | [年的日历图](md/110.md) | calendar | V1.0 | ⭐️⭐️ |
+| 14 | [判断是否为闰年](md/111.md) | calendar | V1.0 | ⭐️⭐️⭐️ |
+| 15 | [判断月有几天](md/112.md) | calendar,datetime | V1.0 | ⭐️⭐️⭐️ |
+| 16 | [月的第一天](md/113.md) | datetime | V1.0 | ⭐️⭐️ |
+| 17 | [月的最后一天](md/114.md) | calendar,datetime | V1.0 | ⭐️⭐️ |
+| 18 | [获取当前时间](md/115.md) | time,datetime | V1.0 | ⭐️⭐️ |
+| 19 | [字符时间转时间](md/116.md) | time,datetime | V1.0 | ⭐️⭐️ |
+| 20 | [时间转字符时间](md/117.md) | time,datetime | V1.0 | ⭐️⭐️ |
+| 21 | [获得某天后的1~n天](md/133.md) | Calendar,monthrange | V4.0 | ⭐️⭐️⭐️ |
+| 22 | [默认启动主线程](md/118.md) | threading | V1.0 | ⭐️⭐️ |
+| 23 | [创建线程](md/119.md) | threading | V1.0 | ⭐️⭐️ |
+| 24 | [交替获得CPU时间片](md/120.md) | threading | V1.0 | ⭐️⭐️⭐️ |
+| 25 | [多线程抢夺同一个变量](md/121.md) | threading | V1.0 | ⭐️⭐️⭐️ |
+| 26 | [多线程变量竞争引起的问题](md/122.md) | threading | V1.0 | ⭐️⭐️⭐️ |
+| 27 | [多线程锁](md/123.md) | threading,lock | V1.0 | ⭐️⭐️⭐️ |
+| 28 | [时间转数组及常用格式](md/124.md) | time,datetime,format | V1.0 | ⭐️⭐️⭐️ |
+| 29 | [nonlocal用于内嵌函数中](md/21.md) | nonlocal | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 30 | [global 声明全局变量](md/22.md) | global | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 31 | [共享变量未绑定之坑](md/156.md) | global | V1.0 | ⭐️⭐⭐ |
+| 32 | [优化代码异常输出包](md/168.md) | debugger | V1.0 | ⭐️⭐⭐ |
+| 33 | [一行代码找到编码](md/170.md) | chardet | V1.0 | ⭐️⭐⭐ |
+| 34 | [创建SQLite连接](md/192.md) | SQLite | v1.0 | ⭐️⭐⭐⭐ |
+| 35 | [json对象转python对象](md/193.md) | python json | v1.0 | ⭐️⭐⭐⭐ |
+| 36 | [python对象转json对象](md/194.md) | python json | v1.0 | ⭐️⭐⭐⭐ |
+| 37 | [一行代码让 pip 安装加速 100 倍](md/176.md) | pip install | v1.0 | ⭐️⭐⭐ |
+
+
+### 工作常用案例
+| 小例子 | 链接 | 标签 | 版本 | 难度 |
+| ---- | ---------------------------------- | ---- | ---- | ---- |
+| 1 | [不用else和if实现计算器](md/60.md) | operator | V1.0 | ⭐️⭐️⭐️ |
+| 2 | [去最求平均](md/61.md) | list,sort,round | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 3 | [打印99乘法表](md/62.md) | for,range,format | V1.0 | ⭐️⭐️⭐️ |
+| 4 | [递归版flatten函数](md/63.md) | recursion,list,isinstance | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 5 | [列表等分为n份](md/64.md) | list,ceil | V1.0 | ⭐️⭐️⭐️ |
+| 6 | [压缩列表](md/65.md) | list,filter | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 7 | [求更长的列表](md/66.md) | max,lambda | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 8 | [求列表众数](md/67.md) | max,lambda,count | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 9 | [所有多个列表的最大值](md/68.md) | max,lambda | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 10 | [列表检查重复](md/69.md) | set | V1.0 | ⭐️⭐️⭐️ |
+| 11 | [浮点数等差数列](md/71.md) | range,float | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 12 | [按条件分组](md/72.md) | lambda | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 13 | [map实现向量运算](md/73.md) | map,lambda | V1.0 | ⭐️⭐️⭐️ |
+| 14 | [值最大的字典](md/74.md) | max,lambda | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 15 | [合并两个字典](md/75.md) | ** | V1.0 | ⭐️⭐️⭐️ |
+| 16 | [Topn 字典](md/76.md) | heapq,nlargest | V1.0 | ⭐️⭐️⭐️ |
+| 17 | [判断是否为异位词](md/77.md) | collections,Counter | V1.0 | ⭐️⭐️⭐️ |
+| 18 | [逻辑上合并字典](md/78.md) | ChainMap | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 19 | [sample 样本抽样](md/80.md) | random,sample | V1.0 | ⭐️⭐️⭐️ |
+| 20 | [重洗数据集](md/81.md) | shuffle | V1.0 | ⭐️⭐️⭐️ |
+| 21 | [10个均匀分布的坐标点](md/82.md) | random,uniform | V1.0 | ⭐️⭐️⭐️ |
+| 22 | [10个高斯分布的坐标点](md/83.md) | random,gauss | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 23 | [是否互为排序词](md/100.md) | collections,defaultdict | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 24 | [str1是否由str2旋转而来](md/101.md) | str | V1.0 | ⭐️⭐️⭐️ |
+| 25 | [寻找第n次出现位置](md/125.md) | enumerator | V1.0 | ⭐️⭐️⭐️ |
+| 26 | [找出所有重复元素](md/127.md) | calendar,datetime | V1.0 | ⭐️⭐️⭐️⭐️ |
+| 27 | [联合统计次数](md/128.md) | Counter | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 28 | [求两点球面距离](md/199.md) | math asin | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 29 | [获取文件编码](md/200.md) | chardet | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
+| 30 | [格式化json串](md/201.md) | json | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |
-# 显示二维码
-img.show()
-```
-生成一个orange的二维码:
-
-更多样式,大家可以自己去玩耍。
diff --git a/dev/python-dev.md b/dev/python-dev.md
new file mode 100644
index 00000000..1c5c04b8
--- /dev/null
+++ b/dev/python-dev.md
@@ -0,0 +1,1481 @@
+### Python 实战
+
+
+#### 221 自动群发邮件
+
+Python自动群发邮件
+
+```python
+import smtplib
+from email import (header)
+from email.mime import (text, application, multipart)
+import time
+
+def sender_mail():
+ smt_p = smtplib.SMTP()
+ smt_p.connect(host='smtp.qq.com', port=25)
+ sender, password = '113097485@qq.com', "**************"
+ smt_p.login(sender, password)
+ receiver_addresses, count_num = [
+ 'guozhennianhua@163.com', 'xiaoxiazi99@163.com'], 1
+ for email_address in receiver_addresses:
+ try:
+ msg = multipart.MIMEMultipart()
+ msg['From'] = "zhenguo"
+ msg['To'] = email_address
+ msg['subject'] = header.Header('这是邮件主题通知', 'utf-8')
+ msg.attach(text.MIMEText(
+ '这是一封测试邮件,请勿回复本邮件~', 'plain', 'utf-8'))
+ smt_p.sendmail(sender, email_address, msg.as_string())
+ time.sleep(10)
+ print('第%d次发送给%s' % (count_num, email_address))
+ count_num = count_num + 1
+ except Exception as e:
+ print('第%d次给%s发送邮件异常' % (count_num, email_address))
+ continue
+ smt_p.quit()
+
+sender_mail()
+```
+
+
+
+注意:
+发送邮箱是qq邮箱,所以要在qq邮箱中设置开启SMTP服务,设置完成时会生成一个授权码,将这个授权码赋值给文中的`password`变量
+
+#### 222 二分搜索
+
+二分搜索是程序员必备的算法,无论什么场合,都要非常熟练地写出来。
+
+小例子描述:
+在**有序数组**`arr`中,指定区间`[left,right]`范围内,查找元素`x`
+如果不存在,返回`-1`
+
+二分搜索`binarySearch`实现的主逻辑
+
+```python
+def binarySearch(arr, left, right, x):
+ while left <= right:
+
+ mid = int(left + (right - left) / 2); # 找到中间位置。求中点写成(left+right)/2更容易溢出,所以不建议这样写
+
+ # 检查x是否出现在位置mid
+ if arr[mid] == x:
+ print('found %d 在索引位置%d 处' %(x,mid))
+ return mid
+
+ # 假如x更大,则不可能出现在左半部分
+ elif arr[mid] < x:
+ left = mid + 1 #搜索区间变为[mid+1,right]
+ print('区间缩小为[%d,%d]' %(mid+1,right))
+
+ # 同理,假如x更小,则不可能出现在右半部分
+ elif x
+
+```python
+import requests
+from lxml import etree
+import pandas as pd
+import re
+
+url = 'http://www.weather.com.cn/weather1d/101010100.shtml#input'
+with requests.get(url) as res:
+ content = res.content
+ html = etree.HTML(content)
+```
+
+
+
+通过lxml模块提取值
+
+lxml比beautifulsoup解析在某些场合更高效
+
+```python
+location = html.xpath('//*[@id="around"]//a[@target="_blank"]/span/text()')
+temperature = html.xpath('//*[@id="around"]/div/ul/li/a/i/text()')
+```
+
+结果:
+
+```python
+['香河', '涿州', '唐山', '沧州', '天津', '廊坊', '太原', '石家庄', '涿鹿', '张家口', '保定', '三河', '北京孔庙', '北京国子监', '中国地质博物馆', '月坛公
+园', '明城墙遗址公园', '北京市规划展览馆', '什刹海', '南锣鼓巷', '天坛公园', '北海公园', '景山公园', '北京海洋馆']
+
+['11/-5°C', '14/-5°C', '12/-6°C', '12/-5°C', '11/-1°C', '11/-5°C', '8/-7°C', '13/-2°C', '8/-6°C', '5/-9°C', '14/-6°C', '11/-4°C', '13/-3°C'
+, '13/-3°C', '12/-3°C', '12/-3°C', '13/-3°C', '12/-2°C', '12/-3°C', '13/-3°C', '12/-2°C', '12/-2°C', '12/-2°C', '12/-3°C']
+```
+
+
+构造DataFrame对象
+
+```python
+df = pd.DataFrame({'location':location, 'temperature':temperature})
+print('温度列')
+print(df['temperature'])
+```
+
+正则解析温度值
+
+```python
+df['high'] = df['temperature'].apply(lambda x: int(re.match('(-?[0-9]*?)/-?[0-9]*?°C', x).group(1) ) )
+df['low'] = df['temperature'].apply(lambda x: int(re.match('-?[0-9]*?/(-?[0-9]*?)°C', x).group(1) ) )
+print(df)
+```
+
+详细说明子字符创捕获
+
+除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用`()`表示的就是要提取的分组(group)。比如:`^(\d{3})-(\d{3,8})$`分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码
+
+```python
+m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
+print(m.group(0))
+print(m.group(1))
+print(m.group(2))
+
+# 010-12345
+# 010
+# 12345
+```
+
+如果正则表达式中定义了组,就可以在`Match`对象上用`group()`方法提取出子串来。
+
+注意到`group(0)`永远是原始字符串,`group(1)`、`group(2)`……表示第1、2、……个子串。
+
+
+最终结果
+
+```kepython
+Name: temperature, dtype: object
+ location temperature high low
+0 香河 11/-5°C 11 -5
+1 涿州 14/-5°C 14 -5
+2 唐山 12/-6°C 12 -6
+3 沧州 12/-5°C 12 -5
+4 天津 11/-1°C 11 -1
+5 廊坊 11/-5°C 11 -5
+6 太原 8/-7°C 8 -7
+7 石家庄 13/-2°C 13 -2
+8 涿鹿 8/-6°C 8 -6
+9 张家口 5/-9°C 5 -9
+10 保定 14/-6°C 14 -6
+11 三河 11/-4°C 11 -4
+12 北京孔庙 13/-3°C 13 -3
+13 北京国子监 13/-3°C 13 -3
+14 中国地质博物馆 12/-3°C 12 -3
+15 月坛公园 12/-3°C 12 -3
+16 明城墙遗址公园 13/-3°C 13 -3
+17 北京市规划展览馆 12/-2°C 12 -2
+18 什刹海 12/-3°C 12 -3
+19 南锣鼓巷 13/-3°C 13 -3
+20 天坛公园 12/-2°C 12 -2
+21 北海公园 12/-2°C 12 -2
+22 景山公园 12/-2°C 12 -2
+23 北京海洋馆 12/-3°C 12 -3
+```
+
+### 十、数据分析
+
+本项目基于Kaggle电影影评数据集,通过这个系列,你将学到如何进行数据探索性分析(EDA),学会使用数据分析利器`pandas`,会用绘图包`pyecharts`,以及EDA时可能遇到的各种实际问题及一些处理技巧。
+
+
+
+本项目需要导入的包:
+
+```python
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+from pyecharts.charts import Bar,Grid,Line
+import pyecharts.options as opts
+from pyecharts.globals import ThemeType
+```
+
+#### 1 创建DataFrame
+pandas中一个dataFrame实例:
+```python
+Out[89]:
+ a val
+0 apple1 1.0
+1 apple2 2.0
+2 apple3 3.0
+3 apple4 4.0
+4 apple5 5.0
+```
+
+我们的**目标**是变为如下结构:
+```python
+a apple1 apple2 apple3 apple4 apple5
+0 1.0 2.0 3.0 4.0 5.0
+```
+
+乍看可使用`pivot`,但很难一步到位。
+
+所以另辟蹊径,提供一种简单且好理解的方法:
+
+```python
+In [113]: pd.DataFrame(index=[0],columns=df.a,data=dict(zip(df.a,df.val)))
+Out[113]:
+a apple1 apple2 apple3 apple4 apple5
+0 1.0 2.0 3.0 4.0 5.0
+```
+以上方法是重新创建一个DataFrame,直接把`df.a`所有可能取值作为新dataframe的列,index调整为`[0]`,注意类型必须是数组类型(array-like 或者 Index),两个轴确定后,`data`填充数据域。
+
+```python
+In [116]: dict(zip(df.a,df.val))
+Out[116]: {'apple1': 1.0, 'apple2': 2.0, 'apple3': 3.0, 'apple4': 4.0, 'apple5': 5.0}
+```
+
+
+
+#### 2 导入数据
+数据来自kaggle,共包括三个文件:
+
+1. movies.dat
+2. ratings.dat
+3. users.dat
+
+`movies.dat`包括三个字段:['Movie ID', 'Movie Title', 'Genre']
+
+使用pandas导入此文件:
+
+```python
+import pandas as pd
+
+movies = pd.read_csv('./data/movietweetings/movies.dat', delimiter='::', engine='python', header=None, names = ['Movie ID', 'Movie Title', 'Genre'])
+```
+
+导入后,显示前5行:
+
+```python
+ Movie ID Movie Title \
+0 8 Edison Kinetoscopic Record of a Sneeze (1894)
+1 10 La sortie des usines Lumi猫re (1895)
+2 12 The Arrival of a Train (1896)
+3 25 The Oxford and Cambridge University Boat Race ...
+4 91 Le manoir du diable (1896)
+5 131 Une nuit terrible (1896)
+6 417 Le voyage dans la lune (1902)
+7 439 The Great Train Robbery (1903)
+8 443 Hiawatha, the Messiah of the Ojibway (1903)
+9 628 The Adventures of Dollie (1908)
+ Genre
+0 Documentary|Short
+1 Documentary|Short
+2 Documentary|Short
+3 NaN
+4 Short|Horror
+5 Short|Comedy|Horror
+6 Short|Action|Adventure|Comedy|Fantasy|Sci-Fi
+7 Short|Action|Crime|Western
+8 NaN
+9 Action|Short
+```
+
+
+
+次导入其他两个数据文件
+
+`users.dat`:
+
+```python
+users = pd.read_csv('./data/movietweetings/users.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Twitter ID'])
+print(users.head())
+```
+
+结果:
+
+```python
+ User ID Twitter ID
+0 1 397291295
+1 2 40501255
+2 3 417333257
+3 4 138805259
+4 5 2452094989
+5 6 391774225
+6 7 47317010
+7 8 84541461
+8 9 2445803544
+9 10 995885060
+```
+
+
+
+`rating.data`:
+
+```python
+ratings = pd.read_csv('./data/movietweetings/ratings.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Movie ID', 'Rating', 'Rating Timestamp'])
+print(ratings.head())
+```
+
+结果:
+
+```python
+ User ID Movie ID Rating Rating Timestamp
+0 1 111161 10 1373234211
+1 1 117060 7 1373415231
+2 1 120755 6 1373424360
+3 1 317919 6 1373495763
+4 1 454876 10 1373621125
+5 1 790724 8 1374641320
+6 1 882977 8 1372898763
+7 1 1229238 9 1373506523
+8 1 1288558 5 1373154354
+9 1 1300854 8 1377165712
+```
+
+ **read_csv 使用说明**
+
+说明,本次导入`dat`文件使用`pandas.read_csv`函数。
+
+第一个位置参数`./data/movietweetings/ratings.dat` 表示文件的相对路径
+
+第二个关键字参数:`delimiter='::'`,表示文件分隔符使用`::`
+
+后面几个关键字参数分别代表使用的引擎,文件没有表头,所以`header`为`None;`
+
+导入后dataframe的列名使用`names`关键字设置,这个参数大家可以记住,比较有用。
+
+
+
+Kaggle电影数据集第一节,我们使用数据处理利器 `pandas`, 函数`read_csv` 导入给定的三个数据文件。
+
+```python
+import pandas as pd
+
+movies = pd.read_csv('./data/movietweetings/movies.dat', delimiter='::', engine='python', header=None, names = ['Movie ID', 'Movie Title', 'Genre'])
+users = pd.read_csv('./data/movietweetings/users.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Twitter ID'])
+ratings = pd.read_csv('./data/movietweetings/ratings.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Movie ID', 'Rating', 'Rating Timestamp'])
+```
+
+用到的`read_csv`,某些重要的参数,如何使用在上一节也有所提到。下面开始数据探索分析(EDA)
+
+> 找出得分前10喜剧(comedy)
+
+
+
+#### 3 处理组合值
+
+表`movies`字段`Genre`表示电影的类型,可能有多个值,分隔符为`|`,取值也可能为`None`.
+
+针对这类字段取值,可使用Pandas中Series提供的`str`做一步转化,**注意它是向量级的**,下一步,如Python原生的`str`类似,使用`contains`判断是否含有`comedy`字符串:
+
+```python
+mask = movies.Genre.str.contains('comedy',case=False,na=False)
+```
+
+注意使用的两个参数:`case`, `na`
+
+case为 False,表示对大小写不敏感;
+na Genre列某个单元格为`NaN`时,我们使用的充填值,此处填充为`False`
+
+返回的`mask`是一维的`Series`,结构与 movies.Genre相同,取值为True 或 False.
+
+观察结果:
+
+```python
+0 False
+1 False
+2 False
+3 False
+4 False
+5 True
+6 True
+7 False
+8 False
+9 False
+Name: Genre, dtype: bool
+
+```
+
+
+ #### 4 访问某列
+
+得到掩码mask后,pandas非常方便地能提取出目标记录:
+
+```python
+comedy = movies[mask]
+comdey_ids = comedy['Movie ID']
+
+```
+
+以上,在pandas中被最频率使用,不再解释。看结果`comedy_ids.head()`:
+
+```python
+5 131
+6 417
+15 2354
+18 3863
+19 4099
+20 4100
+21 4101
+22 4210
+23 4395
+25 4518
+Name: Movie ID, dtype: int64
+
+```
+
+
+
+1-4介绍`数据读入`,`处理组合值`,`索引数据`等, pandas中使用较多的函数,基于Kaggle真实电影影评数据集,最后得到所有`喜剧 ID`:
+
+```python
+5 131
+6 417
+15 2354
+18 3863
+19 4099
+20 4100
+21 4101
+22 4210
+23 4395
+25 4518
+Name: Movie ID, dtype: int64
+
+```
+
+下面继续数据探索之旅~
+
+#### 5 连接两个表
+
+拿到所有喜剧的ID后,要想找出其中平均得分最高的前10喜剧,需要关联另一张表:`ratings`:
+
+再回顾下ratings表结构:
+
+```python
+ User ID Movie ID Rating Rating Timestamp
+0 1 111161 10 1373234211
+1 1 117060 7 1373415231
+2 1 120755 6 1373424360
+3 1 317919 6 1373495763
+4 1 454876 10 1373621125
+5 1 790724 8 1374641320
+6 1 882977 8 1372898763
+7 1 1229238 9 1373506523
+8 1 1288558 5 1373154354
+9 1 1300854 8 1377165712
+
+```
+
+
+pandas 中使用`join`关联两张表,连接字段是`Movie ID`,如果顺其自然这么使用`join`:
+
+```python
+combine = ratings.join(comedy, on='Movie ID', rsuffix='2')
+
+```
+
+左右滑动,查看完整代码
+
+大家可验证这种写法,仔细一看,会发现结果非常诡异。
+
+究其原因,这是pandas join函数使用的一个算是坑点,它在官档中介绍,连接右表时,此处右表是`comedy`,它的`index`要求是连接字段,也就是 `Movie ID`.
+
+左表的index不要求,但是要在参数 `on`中给定。
+
+**以上是要注意的一点**
+
+修改为:
+
+```python
+combine = ratings.join(comedy.set_index('Movie ID'), on='Movie ID')
+print(combine.head(10))
+
+```
+
+以上是OK的写法
+
+观察结果:
+
+```python
+ User ID Movie ID Rating Rating Timestamp Movie Title Genre
+0 1 111161 10 1373234211 NaN NaN
+1 1 117060 7 1373415231 NaN NaN
+2 1 120755 6 1373424360 NaN NaN
+3 1 317919 6 1373495763 NaN NaN
+4 1 454876 10 1373621125 NaN NaN
+5 1 790724 8 1374641320 NaN NaN
+6 1 882977 8 1372898763 NaN NaN
+7 1 1229238 9 1373506523 NaN NaN
+8 1 1288558 5 1373154354 NaN NaN
+9 1 1300854 8 1377165712 NaN NaN
+
+```
+
+Genre列为`NaN`表明,这不是喜剧。需要筛选出此列不为`NaN` 的记录。
+
+#### 6 按列筛选
+
+pandas最方便的地方,就是向量化运算,尽可能减少了for循环的嵌套。
+
+按列筛选这种常见需求,自然可以轻松应对。
+
+为了照顾初次接触 pandas 的朋友,分两步去写:
+
+```python
+mask = pd.notnull(combine['Genre'])
+
+```
+
+结果是一列只含`True 或 False`的值
+
+```python
+result = combine[mask]
+print(result.head())
+
+```
+
+结果中,Genre字段中至少含有一个Comedy字符串,表明验证了我们以上操作是OK的。
+
+```python
+ User ID Movie ID Rating Rating Timestamp Movie Title \
+12 1 1588173 9 1372821281 Warm Bodies (2013)
+13 1 1711425 3 1372604878 21 & Over (2013)
+14 1 2024432 8 1372703553 Identity Thief (2013)
+17 1 2101441 1 1372633473 Spring Breakers (2012)
+28 2 1431045 7 1457733508 Deadpool (2016)
+
+ Genre
+12 Comedy|Horror|Romance
+13 Comedy
+14 Adventure|Comedy|Crime|Drama
+17 Comedy|Crime|Drama
+28 Action|Adventure|Comedy|Sci-Fi
+
+
+```
+
+
+
+截止目前已经求出所有喜剧电影`result`,前5行如下,Genre中都含有`Comedy`字符串:
+```python
+ User ID Movie ID Rating Rating Timestamp Movie Title \
+12 1 1588173 9 1372821281 Warm Bodies (2013)
+13 1 1711425 3 1372604878 21 & Over (2013)
+14 1 2024432 8 1372703553 Identity Thief (2013)
+17 1 2101441 1 1372633473 Spring Breakers (2012)
+28 2 1431045 7 1457733508 Deadpool (2016)
+
+ Genre
+12 Comedy|Horror|Romance
+13 Comedy
+14 Adventure|Comedy|Crime|Drama
+17 Comedy|Crime|Drama
+28 Action|Adventure|Comedy|Sci-Fi
+```
+
+
+
+#### 7 按照Movie ID 分组
+
+result中会有很多观众对同一部电影的打分,所以要求得分前10的喜剧,先按照`Movie ID`分组,然后求出平均值:
+```python
+score_as_movie = result.groupby('Movie ID').mean()
+```
+
+前5行显示如下:
+```python
+ User ID Rating Rating Timestamp
+Movie ID
+131 34861.000000 7.0 1.540639e+09
+417 34121.409091 8.5 1.458680e+09
+2354 6264.000000 8.0 1.456343e+09
+3863 43803.000000 10.0 1.430439e+09
+4099 25084.500000 7.0 1.450323e+09
+```
+
+#### 8 按照电影得分排序
+
+```python
+score_as_movie.sort_values(by='Rating', ascending = False,inplace=True)
+score_as_movie
+```
+前5行显示如下:
+```python
+ User ID Rating Rating Timestamp
+Movie ID
+7134690 30110.0 10.0 1.524974e+09
+416889 1319.0 10.0 1.543320e+09
+57840 23589.0 10.0 1.396802e+09
+5693562 50266.0 10.0 1.511024e+09
+5074 43803.0 10.0 1.428352e+09
+```
+都是满分?这有点奇怪,会不会这些电影都只有几个人评分,甚至只有1个?评分样本个数太少,显然最终的平均分数不具有太强的说服力。
+
+所以,下面要进行每部电影的评分人数统计
+
+#### 9 分组后使用聚合函数
+
+根据`Movie ID`分组后,使用`count`函数统计`每组个数`,只保留count列,最后得到`watchs2`:
+
+```python
+watchs = result.groupby('Movie ID').agg(['count'])
+watchs2 = watchs['Rating']['count']
+```
+打印前20行:
+```python
+print(watchs2.head(20))
+```
+结果:
+```python
+Movie ID
+131 1
+417 22
+2354 1
+3863 1
+4099 2
+4100 1
+4101 1
+4210 1
+4395 1
+4518 1
+4546 2
+4936 2
+5074 1
+5571 1
+6177 1
+6414 3
+6684 1
+6689 1
+7145 1
+7162 2
+Name: count, dtype: int64
+```
+果然,竟然有这么多电影的评论数只有1次!样本个数太少,评论的平均值也就没有什么说服力。
+
+查看`watchs2`一些重要统计量:
+```python
+watchs2.describe()
+```
+结果:
+```python
+count 10740.000000
+mean 20.192086
+std 86.251411
+min 1.000000
+25% 1.000000
+50% 2.000000
+75% 7.000000
+max 1843.000000
+Name: count, dtype: float64
+```
+共有10740部**喜剧**电影被评分,平均打分次数20次,标准差86,75%的电影样本打分次数小于7次,最小1次,最多1843次。
+
+#### 10 频率分布直方图
+
+绘制评论数的频率分布直方图,便于更直观的观察电影被评论的分布情况。上面分析到,75%的电影打分次数小于7次,所以绘制打分次数小于20次的直方图:
+
+```python
+fig = plt.figure(figsize=(12,8))
+histn = plt.hist(watchs2[watchs2 <=19],19,histtype='step')
+plt.scatter([i+1 for i in range(len(histn[0]))],histn[0])
+```
+
+
+
+`histn`元祖表示个数和对应的被分割的区间,查看`histn[0]`:
+```python
+array([4383., 1507., 787., 541., 356., 279., 209., 163., 158.,
+ 118., 114., 90., 104., 81., 80., 73., 62., 65.,
+ 52.])
+```
+```python
+sum(histn[0]) # 9222
+```
+看到电影评论次数1到19次的喜剧电影9222部,共有10740部喜剧电影,大约`86%`的喜剧电影评论次数`小于20次`,有`1518`部电影评论数不小于20次。
+
+我们肯定希望挑选出被评论次数尽可能多的电影,因为难免会有水军和滥竽充数等`异常评论`行为。那么,如何准确的量化最小抽样量呢?
+
+
+
+#### 11 最小抽样量
+
+根据统计学的知识,最小抽样量和Z值、样本方差和样本误差相关,下面给出具体的求解最小样本量的计算方法。
+
+采用如下计算公式:
+
+$$ n = \frac{Z^2\sigma^2}{E^2} $$
+
+
+此处,$Z$ 值取为95%的置信度对应的Z值也就是1.96,样本误差取为均值的2.5%.
+
+根据以上公式,编写下面代码:
+
+```python
+n3 = result.groupby('Movie ID').agg(['count','mean','std'])
+n3r = n3[n3['Rating']['count']>=20]['Rating']
+```
+只计算影评超过20次,且满足最小样本量的电影。计算得到的`n3r`前5行:
+```python
+ count mean std
+Movie ID
+417 22 8.500000 1.263027
+12349 68 8.485294 1.227698
+15324 20 8.350000 1.039990
+15864 51 8.431373 1.374844
+17925 44 8.636364 1.259216
+```
+进一步求出最小样本量:
+```python
+nmin = (1.96**2*n3r['std']**2) / ( (n3r['mean']*0.025)**2 )
+```
+`nmin`前5行:
+```python
+Movie ID
+417 135.712480
+12349 128.671290
+15324 95.349276
+15864 163.434005
+17925 130.668350
+```
+
+筛选出满足最小抽样量的喜剧电影:
+
+```python
+n3s = n3r[ n3r['count'] >= nmin ]
+```
+结果显示如下,因此共有`173`部电影满足最小样本抽样量。
+
+```python
+
+count mean std
+Movie ID
+53604 129 8.635659 1.230714
+57012 207 8.449275 1.537899
+70735 224 8.839286 1.190799
+75686 209 8.095694 1.358885
+88763 296 8.945946 1.026984
+... ... ... ...
+6320628 860 7.966279 1.469924
+6412452 276 7.510870 1.389529
+6662050 22 10.000000 0.000000
+6966692 907 8.673649 1.286455
+7131622 1102 7.851180 1.751500
+173 rows × 3 columns
+```
+
+#### 12 去重和连表
+
+按照平均得分从大到小排序:
+```python
+n3s_sort = n3s.sort_values(by='mean',ascending=False)
+```
+结果:
+```python
+ count mean std
+Movie ID
+6662050 22 10.000000 0.000000
+4921860 48 10.000000 0.000000
+5262972 28 10.000000 0.000000
+5512872 353 9.985836 0.266123
+3863552 199 9.010050 1.163372
+... ... ... ...
+1291150 647 6.327666 1.785968
+2557490 546 6.307692 1.858434
+1478839 120 6.200000 0.728761
+2177771 485 6.150515 1.523922
+1951261 1091 6.083410 1.736127
+173 rows × 3 columns
+```
+仅靠`Movie ID`还是不知道哪些电影,连接`movies`表:
+```python
+ms = movies.drop_duplicates(subset=['Movie ID'])
+ms = ms.set_index('Movie ID')
+n3s_final = n3s_drops.join(ms,on='Movie ID')
+```
+
+#### 13 结果分析
+
+喜剧榜单前50名:
+```python
+Movie Title
+Five Minutes (2017)
+MSG 2 the Messenger (2015)
+Avengers: Age of Ultron Parody (2015)
+Be Somebody (2016)
+Bajrangi Bhaijaan (2015)
+Back to the Future (1985)
+La vita 鐚?bella (1997)
+The Intouchables (2011)
+The Sting (1973)
+Coco (2017)
+Toy Story 3 (2010)
+3 Idiots (2009)
+Green Book (2018)
+Dead Poets Society (1989)
+The Apartment (1960)
+P.K. (2014)
+The Truman Show (1998)
+Am鑼卨ie (2001)
+Inside Out (2015)
+Toy Story 4 (2019)
+Toy Story (1995)
+Finding Nemo (2003)
+Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb (1964)
+Home Alone (1990)
+Zootopia (2016)
+Up (2009)
+Monsters, Inc. (2001)
+La La Land (2016)
+Relatos salvajes (2014)
+En man som heter Ove (2015)
+Snatch (2000)
+Lock, Stock and Two Smoking Barrels (1998)
+How to Train Your Dragon 2 (2014)
+As Good as It Gets (1997)
+Guardians of the Galaxy (2014)
+The Grand Budapest Hotel (2014)
+Fantastic Mr. Fox (2009)
+Silver Linings Playbook (2012)
+Sing Street (2016)
+Deadpool (2016)
+Annie Hall (1977)
+Pride (2014)
+In Bruges (2008)
+Big Hero 6 (2014)
+Groundhog Day (1993)
+The Breakfast Club (1985)
+Little Miss Sunshine (2006)
+Deadpool 2 (2018)
+The Terminal (2004)
+```
+
+前10名评论数图:
+
+
+
+代码:
+```python
+x = n3s_final['Movie Title'][:10].tolist()[::-1]
+y = n3s_final['count'][:10].tolist()[::-1]
+bar = (
+ Bar()
+ .add_xaxis(x)
+ .add_yaxis('评论数',y,category_gap='50%')
+ .reversal_axis()
+ .set_global_opts(title_opts=opts.TitleOpts(title="喜剧电影被评论次数"),
+ toolbox_opts=opts.ToolboxOpts(),)
+)
+grid = (
+ Grid(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
+ .add(bar, grid_opts=opts.GridOpts(pos_left="30%"))
+)
+grid.render_notebook()
+```
+
+前10名得分图:
+
+
+
+代码:
+```python
+x = n3s_final['Movie Title'][:10].tolist()[::-1]
+y = n3s_final['mean'][:10].round(3).tolist()[::-1]
+bar = (
+ Bar()
+ .add_xaxis(x)
+ .add_yaxis('平均得分',y,category_gap='50%')
+ .reversal_axis()
+ .set_global_opts(title_opts=opts.TitleOpts(title="喜剧电影平均得分"),
+ xaxis_opts=opts.AxisOpts(min_=8.0,name='平均得分'),
+ toolbox_opts=opts.ToolboxOpts(),)
+)
+grid = (
+ Grid(init_opts=opts.InitOpts(theme=ThemeType.MACARONS))
+ .add(bar, grid_opts=opts.GridOpts(pos_left="30%"))
+)
+grid.render_notebook()
+```
+
+
+
+#### 14 生成哑变量
+
+分类变量的数值化,是指将枚举类变量转化为indicator变量或称dummy变量。
+
+那么什么是`indicator变量`,看看如下例子,A变量解析为:`[1,0,0]`, B解析为:`[0,1,0]`, C解析为:`[0,0,1]`
+```python
+In [8]: s = pd.Series(list('ABCA'))
+In [9]: pd.get_dummies(s)
+Out[9]:
+ A B C
+0 1 0 0
+1 0 1 0
+2 0 0 1
+3 1 0 0
+```
+
+如果输入的字符有4个唯一值,看到字符a被解析为[1,0,0,0],向量长度为4.
+
+```python
+In [5]: s = pd.Series(list('abaccd'))
+In [6]: pd.get_dummies(s)
+Out[6]:
+ a b c d
+0 1 0 0 0
+1 0 1 0 0
+2 1 0 0 0
+3 0 0 1 0
+4 0 0 1 0
+5 0 0 0 1
+```
+
+也就是说dummy向量的长度等于输入字符串中,唯一字符的个数。
+
+#### 15 讨厌的SettingWithCopyWarning!!!
+
+Pandas 处理数据,太好用了,谁用谁知道!
+
+使用过 Pandas 的,几乎都会遇到一个警告:
+
+*SettingWithCopyWarning*
+
+非常烦人!
+
+尤其是刚接触 Pandas 的,完全不理解为什么弹出这么一串:
+
+```python
+d:\source\test\settingwithcopy.py:9: SettingWithCopyWarning:
+A value is trying to be set on a copy of a slice from a DataFrame.
+Try using .loc[row_indexer,col_indexer] = value instead
+
+See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
+```
+
+归根结底,是因为代码中出现`链式操作`...
+
+有人就问了,什么是`链式操作`?
+
+这样的:
+
+```python
+tmp = df[df.a<4]
+tmp['c'] = 200
+```
+
+先记住这个最典型的情况,即可!
+
+有的人就问了:出现这个 Warning, 需要理会它吗?
+
+如果结果不对,当然要理会;如果结果对,不care.
+
+举个例子~~
+
+```python
+import pandas as pd
+
+df = pd.DataFrame({'a':[1,3,5],'b':[4,2,7]},index=['a','b','c'])
+df.loc[df.a<4,'c'] = 100
+print(df)
+print('it\'s ok')
+
+tmp = df[df.a<4]
+tmp['c'] = 200
+print('-----tmp------')
+print(tmp)
+print('-----df-------')
+print(df)
+```
+
+输出结果:
+```python
+ a b c
+a 1 4 100.0
+b 3 2 100.0
+c 5 7 NaN
+it's ok
+d:\source\test\settingwithcopy.py:9: SettingWithCopyWarning:
+A value is trying to be set on a copy of a slice from a DataFrame.
+Try using .loc[row_indexer,col_indexer] = value instead
+
+See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
+ tmp['c'] = 200
+-----tmp------
+ a b c
+a 1 4 200
+b 3 2 200
+-----df-------
+ a b c
+a 1 4 100.0
+b 3 2 100.0
+c 5 7 NaN
+```
+
+it's ok 行后面的发生链式赋值,导致结果错误。因为 tmp 变了,df 没赋上值啊,所以必须理会。
+
+it's ok 行前的是正解。
+
+以上,链式操作尽量避免,如何避免?多使用 `.loc[row_indexer,col_indexer]`,提示告诉我们的~
+
+#### 16 NumPy 数据归一化、分布可视化
+
+仅使用 `NumPy`,下载数据,归一化,使用 `seaborn` 展示数据分布。
+
+**下载数据**
+
+```python
+import numpy as np
+
+url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
+wid = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[1])
+```
+仅提取 `iris` 数据集的第二列 `usecols = [1]`
+
+**展示数据**
+
+```python
+array([3.5, 3. , 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3. ,
+ 3. , 4. , 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.6, 3.3, 3.4, 3. ,
+ 3.4, 3.5, 3.4, 3.2, 3.1, 3.4, 4.1, 4.2, 3.1, 3.2, 3.5, 3.1, 3. ,
+ 3.4, 3.5, 2.3, 3.2, 3.5, 3.8, 3. , 3.8, 3.2, 3.7, 3.3, 3.2, 3.2,
+ 3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7, 2. , 3. , 2.2, 2.9, 2.9,
+ 3.1, 3. , 2.7, 2.2, 2.5, 3.2, 2.8, 2.5, 2.8, 2.9, 3. , 2.8, 3. ,
+ 2.9, 2.6, 2.4, 2.4, 2.7, 2.7, 3. , 3.4, 3.1, 2.3, 3. , 2.5, 2.6,
+ 3. , 2.6, 2.3, 2.7, 3. , 2.9, 2.9, 2.5, 2.8, 3.3, 2.7, 3. , 2.9,
+ 3. , 3. , 2.5, 2.9, 2.5, 3.6, 3.2, 2.7, 3. , 2.5, 2.8, 3.2, 3. ,
+ 3.8, 2.6, 2.2, 3.2, 2.8, 2.8, 2.7, 3.3, 3.2, 2.8, 3. , 2.8, 3. ,
+ 2.8, 3.8, 2.8, 2.8, 2.6, 3. , 3.4, 3.1, 3. , 3.1, 3.1, 3.1, 2.7,
+ 3.2, 3.3, 3. , 2.5, 3. , 3.4, 3. ])
+
+```
+
+这是单变量(univariate)长度为 150 的一维 NumPy 数组。
+
+**归一化**
+
+求出最大值、最小值
+```python
+smax = np.max(wid)
+smin = np.min(wid)
+
+In [51]: smax,smin
+Out[51]: (4.4, 2.0)
+````
+归一化公式:
+```python
+s = (wid - smin) / (smax - smin)
+```
+只打印小数点后三位设置:
+```python
+np.set_printoptions(precision=3)
+```
+
+归一化结果:
+```markdown
+array([0.625, 0.417, 0.5 , 0.458, 0.667, 0.792, 0.583, 0.583, 0.375,
+ 0.458, 0.708, 0.583, 0.417, 0.417, 0.833, 1. , 0.792, 0.625,
+ 0.75 , 0.75 , 0.583, 0.708, 0.667, 0.542, 0.583, 0.417, 0.583,
+ 0.625, 0.583, 0.5 , 0.458, 0.583, 0.875, 0.917, 0.458, 0.5 ,
+ 0.625, 0.458, 0.417, 0.583, 0.625, 0.125, 0.5 , 0.625, 0.75 ,
+ 0.417, 0.75 , 0.5 , 0.708, 0.542, 0.5 , 0.5 , 0.458, 0.125,
+ 0.333, 0.333, 0.542, 0.167, 0.375, 0.292, 0. , 0.417, 0.083,
+ 0.375, 0.375, 0.458, 0.417, 0.292, 0.083, 0.208, 0.5 , 0.333,
+ 0.208, 0.333, 0.375, 0.417, 0.333, 0.417, 0.375, 0.25 , 0.167,
+ 0.167, 0.292, 0.292, 0.417, 0.583, 0.458, 0.125, 0.417, 0.208,
+ 0.25 , 0.417, 0.25 , 0.125, 0.292, 0.417, 0.375, 0.375, 0.208,
+ 0.333, 0.542, 0.292, 0.417, 0.375, 0.417, 0.417, 0.208, 0.375,
+ 0.208, 0.667, 0.5 , 0.292, 0.417, 0.208, 0.333, 0.5 , 0.417,
+ 0.75 , 0.25 , 0.083, 0.5 , 0.333, 0.333, 0.292, 0.542, 0.5 ,
+ 0.333, 0.417, 0.333, 0.417, 0.333, 0.75 , 0.333, 0.333, 0.25 ,
+ 0.417, 0.583, 0.458, 0.417, 0.458, 0.458, 0.458, 0.292, 0.5 ,
+ 0.542, 0.417, 0.208, 0.417, 0.583, 0.417])
+```
+
+**分布可视化**
+
+```python
+import seaborn as sns
+sns.distplot(s,kde=False,rug=True)
+```
+频率分布直方图:
+
+
+
+
+
+```python
+sns.distplot(s,hist=True,kde=True,rug=True)
+```
+带高斯密度核函数的直方图:
+
+
+
+
+
+**分布 fit 图**
+
+拿 `gamma` 分布去 fit :
+```python
+from scipy import stats
+sns.distplot(s, kde=False, fit = stats.gamma)
+```
+
+
+
+
+
+
+拿双 `gamma` 去 fit:
+```python
+from scipy import stats
+sns.distplot(s, kde=False, fit = stats.dgamma)
+```
+
+
+
+#### 17 Pandas 使用技巧
+
+对于动辄就几十或几百个 G 的数据,在读取的这么大数据的时候,我们有没有办法随机选取一小部分数据,然后读入内存,快速了解数据和开展 EDA ?
+
+使用 Pandas 的 skiprows 和 概率知识,就能做到。
+
+下面解释具体怎么做。
+
+如下所示,读取某 100 G 大小的 big_data.csv 数据
+
+1) 使用 skiprows 参数,
+
+2) x > 0 确保首行读入,
+
+3) np.random.rand() > 0.01 表示 99% 的数据都会被随机过滤掉
+
+言外之意,只有全部数据的 1% 才有机会选入内存中。
+
+```python
+import pandas as pd
+import numpy as np
+
+df = pd.read_csv("big_data.csv",
+skiprows =
+lambda x: x>0 and np.random.rand() > 0.01)
+
+print("The shape of the df is {}.
+It has been reduced 100 times!".format(df.shape))
+```
+
+使用这种方法,读取的数据量迅速缩减到原来的 1% ,对于迅速展开数据分析有一定的帮助。
+
+### 十一、一步一步掌握Flask web开发
+
+#### 1 Flask版 hello world
+
+Flask是Python轻量级web框架,容易上手,被广大Python开发者所喜爱。
+
+今天我们先从hello world开始,一步一步掌握Flask web开发。例子君是Flask框架的小白,接下来与读者朋友们,一起学习这个对我而言的新框架,大家多多指导。
+
+首先`pip install Flask`,安装Flask,然后import Flask,同时创建一个 `app`
+```python
+from flask import Flask
+
+App = Flask(__name__)
+```
+
+写一个index页的入口函数,返回hello world.
+
+通过装饰器:App.route('/')创建index页的路由或地址,一个`/`表示index页,也就是主页。
+
+```python
+@App.route('/')
+def index():
+ return "hello world"
+```
+
+调用 `index`函数:
+```python
+if __name__ == "__main__":
+ App.run(debug=True)
+```
+
+然后启动,会在console下看到如下启动信息,表明`服务启动成功`。
+```python
+* Debug mode: on
+ * Restarting with stat
+ * Debugger is active!
+ * Debugger PIN: 663-788-611
+ * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
+```
+
+ 接下来,打开一个网页,相当于启动客户端,并在Url栏中输入:`http://127.0.0.1:5000/`,看到页面上答应出`hello world`,证明服务访问成功。
+
+ 同时在服务端后台看到如下信息,表示处理一次来自客户端的`get`请求。
+ ```python
+ 27.0.0.1 - - [03/Feb/2020 21:26:50] "GET / HTTP/1.1" 200 -
+ ```
+
+ 以上就是flask的hello world 版
+
+#### 2 Flask之数据入库操作
+
+数据持久化就是将数据写入到数据库存储的过程。
+
+本例子使用`sqlite3`数据库。
+
+1)导入`sqlite3`,未安装前使用命令`pip install sqlite3`
+
+创建一个`py`文件:`sqlite3_started.py`,并写下第一行代码:
+```python
+import sqlite3
+```
+2)手动创建一个数据库实例`db`, 命名`test.db`
+
+3)创建与数据库实例`test.db`的连接:
+```python
+conn = sqlite3.connect("test.db")
+```
+
+4)拿到连接`conn`的cursor
+```python
+c = conn.cursor()
+```
+
+5)创建第一张表`books`
+
+共有四个字段:`id`,`sort`,`name`,`price`,类型分别为:`int`,`int`,`text`,`real`. 其中`id`为`primary key`. 主键的取值必须是唯一的(`unique`),否则会报错。
+
+
+```python
+c.execute('''CREATE TABLE books
+ (id int primary key,
+ sort int,
+ name text,
+ price real)''')
+```
+第一次执行上面语句,表`books`创建完成。当再次执行时,就会报`重复建表`的错误。需要优化脚本,检查表是否存在`IF NOT EXISTS books`,不存在再创建:
+```python
+c.execute('''CREATE TABLE IF NOT EXISTS books
+ (id int primary key,
+ sort int,
+ name text,
+ price real)''')
+```
+
+6)插入一行记录
+
+共为4个字段赋值
+
+```python
+c.execute('''INSERT INTO books VALUES
+ (1,
+ 1,
+ 'computer science',
+ 39.0)''')
+```
+
+7)一次插入多行记录
+
+先创建一个list:`books`,使用`executemany`一次插入多行。
+```python
+books = [(2, 2, 'Cook book', 68),
+ (3, 2, 'Python intro', 89),
+ (4, 3, 'machine learning', 59),
+ ]
+
+
+c.executemany('INSERT INTO books VALUES (?, ?, ?, ?)', books)
+```
+
+8)提交
+
+提交后才会真正生效,写入到数据库
+
+```python
+conn.commit()
+```
+
+9)关闭期初建立的连接conn
+
+务必记住手动关闭,否则会出现内存泄漏
+```python
+conn.close()
+print('Done')
+```
+
+10)查看结果
+例子君使用`vs code`,在扩展库中选择:`SQLite`安装。
+
+
+
+新建一个`sq`文件:`a.sql`,内容如下:
+
+```sql
+SELECT * from books
+```
+右键`run query`,得到表`books`插入的4行记录可视化图:
+
+
+
+以上十步就是sqlite3写入数据库的主要步骤,作为Flask系列的第二篇,为后面的前端讲解打下基础。
+
+#### 3 Flask各层调用关系
+
+这篇介绍Flask和B/S模式,即浏览器/服务器模式,是接下来快速理解Flask代码的关键理论篇:**理解Views、models和渲染模板层的调用关系**。
+
+1) 发出请求
+
+当我们在浏览器地址栏中输入某个地址,按回车后,完成第一步。
+
+2) 视图层 views接收1)步发出的请求,Flask中使用解释器的方式处理这个求情,实例代码如下,它通常涉及到调用models层和模板文件层
+
+```python
+@main_blue.route('/', methods=['GET', 'POST'])
+def index():
+ form = TestForm()
+ print('test')
+```
+
+3) models层会负责创建数据模型,执行CRUD操作
+
+4) 模板文件层处理html模板
+
+5) 组合后返回html
+
+6) models层和html模板组合后返回给views层
+
+7)最后views层响应并渲染到浏览器页面,我们就能看到请求的页面。
+
+完整过程图如下所示:
+
+
+
+读者朋友们,如果你和例子君一样都是初学Flask编程,需要好好理解上面的过程。理解这些对于接下来的编程会有一定的理论指导,方向性指导价值。
+
+### Python 问答
+
+#### Python 如何生成二维码?
+
+
+
+
+
+## qrcode
+
+今天先来解答如何生成二维码。Python的`qrcode`包支持生成二维码。
+
+用法也很简单:
+
+```python
+import qrcode
+
+# 二维码内容
+data = "http://www.zglg.work/wp-content/uploads/2020/10/image-3.png"
+# 生成二维码
+img = qrcode.make(data=data)
+# 直接显示二维码
+img.show()
+# 保存二维码为文件
+img.save("我的微信.jpg")
+```
+
+生成的二维码如下:
+
+
+
+
+大家微信扫描后,会出现我的二维码。
+
+另外,还可以设置二维码的颜色等样式:
+
+```python
+import qrcode
+
+# 实例化二维码生成类
+qr = qrcode.QRCode(border=2)
+# 设置二维码数据
+data = "http://www.zglg.work/wp-content/uploads/2020/10/image-3.png"
+qr.add_data(data=data)
+# 启用二维码颜色设置
+qr.make(fit=True)
+img = qr.make_image(fill_color="orange", back_color="white")
+
+# 显示二维码
+img.show()
+```
+
+生成一个orange的二维码:
+
+
+
+更多样式,大家可以自己去玩耍。
+
+## Python小项目:句子KWIC显示
+
+上下文关键字(KWIC, Key Word In Context)是最常见的多行协调显示格式。
+
+此小项目描述:输入一系列句子,给定一个给定单词,每个句子中至少会出现一次给定单词。目标输出,给定单词按照KWIC显示,KWIC显示的基本要求:待查询单词居中,前面`pre`序列右对齐,后面`post`序列左对齐,待查询单词前和后长度相等,若输入句子无法满足要求,用空格填充。
+
+输入参数:输入句子sentences, 待查询单词selword, 滑动窗口长度`window_len`
+
+举例,输入如下六个句子,给定单词`secure`,输出如下字符串:
+
+```python
+ pre keyword post
+
+ welfare , and secure the blessings of
+ nations , and secured immortal glory with
+ , and shall secure to you the
+ cherished . To secure us against these
+ defense as to secure our cities and
+ I can to secure economy and fidelity
+```
+
+请补充实现下面函数:
+
+```python
+def kwic(sentences: List[str], selword: str, window_len: int) -> str:
+ """
+ :type: sentences: input sentences
+ :type: selword: selected word
+ :type: window_len: window length
+ """
+```
+
+更多KWIC显示参考如下:
+
+http://dep.chs.nihon-u.ac.jp/english_lang/tukamoto/kwic_e.html
+
+完整代码已经公布在:http://www.zglg.work/Python-20-topics/python-project1-kwic/
+
+
+
diff --git a/md/1.md b/md/1.md
index 38259505..817a25ea 100644
--- a/md/1.md
+++ b/md/1.md
@@ -25,6 +25,6 @@ relu(5) # 5
relu(-1) # 0
```
-
-
-[下一个例子](2.md)
+
+
+[下一个例子](2.md)
diff --git a/md/10.md b/md/10.md
index 3cc76980..1fdec254 100644
--- a/md/10.md
+++ b/md/10.md
@@ -6,12 +6,39 @@
#### 10 转为整型
-int(x, base =10) , x可能为字符串或数值,将x 转换为一个普通整数。如果参数是字符串,那么它可能包含符号和小数点。如果超出了普通整数的表示范围,一个长整数被返回。
+int(x, base =10) , x可能为字符串或数值,将 x 转换为一个普通整数。
+
+参数base指定x进制数,常见的2,8,10,16分别表示二进制、八进制、十进制、十六进制的数字
+
+如果参数是字符串,必须为整数型字符串,如果是浮点数字符串会抛出异常。
+
+如果x是浮点数,int后截去小数点,只保留整数部分。
```python
-In [1]: int('12',16)
-Out[1]: 18
+In [2]: int('0110',2)
+
+Out[2]: 6
+
+In [3]: int('0732',8)
+Out[3]: 474
+
+In [4]: int('12',16)
+Out[4]: 18
+
+In [5]: int('12',10)
+Out[5]: 12
+
+In [6]: int(1.45)
+Out[6]: 1
+
+In [7]: int('1.45')
+---------------------------------------------------------------------------
+ValueError Traceback (most recent call last)
+ in
+----> 1 int('1.45')
+
+ValueError: invalid literal for int() with base 10: '1.45'
```
-[上一个例子](9.md) [下一个例子](11.md)
\ No newline at end of file
+[上一个例子](9.md) [下一个例子](11.md)
diff --git a/md/11.md b/md/11.md
index 40874b42..31072399 100644
--- a/md/11.md
+++ b/md/11.md
@@ -9,9 +9,12 @@
base为底的exp次幂,如果mod给出,取余
```python
-In [1]: pow(3, 2, 4)
+In [1]: pow(2,1.5)
+Out[1]: 2.8284271247461903
+
+In [1]: pow(3, 2, 4) # 3的2次方结果再对4取余数
Out[1]: 1
```
-[上一个例子](10.md) [下一个例子](12.md)
\ No newline at end of file
+[上一个例子](10.md) [下一个例子](12.md)
diff --git a/md/118.md b/md/118.md
index ca14fe8d..8b3eaec1 100644
--- a/md/118.md
+++ b/md/118.md
@@ -23,7 +23,7 @@ print(t) # <_MainThread(MainThread, started 139908235814720)>
所以,验证了程序默认是在`MainThead`中执行。
-`t.getName()`获得这个线程的名字,其他常用方法,`getName()`获得线程`id`,`isAlive()`判断线程是否存活等。
+`t.getName()`获得这个线程的名字,其他常用方法,`t.ident`获得线程`id`,`isAlive()`判断线程是否存活等。
```python
print(t.getName()) # MainThread
@@ -31,4 +31,4 @@ print(t.ident) # 139908235814720
print(t.isAlive()) # True
```
-[上一个例子](117.md) [下一个例子](119.md)
\ No newline at end of file
+[上一个例子](117.md) [下一个例子](119.md)
diff --git a/md/123.md b/md/123.md
index 20f70c47..ccff06f5 100644
--- a/md/123.md
+++ b/md/123.md
@@ -54,10 +54,10 @@ t8 adds a to 1: 9
t9 adds a to 1: 10
```
-一起正常,其实这已经是单线程顺序执行了,就本例子而言,已经失去多线程的价值,并且还带来了因为线程创建开销,浪费时间的副作用。
+一切正常,其实这已经是单线程顺序执行了,就本例子而言,已经失去多线程的价值,并且还带来了因为线程创建开销,浪费时间的副作用。
程序中只有一把锁,通过 `try...finally`还能确保不发生死锁。但是,当程序中启用多把锁,还是很容易发生死锁。
注意使用场合,避免死锁,是我们在使用多线程开发时需要注意的一些问题。
-[上一个例子](122.md) [下一个例子](124.md)
\ No newline at end of file
+[上一个例子](122.md) [下一个例子](124.md)
diff --git a/md/13.md b/md/13.md
index 634ac883..3cc2f3c5 100644
--- a/md/13.md
+++ b/md/13.md
@@ -6,6 +6,8 @@
#### 13 链式比较
+Python支持这种连续不等比较,写起来更方便
+
```python
i = 3
print(1 < i < 3) # False
@@ -13,4 +15,4 @@ print(1 < i <= 3) # True
```
-[上一个例子](12.md) [下一个例子](14.md)
\ No newline at end of file
+[上一个例子](12.md) [下一个例子](14.md)
diff --git a/md/14.md b/md/14.md
index a66f7aca..061a1d8d 100644
--- a/md/14.md
+++ b/md/14.md
@@ -11,9 +11,20 @@
```python
In [12]: s = "apple"
-In [13]: bytes(s,encoding='utf-8')
-Out[13]: b'apple'
+In [13]: a = bytes(s,encoding='utf-8')
+In [14] a
+Out[14]: b'apple'
+
+# 转化后a变为字节序列,bytes类型,
+# 并且每个字符都被转化为数值,如下所示
+In [15]: for i in a:
+ ...: print(i)
+97
+112
+112
+108
+101
```
-[上一个例子](13.md) [下一个例子](15.md)
\ No newline at end of file
+[上一个例子](13.md) [下一个例子](15.md)
diff --git a/md/15.md b/md/15.md
index 93b443f5..b5127301 100644
--- a/md/15.md
+++ b/md/15.md
@@ -7,16 +7,30 @@
#### 15 任意对象转为字符串
```python
-In [14]: i = 100
+
-In [15]: str(i)
-Out[15]: '100'
+In [1]: str(100)
+Out[1]: '100'
-In [16]: str([])
-Out[16]: '[]'
+In [2]: str([3,2,10])
+Out[2]: '[3, 2, 10]'
+
+In [3]: str({'a':1, 'b':10})
+Out[3]: "{'a': 1, 'b': 10}"
+
+In [11]: from collections import defaultdict
+In [12]: dd = defaultdict(int)
+
+In [14]: for i in [1,3,2,2,3,3]:
+ ...: dd[i] += 1
+ ...:
+
+In [15]: dd
+Out[15]: defaultdict(int, {1: 1, 3: 3, 2: 2})
+
+In [16]: str(dd)
+Out[16]: "defaultdict(, {1: 1, 3: 3, 2: 2})"
-In [17]: str(tuple())
-Out[17]: '()'
```
-[上一个例子](14.md) [下一个例子](16.md)
\ No newline at end of file
+[上一个例子](14.md) [下一个例子](16.md)
diff --git a/md/159.md b/md/159.md
index 84bec8a9..98b7426f 100644
--- a/md/159.md
+++ b/md/159.md
@@ -13,7 +13,7 @@
```python
def del_item(lst,e):
- return [lst.remove(i) for i in e if i==e] # NO!
+ return [lst.remove(i) for i in lst if i==e] # NO!
```
考虑删除这个序列[1,3,3,3,5]中的元素3,结果发现只删除其中两个:
@@ -31,4 +31,4 @@ def del_item(lst,e):
```
-[上一个例子](158.md) [下一个例子](160.md)
\ No newline at end of file
+[上一个例子](158.md) [下一个例子](160.md)
diff --git a/md/16.md b/md/16.md
index 45bccd41..5cc1a5a3 100644
--- a/md/16.md
+++ b/md/16.md
@@ -18,6 +18,18 @@ Out[3]: at 0x0000000005DE75D0, file "", line 1>
In [4]: exec(r)
helloworld
+
+s = """
+def f():
+ a = 100 % 52
+ print(a)
+f()
+"""
+r = compile(s,"", "exec")
+exec(r)
```
-[上一个例子](15.md) [下一个例子](17.md)
\ No newline at end of file
+输出
+48
+
+[上一个例子](15.md) [下一个例子](17.md)
diff --git a/md/17.md b/md/17.md
index 33dbc7f5..3b3c360c 100644
--- a/md/17.md
+++ b/md/17.md
@@ -10,8 +10,24 @@
```python
In [1]: s = "1 + 3 +5"
- ...: eval(s)
-Out[1]: 9
+
+In [2]: eval(s)
+Out[2]: 9
+
+s = ["{'小汽车':10, '面包车':8}", "{'面包车':5}"]
+from collections import defaultdict
+d = defaultdict(int)
+
+for item in s:
+ my_dict = eval(item)
+ print(type(my_dict))
+ for key in my_dict:
+ d[key] += my_dict[key]
+print(d)
+
+
+
+defaultdict(, {'小汽车': 10, '面包车': 13})
```
-[上一个例子](16.md) [下一个例子](18.md)
\ No newline at end of file
+[上一个例子](16.md) [下一个例子](18.md)
diff --git a/md/198.md b/md/198.md
index 566f6437..45709457 100644
--- a/md/198.md
+++ b/md/198.md
@@ -6,6 +6,23 @@
@version
@date 2020/04/05
```
-
+## 1 常见算术运算
-[上一个例子](197.md) [下一个例子](199.md)
\ No newline at end of file
+```python
+x, y = 3, 2
+print(x + y) # = 5
+print(x - y) # = 1
+print(x * y) # = 6
+print(x / y) # = 1.5
+print(x // y) # = 1
+print(x % y) # = 1
+print(-x) # = -3
+print(abs(-x)) # = 3
+print(int(3.9)) # = 3
+print(float(x)) # = 3.0
+print(x ** y) # = 9
+```
+
+大多数操作符都是不言自明的。注意,`//`运算符执行整数除法。结果是一个向下舍入的整数值(例如,3//2==1)
+
+[上一个例子](197.md) [下一个例子](199.md)
diff --git a/md/199.md b/md/199.md
index 18c86a06..7df7ea58 100644
--- a/md/199.md
+++ b/md/199.md
@@ -1,11 +1,29 @@
```markdown
@author jackzhenguo
-@desc
+@desc 求两点球面距离
@tag
@version
@date 2020/04/06
```
-
+
+```python
+EARTH_RADIUS = 6378.137
+
+import math
+# 角度弧度计算公式
+def get_radian(degree):
+ return degree * 3.1415926 / 180.0
+# 根据经纬度计算两点之间的距离,得到的单位是 千米
+def get_distance(lat1,lng1,lat2,lng2):
+ radLat1 = get_radian(lat1)
+ radLat2 = get_radian(lat2)
+ a = radLat1 - radLat2 # 两点纬度差
+ b = get_radian(lng1) - get_radian(lng2); # 两点的经度差
+ s = 2 * math.asin(math.sqrt(math.pow(math.sin(a / 2), 2) +
+ math.cos(radLat1) * math.cos(radLat2) * math.pow(math.sin(b / 2), 2)));
+ s = s * EARTH_RADIUS
+ return s
+```
[上一个例子](198.md) [下一个例子](200.md)
\ No newline at end of file
diff --git a/md/2.md b/md/2.md
index 22a5a27f..aa58feaa 100644
--- a/md/2.md
+++ b/md/2.md
@@ -8,21 +8,21 @@
十进制转换为二进制:
```python
-In [2]: bin(10)
-Out[2]: '0b1010'
+In [1]: bin(10)
+Out[1]: '0b1010'
```
十进制转换为八进制:
```python
-In [3]: oct(9)
-Out[3]: '0o11'
+In [2]: oct(9)
+Out[2]: '0o11'
```
十进制转换为十六进制:
```python
-In [4]: hex(15)
-Out[4]: '0xf'
+In [3]: hex(15)
+Out[3]: '0xf'
```
-
-
+
+
[上一个例子](1.md) [下一个例子](3.md)
\ No newline at end of file
diff --git a/md/200.md b/md/200.md
index 61f6eebc..ff873a60 100644
--- a/md/200.md
+++ b/md/200.md
@@ -1,11 +1,29 @@
```markdown
@author jackzhenguo
-@desc
+@desc 获取文件编码
@tag
@version
@date 2020/04/07
```
-
+
+```python
+import chardet
+from chardet import UniversalDetector
+
+def get_encoding(file):
+ with open(file, "rb") as f:
+ cs = chardet.detect(f.read())
+ return cs['encoding']
+
+ detector = UniversalDetector()
+ with open(file, "rb") as f:
+ for line in f.readlines():
+ detector.feed(line)
+ if detector.done:
+ break
+ detector.close()
+ return detector.result
+```
[上一个例子](199.md) [下一个例子](201.md)
\ No newline at end of file
diff --git a/md/201.md b/md/201.md
index c4e37277..7e323468 100644
--- a/md/201.md
+++ b/md/201.md
@@ -1,11 +1,25 @@
```markdown
@author jackzhenguo
-@desc
+@desc 格式化json串
@tag
@version
@date 2020/04/08
```
+```python
+import json
+
+
+def format_json(json_str: str):
+ dic = json.loads(json_str)
+
+ js = json.dumps(dic,
+ sort_keys=True,
+ ensure_ascii=False,
+ indent=4,
+ separators=(', ', ': '))
+ return js
+```
[上一个例子](200.md) [下一个例子](202.md)
\ No newline at end of file
diff --git a/md/23.md b/md/23.md
index 05fb188b..ac994a9e 100644
--- a/md/23.md
+++ b/md/23.md
@@ -6,6 +6,30 @@
#### 23 交换两元素
+理解交换两个元素,需要首先明白什么是pack,什么是unpack
+
+```python
+In [1]: a=[3,1]
+
+# unpack
+In [2]: a0,a1 = a
+
+In [3]: a0
+Out[3]: 3
+
+In [4]: a1
+Out[4]: 1
+
+# pack
+In [5]: b = a0, a1
+
+In [6]: b
+Out[6]: (3, 1)
+
+```
+
+所以下面 `b,a = a,b` 交换2个元素的过程,实际是先pack a,b为元组 (a,b),然后再unpack (a,b) 给 b, a的过程
+
```python
def swap(a, b):
return b, a
@@ -14,4 +38,4 @@ def swap(a, b):
print(swap(1, 0)) # (0,1)
```
-[上一个例子](22.md) [下一个例子](24.md)
\ No newline at end of file
+[上一个例子](22.md) [下一个例子](24.md)
diff --git a/md/24.md b/md/24.md
index 6aa000d2..22af8a0c 100644
--- a/md/24.md
+++ b/md/24.md
@@ -9,11 +9,9 @@
```python
In [31]: def f():
...: print('i\'m f')
- ...:
In [32]: def g():
...: print('i\'m g')
- ...:
In [33]: [f,g][1]()
i'm g
diff --git a/md/25.md b/md/25.md
index 6a655eb4..f1e70f29 100644
--- a/md/25.md
+++ b/md/25.md
@@ -7,7 +7,8 @@
#### 25 生成逆序序列
```python
-list(range(10,-1,-1)) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
+list(range(10,-1,-1))
+# [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
```
第三个参数为负时,表示从第一个参数开始递减,终止到第二个参数(不包括此边界)
diff --git a/md/29.md b/md/29.md
index a2282893..9998a648 100644
--- a/md/29.md
+++ b/md/29.md
@@ -9,17 +9,24 @@
创建数据字典
```python
+# 方法1:使用dict
In [1]: dict()
Out[1]: {}
-
In [2]: dict(a='a',b='b')
Out[2]: {'a': 'a', 'b': 'b'}
+# 方法2:zip
In [3]: dict(zip(['a','b'],[1,2]))
Out[3]: {'a': 1, 'b': 2}
+# 方法3:嵌入元组的列表
In [4]: dict([('a',1),('b',2)])
Out[4]: {'a': 1, 'b': 2}
+
+# 方法4:自典型字符串
+In [1]: s = "{'a':1, 'b':2}"
+In [2]: eval(s)
+Out[2]: {'a': 1, 'b': 2}
```
-[上一个例子](28.md) [下一个例子](30.md)
\ No newline at end of file
+[上一个例子](28.md) [下一个例子](30.md)
diff --git a/md/31.md b/md/31.md
index f2417ab3..c9a73545 100644
--- a/md/31.md
+++ b/md/31.md
@@ -9,10 +9,37 @@
返回一个set对象,集合内不允许有重复元素:
```python
-In [159]: a = [1,4,2,3,1]
+In [1]: a = [1,4,2,3,1]
-In [160]: set(a)
-Out[160]: {1, 2, 3, 4}
+In [2]: set(a)
+Out[2]: {1, 2, 3, 4}
+
+In [3]: b = set(a)
+
+In [4]: b.add(5)
+
+In [5]: b
+Out[5]: {1, 2, 3, 4, 5}
+
+In [6]: b.pop()
+Out[6]: 1
+
+In [7]: b
+Out[7]: {2, 3, 4, 5}
+
+In [8]: b.pop()
+Out[8]: 2
+
+In [9]: b
+Out[9]: {3, 4, 5}
+
+# 注意pop删除集合内任意一个元素
+In [10]: help(b.pop)
+Help on built-in function pop:
+
+pop(...) method of builtins.set instance
+ Remove and return an arbitrary set element.
+ Raises KeyError if the set is empty.
```
-[上一个例子](30.md) [下一个例子](32.md)
\ No newline at end of file
+[上一个例子](30.md) [下一个例子](32.md)
diff --git a/md/48.md b/md/48.md
index 38073257..c62565fc 100644
--- a/md/48.md
+++ b/md/48.md
@@ -5,14 +5,22 @@
```
#### 48 查看变量所占字节数
+`getsizeof`查看变量占用字节数
+看到:字典比列表占用更多空间
```python
In [1]: import sys
-In [2]: a = {'a':1,'b':2.0}
+In [3]: a = [('a',1),('b',2)]
+
+In [5]: sys.getsizeof(a)
+Out[5]: 88
+
+
+In [6]: a = {'a':1,'b':2.0}
+In [7]: sys.getsizeof(a)
+Out[7]: 248
-In [3]: sys.getsizeof(a) # 占用240个字节
-Out[3]: 240
```
-[上一个例子](47.md) [下一个例子](49.md)
\ No newline at end of file
+[上一个例子](47.md) [下一个例子](49.md)
diff --git a/md/9.md b/md/9.md
index b027f5ed..3cd61f78 100644
--- a/md/9.md
+++ b/md/9.md
@@ -1,6 +1,6 @@
```markdown
@author jackzhenguo
-@desc
+@desc 转为浮点类型
@date 2019/2/15
```
#### 9 转为浮点类型
@@ -12,6 +12,25 @@ In [1]: float(3)
Out[1]: 3.0
```
+```python
+In [1]: float('3')
+Out[1]: 3.0
+```
+
+浮点数最大值
+```python
+import sys
+
+In[4]: sys.float_info.max
+Out[4]: 1.7976931348623157e+308
+```
+
+正无穷大、负无穷大
+```python
+float('inf') # 正无穷大
+float('-inf') # 负无穷大
+```
+
如果不能转化为浮点数,则会报`ValueError`:
```python
@@ -19,4 +38,4 @@ In [2]: float('a')
# ValueError: could not convert string to float: 'a'
```
-[上一个例子](8.md) [下一个例子](10.md)
\ No newline at end of file
+[上一个例子](8.md) [下一个例子](10.md)
diff --git a/script/.idea/.gitignore b/script/.idea/.gitignore
deleted file mode 100644
index 26d33521..00000000
--- a/script/.idea/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
diff --git a/script/.idea/inspectionProfiles/Project_Default.xml b/script/.idea/inspectionProfiles/Project_Default.xml
deleted file mode 100644
index e4919dcd..00000000
--- a/script/.idea/inspectionProfiles/Project_Default.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/script/.idea/inspectionProfiles/profiles_settings.xml b/script/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 105ce2da..00000000
--- a/script/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/script/.idea/misc.xml b/script/.idea/misc.xml
deleted file mode 100644
index 8161a60d..00000000
--- a/script/.idea/misc.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/script/.idea/modules.xml b/script/.idea/modules.xml
deleted file mode 100644
index 7e8a5742..00000000
--- a/script/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/script/.idea/script.iml b/script/.idea/script.iml
deleted file mode 100644
index 8dc09e54..00000000
--- a/script/.idea/script.iml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/script/.idea/vcs.xml b/script/.idea/vcs.xml
deleted file mode 100644
index 6c0b8635..00000000
--- a/script/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/script/avatar.png b/script/avatar.png
new file mode 100644
index 00000000..4455032c
Binary files /dev/null and b/script/avatar.png differ