## 1. Project Overview & Quickstart (guofei9987/README)

# README

:memo:The missing online resume maker

### Repository Details
- **Repository:** [guofei9987/README](https://github.com/guofei9987/README)
- **Primary Language:** JavaScript

*Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.*

## 2. Official Technical Reference & Guides (guofei9987/guofei9987.github.io)

## File: README.md

个人主页，欢迎 fork

[https://www.guofei.site/](https://www.guofei.site/)

---

## File: _config.yml

permalink: /:year/:month/:day/:title.html
markdown: kramdown
highlighter: rouge


collections:
  reading:
    output: true
    permalink: /reading/:title:output_ext

  os:
    output: true
    permalink: /os/:title:output_ext

kramdown:
  math_engine: null
  smart_quotes: ["apos", "apos", "quot", "quot"]

# 作者信息
author:
  name: Guofei
  email: me@guofei.site
  link: https://www.guofei.site
  github: https://github.com/guofei9987
  linkedin: https://www.linkedin.com/in/guofei9987
  facebook: https://www.facebook.com/guofei9987
  guofei9987/guofei9987.github.io

# 站点信息
title: 郭飞的笔记
url: https://www.guofei.site
repurl: https://github.com/guofei9987/guofei9987.github.io/blob/main/
# rss_url: /pages/atom.xml

# gavatar头像及Favicon
gavatar: /p/me/me.png
favicon: /p/me/me2.png

# google analytics 设置
ga:
  id: UA-98406918-1
  url: www.guofei.site


# 主题设置，自动激活某个标签
active: tags

---

## File: LICENSE.txt

Copyright (c) 2014 郭飞 - Released under The MIT License.

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

---

## File: robots.txt

User-agent: *
Allow: /
Sitemap: https://www.guofei.site/sitemap.txt

---

## File: sitemap.txt

---
title : Sitemap
---
{% for post in site.posts %}{{site.url}}{{ post.url }}
{% endfor %}{% for page in site.pages %}{{site.url}}{{ page.url }}
{% endfor %}{% for article in site.reading %}{{site.url}}{{ article.url }}
{% endfor %}{% for article in site.os %}{{site.url}}{{ article.url }}
{% endfor %}

---

## File: _data/achievement.json

{
"zhihu_agree": "153,925",
"zhihu_collection": "34,960",
"zhihu_follows": "16,747",
"zhihu_agree_str": "153k",
"zhihu_collection_str": "34k",
"zhihu_follows_str": "1.6 万"
}

---

## File: _data/book_list.json

[  
  {
    "name": "《天才小师姐她偏要当废物》",
    "finish_date": "2026年09月13日",
    "author": "狗肠",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "网络小说、女频、修仙、“反系统文”"
  },
  {
    "name": "《古代刀客养家日常》",
    "finish_date": "2026年07月25日",
    "author": "袖侧",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": "网络小说、女频"
  },
  {
    "name": "《奈飞文化手册》",
    "finish_date": "2026年07月04日",
    "author": "帕蒂·麦克考利",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": "国内大厂采纳了很多经验"
  },
  {
    "name": "《东京八平米》",
    "finish_date": "2026年02月08日",
    "author": "吉井忍",
    "publisher":"上海三联书店",
    "score": "❤❤❤",
    "notes":"",
    "comments": "穷有穷的活法。娓娓道来的小感动"
  },
  {
    "name": "《终身免疫力》",
    "finish_date": "2025年8月9日",
    "author": "海瑟·莫迪",
    "publisher":"",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": "作者是免疫学家和综合功能医学专家、医生。"
  },
  {
    "name": "《不老时代》",
    "finish_date": "2025年8月2日",
    "author": "迈克尔·F·罗伊森",
    "publisher":"",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": "作者是一位医学博士，本书畅想了新技术对健康、长寿的贡献，，以及会引发的社会变革，最后是我们应该怎么做。"
  },
  {
    "name": "《超越百岁》",
    "finish_date": "2025年8月1日",
    "author": "彼得•阿提亚",
    "publisher":"",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": "作者曾经在医学院读9年，后来从事金融。年轻时还是运动员，由于超重有心脏风险转而对健康感兴趣。全书文笔好，内容丰富全面，引用大量参考文献。"
  },
  {
    "name": "《长寿的习惯》",
    "finish_date": "2025年7月16日",
    "author": "【日】铃木祐",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "更通俗"
  },
  {
    "name": "《健康长寿：延缓衰老的科学与行动》",
    "finish_date": "2025年7月16日",
    "author": "科林•罗斯",
    "publisher":"",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": "作者不是科班出身，但健康、营养、科学、学习方面有著书立说。对于入门来说，值得一看。"
  },
  {
    "name": "《营养方向别跑偏》",
    "finish_date": "2025年7月12日",
    "author": "夏萌",
    "publisher":"",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": "作者是北京安贞医院老医生，也是中国首批营养学医生。书既覆盖了专业教科书内容，还浅显易懂。"
  },
  {
    "name": "《抗老生活》",
    "finish_date": "2025年7月8日",
    "author": "【日】池谷敏郎",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "作者是一位医生。书短小，但内容不短小，适合入门。人啊，是该考虑抵抗衰老了。"
  },
  {
    "name": "《征服世界完全手册》",
    "finish_date": "2025年7月6日",
    "author": "瑞安•诺思",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "围绕“成为超级大反派”这个命题，娓娓而谈科技、社会形态等"
  },
  {
    "name": "《我们为什么要睡觉》",
    "finish_date": "2025年6月29日",
    "author": "马修•沃克",
    "publisher":"",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": "作者是哈佛大学、加州大学伯克利分校的教授，发表论文超过100片。全书内容翔实，论据丰富，全文都有论文支持。"
  },
  {
    "name": "《亮剑》",
    "finish_date": "2025年6月28日",
    "author": "都梁",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "一声长叹"
  },
  {
    "name": "《光荣与梦想》",
    "finish_date": "2025年6月21日",
    "author": "刘慈欣",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": "奥运比赛替代战争"
  },
  {
    "name": "《军事地形学与定向越野》",
    "finish_date": "2025年3月8日",
    "author": "胡允达",
    "publisher":"武汉大学出版社",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "拓宽知识面。学到了如何使用地图、如何越野。"
  },
  {
    "name": "《治安疏》",
    "finish_date": "2025年3月1日",
    "author": "海瑞",
    "publisher":"",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": "怪不得道长看完气炸了。“嘉靖者言家家皆净”、“数十年君道之误”"
  },
 {
    "name": "《战斗圣经》4本",
    "finish_date": "2024年12月22日",
    "author": "上田 信",
    "publisher":"星光出版社",
    "score": "❤❤❤❤",
    "notes":"每页都是知识点，没有读书笔记",
    "comments": "从未接触过的领域，读得津津有味。用漫画形式全面、浅显地讲解了步兵的种种知识，从如何挖战壕到反恐，从防具到地雷布置，内容具体，实用性强。"
  },
{
  "name": "《半色调信息隐藏与防伪技术》",
  "finish_date": "2024年9月13日",
  "author": "曹鹏",
  "publisher":"电子工业出版社",
  "score": "❤",
  "notes":"",
  "comments": "东拼西凑的缝合怪，却能让我随机漫步到一个个从未到过的美丽之地"
  },
  {
  "name": "《太白金星有点烦》",
  "finish_date": "2024年8月28日",
  "author": "马伯庸",
  "publisher":"",
  "score": "❤❤❤❤",
  "notes":"",
  "comments": "小说的价值是什么？它可以让你在几天内经历另一个人的一生，获得另一个人的人生经验。这本小说就是如此，它让你在几天内体验一个大罗金仙级办公室主任的工作"
  },
  {
  "name": "《饥饿的盛世：乾隆时代的得与失》",
  "finish_date": "2024年6月2日",
  "author": "张宏杰",
  "publisher":"湖南人民出版社",
  "score": "❤❤❤❤",
  "notes":"",
  "comments": "看看这个盛世，这个带血的盛世、奴役的盛世、饥饿的盛世"
  },
  {
  "name": "《普京传》",
  "finish_date": "2024年5月18日",
  "author": "王国章",
  "publisher":"台海出版社",
  "score": "❤❤❤",
  "notes":"",
  "comments": "想浅要了解一下可以翻一翻"
  },
  {
  "name": "《重口味心理学：怎样证明你不是神经病？》",
  "finish_date": "2024年5月12日",
  "author": "姚尧",
  "publisher":"湖南文艺出版社",
  "score": "❤❤❤",
  "notes":"",
  "comments": "入门级读物，用故事简要介绍一些变态心理学的病症"
  },
  {
  "name": "《叫魂：1768年中国妖术大恐慌》",
  "finish_date": "2024年2月16日",
  "author": "【美】孔飞力",
  "publisher":"三联书店",
  "score": "❤❤❤❤",
  "notes":"",
  "comments": "皇帝、官僚集团、民众之间相互作用的社会生态，促成一个影响全社会的事件"
  },
  {
  "name": "《数字音频水印技术及应用》",
  "finish_date": "2023年12月15日",
  "author": "刘海燕",
  "publisher":"清华大学出版社",
  "score": "❤❤❤",
  "notes":"",
  "comments": ""
  },
  {
  "name": "《创新公司：皮克斯的启示》",
  "finish_date": "2023年12月10日",
  "author": "卡特姆,华莱士",
  "publisher":"中信出版社",
  "score": "❤❤❤",
  "notes":"",
  "comments": "作者作为技术大拿，发明了很多现在还在用的计算机图形学技术。皮克斯的管理经验，关于如何管理创意性团队的心得。"
  },
  {
    "name": "《癌症密码》",
    "finish_date": "2023年12月1日",
    "author": "杰森冯",
    "publisher":"北京联合出版公司",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": "癌症范氏经过3次迭代。癌细胞“返祖”，激活了远古的记忆，化身为单细胞生物，开始无节制的增殖"
  },
  {
    "name": "《稀缺》",
    "finish_date": "2023年11月19日",
    "author": "塞德希尔·穆来纳森",
    "publisher":"湛庐文化",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "稀缺消耗头脑的带宽，从而让表现更差，形成恶性循环"
  },
  {
    "name": "《抱住棒棒的自己》",
    "finish_date": "2023年11月7日",
    "author": "徐慢慢心里话",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": "和情绪对话"
  },
  {
    "name": "《每天懂点买房风水学·居家装修学·生活创意学》",
    "finish_date": "2023年6月21日",
    "author": "焦清平",
    "publisher":"新世界",
    "score": "❤❤❤",
    "notes":"",
    "comments": "内容很全面"
  },
  {
    "name": "《不扔东西的整理术》",
    "finish_date": "2023年6月15日",
    "author": "【日】米田玛丽娜",
    "publisher":"花山文艺出版社",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "设计一个机制，使日常使用也弄不乱，这样的整理才是比较好的"
  },
  {
    "name": "《小家，越住越大》",
    "finish_date": "2023年6月11日",
    "author": "逯薇",
    "publisher":"中信出版集团",
    "score": "❤❤❤",
    "notes":"",
    "comments": "收纳、玄关、厨房"
  },
  {
    "name": "《打造让孩子自主学习的住宅》",
    "finish_date": "2023年6月4日",
    "author": "四十万靖、渡边朗子",
    "publisher":"清华大学出版社",
    "score": "❤❤",
    "notes":"",
    "comments": "房屋的格局方便孩子和父母的交流"
  },
  {
    "name": "《人生护城河》",
    "finish_date": "2023年6月3日",
    "author": "张辉",
    "publisher":"人民邮电出版社",
    "score": "❤❤",
    "notes":"",
    "comments": "人生有限公司。三种收入。第三空间"
  },
  {
    "name": "《改变未来的九大算法》",
    "finish_date": "2023年5月5日",
    "author": "约翰·麦考密克",
    "publisher":"中信出版社",
    "score": "❤❤",
    "notes":"",
    "comments": "搜索引擎索引，PageRank，RSA，纠错码，图片识别，数据压缩，数据库，数据库，数字签名，不存在的算法"
  },
  {
    "name": "《买房让日本人幸福了吗？》",
    "finish_date": "2023年5月1日",
    "author": "【日】榊淳司",
    "publisher":"上海译文出版社",
    "score": "❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《网络空间安全导论》",
    "finish_date": "2023年4月22日",
    "author": "",
    "publisher":"机械工业出版社",
    "score": "❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《c语言接口与实现》",
    "finish_date": "2023年4月15日",
    "author": "",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": "讲的是各种数据结构，感觉还可以重读"
  },
  {
    "name": "《c和指针》",
    "finish_date": "2023年4月8日",
    "author": "Kenneth Reek",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《小王子》",
    "finish_date": "2023年2月6日",
    "author": "",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《骆驼祥子》",
    "finish_date": "2023年1月15日",
    "author": "老舍",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "雨下给富人，也下给穷人；下给义人，也下给不义的人。其实，雨并不公道，因为下落在一个没有公道的世界上。"
  },
  {
    "name": "《基于BERT模型的自然语言处理实战》",
    "finish_date": "2023年1月8日",
    "author": "李金洪",
    "publisher":"电子工业出版社出版",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "讲解系统、细致，但有些代码效果不理想"
  },
  {
    "name": "《加速：从拖延到高效，过三倍速度人生》",
    "finish_date": "2022年12月19日",
    "author": "",
    "publisher":"",
    "score": "❤❤",
    "notes":"",
    "comments": "鸡汤，但有些肉丁"
  },
  {
    "name": "《半小时漫画必背古诗词》",
    "finish_date": "2022年11月24日",
    "author": "",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": "讲了古诗词各流派，还讲了其历史背景"
  },
  {
    "name": "《半小时漫画三国演义》",
    "finish_date": "2022年11月19日",
    "author": "",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "纪录片《人类宇宙》",
    "finish_date": "2022年11月20日",
    "author": "Stephen Cooter",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《半小时漫画世界名著》",
    "finish_date": "2022年11月16日",
    "author": "",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "推荐！不仅仅是介绍名著剧情，更多的是介绍其历史背景、影响"
  },
  {
    "name": "电视剧《走向共和》",
    "finish_date": "2022年8月22日",
    "author": "",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "纪录片《铁血二战》",
    "finish_date": "2022年11月22日",
    "author": "CCTV",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "对二战过程有基本的认识了"
  },
  {
    "name": "《编写高质量代码：改善Python程序的91个建议》",
    "finish_date": "2022年11月2日",
    "author": "张颖",
    "publisher":"机械工业出版社",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《漫画算法：小灰的算法之旅》",
    "finish_date": "2022年10月30日",
    "author": "苏杰",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《贫穷的本质》",
    "finish_date": "2022年9月11日",
    "author": "阿比吉特班纳吉",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《最重要的事，只有一件》",
    "finish_date": "2022年8月28日",
    "author": "凯勒",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《信息安全导论》",
    "finish_date": "2022年8月26日",
    "author": "杨种学",
    "publisher":"",
    "score": "❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《极简主义改变了我》",
    "finish_date": "2022年7月12日",
    "author": "乔舒亚贝克尔",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "极简主义"
  },
  {
    "name": "《网上遗产》",
    "finish_date": "2022年5月28日",
    "author": "卡斯凯特",
    "publisher":"",
    "score": "❤❤",
    "notes":"",
    "comments": "知识密度不大。不过有两个优点：像散文一样娓娓道来，多情感叙事；话题引人思考。"
  },
  {
    "name": "《人人都是产品经理》",
    "finish_date": "2022年5月22日",
    "author": "苏杰",
    "publisher":"",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "好书"
  },
  {
    "name": "电视剧《大明王朝1566》",
    "finish_date": "2021年8月1日",
    "author": "刘和平",
    "publisher":"",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
    "name": "《大明王朝1566》",
    "finish_date": "2022年5月13日",
    "author": "刘和平",
    "publisher":"",
    "score": "❤❤❤❤❤",
    "notes":"",
    "comments": "看了两遍电视剧，又看了一遍书"
  },
  {
    "name": "《自然语言处理入门》",
    "finish_date": "2022年4月30日",
    "author": "何晗",
    "publisher":"人民邮电出版社",
    "score": "❤❤❤❤",
    "notes":"",
    "comments": "HanLP相关的算法，例如分词、词性标注、NER等"
  },
  {
    "name": "《活着》",
    "finish_date": "2022年1月27日",
    "author": "余华",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": "主角富贵是地主家的儿子。赌光家产（龙二设局骗光），沦为贫农。遭遇国民党抓壮丁，战友春生，还好是炮兵，没死，被俘后回家，发现母亲因病去世，女儿凤霞发烧变聋哑。土改，龙二成了替死鬼。儿子有庆给县长春生献血而死。凤霞难产死了，女婿二喜在工地出事死了，外孙苦根夭折。只剩富贵一个人。"
  },
  {
    "name": "《西方博弈往事》",
    "finish_date": "2022年1月27日",
    "author": "",
    "publisher":"",
    "score": "❤❤❤",
    "notes":"",
    "comments": ""
  },
  {
  "name": "《武器百科全书》",
  "author": "",
  "publisher":"华侨出版社",
  "finish_date": "2021年1月03日",
  "score": "❤❤❤",
  "comments": "百科全书"
},
{
  "name": "《闪电增肌》",
  "author": "",
  "publisher":"中国工信出版社",
  "finish_date": "2021年1月18日",
  "score": "❤❤❤",
  "comments": "百科全书"
},
{
  "name": "《坦克百年上：铁马嘶鸣》",
  "author": "邓涛",
  "publisher":"机械工业出版社",
  "finish_date": "2021年2月3日",
  "score": "❤❤❤❤",
  "comments": "这本书好在不只是讲坦克，而是讲每个型号的坦克被设计成这个样子，背后的社会、政治、地理原因。例如，早期的英国的海军传统，使坦克按照“陆上巡洋舰”甚至“无畏舰”来设计，最后英国坦克的风格是重视装甲，机动和火控不行。苏联军人意志力很强，所以牺牲乘员舒适度，提高坦克的综合性能。法国因为国力衰弱，指望重型坦克的视觉冲击力提升威望。意大利为了转移大萧条后的矛盾，不顾战争和经济状况错位，侵略埃塞俄比亚和武装干涉西班牙，损失大量的储备，导致二战坦克很差。"
},
{
  "name": "《坦克百年下：变化中的乾坤》",
  "author": "邓涛",
  "publisher":"机械工业出版社",
  "finish_date": "2021年3月1日",
  "score": "❤❤❤❤",
  "comments": "而德国由于政治原因，导致火炮性能过剩，导致底盘设计困难重重，又因为工业基础雄厚，所以技术路线越来越偏。美国长期缺乏战争经验，坦克纸上谈兵，又有深厚的工业能力，造了很多奇葩。以色列兵源珍贵、要打巷战，所以防御极高。瑞典纵深防御战略，设计了非常适合瑞典地形的坦克。"
},
{
  "name": "《体能训练理论与方法》",
  "author": "赵琦",
  "publisher":"东南大学出版社",
  "finish_date": "2021年3月3日",
  "score": "❤❤❤❤",
  "comments": "教科书"
},
{
  "name": "《大话重构》",
  "author": "范钢",
  "publisher":"人民邮电出版社",
  "finish_date": "2021年3月16日",
  "score": "❤❤❤",
  "comments": "作者确实在认真思考，认真编程，认真重构"
},
{
  "name": "《Python自然语言处理》",
  "author": "【印度】Jalaj.Thanaki",
  "publisher":"机械工业出版社",
  "finish_date": "2021年5月3日",
  "score": "❤❤❤",
  "comments": "前半部分不错，后半部分有些虚。"
},
{
  "name": "《NLTK基础教程》",
  "author": "【印度】Nitin.Hardeniya",
  "publisher":"人民邮电出版社",
  "finish_date": "2021年5月6日",
  "score": "❤❤❤❤",
  "comments": "干货多。"
},
{
  "name": "《重新定义公司》",
  "author": "【美】埃里克",
  "publisher":"中信出版社",
  "finish_date": "2021年7月18日",
  "score": "❤❤❤❤",
  "comments": "谷歌是如何做的"
},
{
  "name": "《美妙的新世界》",
  "author": "阿道司赫胥黎",
  "publisher":"译林出版社",
  "finish_date": "",
  "score": "❤❤❤",
  "comments": ""
},
{
  "name": "《潜规则》",
  "author": "吴思",
  "publisher":"复旦大学出版社",
  "finish_date": "2021年10月1日",
  "score": "❤❤❤❤",
  "comments": "好书。黑暗的封建社会，潜规则就像有机体一样，腐蚀整个国家。"
},
{
  "name": "《血酬定律》",
  "author": "吴思",
  "publisher":"复旦大学出版社",
  "finish_date": "2021年10月3日",
  "score": "❤❤❤❤",
  "comments": "吴思的三部曲之二。比《潜规则》更深入分析，从天子、官僚、庶民以及其它部分的各自视角和整体视角揭露封建社会的底层潜规则。"
},
{
  "name": "《岂不怀归：三和青年调查》",
  "author": "田丰",
  "publisher":"",
  "finish_date": "2021年10月7日",
  "score": "❤❤❤❤",
  "comments": "有这么一个群落"
},
{
  "name": "《海盗经济学》",
  "author": "彼得里森",
  "publisher":"",
  "finish_date": "2021年10月29日",
  "score": "❤❤❤❤",
  "comments": "民主和专制，没有哪一个更好，只有哪一个更适合。在特定客观的要求下，海盗团伙的最佳制度是民主，商船的最佳制度是专制。"
},
{
  "name": "《浪潮之巅》",
  "author": "吴军",
  "publisher":"人民邮电出版社",
  "finish_date": "2021年12月24日",
  "score": "❤❤❤❤❤",
  "comments": "前半部分讲了AT&T、IBM等响当当的企业的兴衰史，后半部分讲了其背后的学术环境、金融操作。"
},
{
  "name": "《格局》",
  "author": "吴军",
  "publisher":"",
  "finish_date": "2021年10月29日",
  "score": "❤❤",
  "comments": "鸡汤，不推荐。"
},
{
  "name": "《数据安全-架构设计与实战》",
  "author": "郑云文",
  "publisher":"",
  "finish_date": "2021年10月1日",
  "score": "❤❤",
  "comments": "入门科普"
},
{
  "name": "《富甲美国》",
  "author": "",
  "publisher":"江苏凤凰文艺出版社",
  "finish_date": "2020年1月31日",
  "score": "❤❤❤",
  "comments": "又名《促销的本质》，沃尔玛创始人山姆沃尔顿自传。优点是行文质量很高，缺点是细节太多，有点儿流水账。部分内容压缩到笔记库中了。"
},
{
  "name": "《精力管理》",
  "author": "Jim Loehr, Tony Schwartz",
  "publisher":"中国青年出版社",
  "finish_date": "2020年2月5日",
  "score": "❤❤❤❤",
  "comments": "知识密度没有预想的那么高，但整体还不错。"
},
{
  "name": "《知识图谱：方法、实践与应用》",
  "author": "王昊奋",
  "publisher":"中国工信出版社",
  "finish_date": "2020年4月22日",
  "score": "❤❤❤",
  "comments": "作为入门书和词典都不错。"
},
{
  "name": "《消失的殖民星球》",
  "author": "斯卡尔齐",
  "publisher":"",
  "finish_date": "2020年5月4日",
  "score": "❤❤❤❤",
  "comments": "2008年雨果奖最佳、轨迹奖两项提名，并获得2010年日本星云奖。一个被抛弃的殖民星。"
},
{
  "name": "《十次危机》",
  "author": "温铁军",
  "publisher":"",
  "finish_date": "2020年6月7日",
  "score": "❤❤❤❤❤",
  "comments": "思想偏向国家主义。建国后的很多事情可以用经济现象来解释。看完后对建国后的经济史有深入了解了，内容比《激荡三十年》和《跌宕一百年》更深入。"
},
{
  "name": "《漫画人体——一看就懂的人体结构书》",
  "author": "【日】坂井建雄",
  "publisher":"电子工业出版社",
  "finish_date": "2020年10月26日",
  "score": "❤❤❤❤❤",
  "comments": "讲解清晰，插图明了，内容专业。"
},
{
  "name": "《你的呼吸还好吗？：会呼吸才能不生病》",
  "author": "王涛",
  "publisher":"中国人口出版社",
  "finish_date": "2020年10月31日",
  "score": "❤❤",
  "comments": "一般般的书，很多内容没有科学内容。不过学到了龟息法这个概念。"
},
{
  "name": "《越野行走终极指南》",
  "author": "克劳斯施万贝克",
  "publisher":"人民邮电出版社",
  "finish_date": "2020年10月31日",
  "score": "❤❤",
  "comments": "学到了一种新的锻炼方法。书本前几十页讲方法，后面大篇幅都在讲好处。"
},
{
  "name": "《大脑使用指南》",
  "author": "赵思家",
  "publisher":"湖南科技出版社",
  "finish_date": "2020年11月7日",
  "score": "❤❤❤❤❤",
  "comments": "作者是伦敦大学神经科学博士神经科学专家，书本的趣味性、专业性都极佳，值得一看。"
},
{
  "name": "《爱因斯坦大脑》",
  "author": "探秘天下编写组",
  "publisher":"时事出版社",
  "finish_date": "2020年11月8日",
  "score": "❤❤",
  "comments": "几十个“小百科”堆出来的“大杂烩”"
},
{
  "name": "《大脑，你在忙什么？》",
  "author": "徐刚",
  "publisher":"天津科学技术出版社",
  "finish_date": "2020年11月8日",
  "score": "❤❤",
  "comments": "同上，也是几十个“小百科”堆出来的“大杂烩”"
},
{
  "name": "《信息隐藏技术：隐写术与数字水印》",
  "author": "S.Katzenbeisser",
  "publisher":"人民邮电出版社",
  "finish_date": "2020年11月31日",
  "score": "❤❤❤",
  "comments": "中文翻译不太行"
},
{
  "name": "《男性肌肉与力量训练指南》",
  "author": "Stephen Cabral",
  "publisher":"人民邮电出版社",
  "finish_date": "2020年12月5日",
  "score": "❤❤",
  "comments": ""
},
{
  "name": "《力量训练原理与实践》",
  "author": "Michael H. Stone",
  "publisher":"人民体育出版社",
  "finish_date": "2020年12月5日",
  "score": "❤❤❤❤❤",
  "comments": "经典教材果然好！"
},
{
  "name": "《低智商社会》",
  "author": "大前研一",
  "publisher":"",
  "finish_date": "2019年1月2日",
  "score": "❤❤❤",
  "comments": "大前研一是不是对日本国民素质的要求太高了？"
},
{
  "name": "《菊与刀》",
  "author": "【美】鲁思·本尼迪克特",
  "publisher":"",
  "finish_date": "2019年1月9日",
  "score": "❤❤❤❤",
  "comments": "系统而细致的介绍文化差异。这本书告诉我，很多文化现象在当事人看来理所当然，在外人看来简直不可理喻，细致研究会发现其形成逻辑。"
},
{
  "name": "《低欲望社会》",
  "author": "大前研一",
  "publisher":"上海译文出版社",
  "finish_date": "2019年1月12日",
  "score": "❤❤❤",
  "comments": "《低智商社会》和《低欲望社会》描述的现象和产生条件都与中国现状大不相同，无须过于套用。然而书对中国很有价值，指导未来避雷。"
},
{
  "name": "《人类简史》",
  "author": "尤瓦尔赫拉利",
  "publisher":"中信出版社",
  "finish_date": "2019年1月15日",
  "score": "❤❤❤❤❤",
  "comments": "这本书太厉害了。写了一万多字的读书笔记。"
},
{
  "name": "《未来简史》",
  "author": "尤瓦尔赫拉利",
  "publisher":"中信出版社",
  "finish_date": "2019年1月25日",
  "score": "❤❤❤❤❤",
  "comments": "相当推荐。"
},
{
  "name": "《今日简史》",
  "author": "尤瓦尔赫拉利",
  "publisher":"中信出版社",
  "finish_date": "2019年2月7日",
  "score": "❤❤❤❤❤",
  "comments": "一口气看完三部曲。这本书仍然五星好评，建议大家去看看原书。"
},
{
  "name": "《神们自己》",
  "author": "阿西莫夫",
  "publisher":"江苏凤凰文艺出版社",
  "finish_date": "2019年2月10日",
  "score": "❤❤❤❤",
  "comments": "电子通道、三性物种。"
},
{
  "name": "《数据造假理论》",
  "author": "罗云夫",
  "publisher":"",
  "finish_date": "2019年2月19日",
  "score": "❤❤❤",
  "comments": "知己知彼"
},
{
  "name": "《佛祖都说了些什么》",
  "author": "林欣浩",
  "publisher":"北京时代华文书局",
  "finish_date": "2019年2月22日",
  "score": "❤❤❤❤❤",
  "comments": "五星好评！十分精彩！“书本被书名耽误”系列。不但了解了中国佛教各派的思想，还了解了儒释道在中国的演变，最后回到唯物史观。现代人的高维度去俯视思想变迁。"
},
{
  "name": "《思考的艺术》",
  "author": "文森特•赖安•拉吉罗",
  "publisher":"机械工业出版社",
  "finish_date": "2019年2月27日",
  "score": "❤❤❤",
  "comments": "对我个人来说知识密度并不大，还是有一些有用的点。"
},
{
  "name": "《学会提问》",
  "author": "【美】 尼尔·布朗， 斯图尔特·基利",
  "publisher":"机械工业出版社",
  "finish_date": "2019年3月1日",
  "score": "❤❤❤❤❤",
  "comments": "五星好评，可以重读。"
},
{
  "name": "《批判性思维工具》",
  "author": "理查德·保罗，琳达·埃尔德",
  "publisher":"机械工业出版社",
  "finish_date": "2019年3月9日",
  "score": "❤❤❤",
  "comments": "有些章节很精彩。"
},
{
  "name": "《erp项目管理散记》",
  "author": "田俊国",
  "publisher":"清华大学出版社",
  "finish_date": "2019年3月10日",
  "score": "❤❤",
  "comments": "书很薄，内容有点儿老"
},
{
  "name": "《成大事者不纠结》",
  "author": "罗振宇",
  "publisher":"北京联合出版公司",
  "finish_date": "2019年3月12日",
  "score": "❤❤❤",
  "comments": "“过往不恋，当下不杂，未来不迎”不再是一个口号，而是变成有血有肉的故事。"
},
{
  "name": "《失控》",
  "author": "凯文凯利",
  "publisher":"中信出版社",
  "finish_date": "2019年3月12日",
  "score": "❤❤❤❤❤",
  "comments": "作为一本1994年的书，非常有洞察力。书本涉猎计算机、生态学、控制论、人工智能等。"
},
{
  "name": "《必然》",
  "author": "凯文凯利",
  "publisher":"中信出版社",
  "finish_date": "2019年3月23日",
  "score": "❤❤❤❤❤",
  "comments": "对科技、生态、复杂学有了更深的认识"
},
{
  "name": "《科技想要什么》",
  "author": "凯文凯利",
  "publisher":"中信出版社",
  "finish_date": "2019年3月27日",
  "score": "❤❤❤❤❤",
  "comments": "一次大的认知升级。宇宙、生物、科技的演化一脉相承，有很强的必然性。"
},
{
  "name": "《100个受欢迎的礼仪细节》",
  "author": "",
  "publisher":"上海科学普及出版社",
  "finish_date": "2019年3月28日",
  "score": "❤❤",
  "comments": "细节"
},
{
  "name": "《数字化生存》",
  "author": "Nicholas Negroponte",
  "publisher":"",
  "finish_date": "2019年3月28日",
  "score": "❤❤❤❤",
  "comments": "1996年出版，20年前读它，是科幻书，现在读它，是历史书"
},
{
  "name": "《原则》",
  "author": "瑞·达利欧",
  "publisher":"中信出版社",
  "finish_date": "2019年4月11日",
  "score": "❤❤❤❤❤",
  "comments": "耐心看完第一章，你会发现后面全是高能内容。我以前模模糊糊的认识到的一些东西，作者条分缕析全给写出来了。独立思考、极度开放。"
},
{
  "name": "《共产党宣言》",
  "author": "马克思，恩格斯",
  "publisher":"",
  "finish_date": "2019年4月12日",
  "score": "❤❤❤❤❤",
  "comments": "一个幽灵..."
},
{
  "name": "《轻断食》",
  "author": "【英】莫斯利，【英】史宾赛",
  "publisher":"广东科技出版社",
  "finish_date": "2019年4月14日",
  "score": "❤❤❤",
  "comments": "3月份减重20斤，怕减肥方法不科学引发健康问题，所以看这本书。作者很权威，值得看。"
},
{
  "name": "《半小时漫画世界史》",
  "author": "陈磊（笔名：二混子）",
  "publisher":"江苏凤凰文艺出版社",
  "finish_date": "2019年4月17日",
  "score": "❤❤❤❤❤",
  "comments": "对于想快速了解历史的理科生来说，非常适合的。"
},
{
  "name": "《半小时漫画中国史》",
  "author": "陈磊（笔名：二混子）",
  "publisher":"江苏凤凰文艺出版社",
  "finish_date": "2019年4月18日",
  "score": "❤❤❤❤",
  "comments": "挺好，这个系列都挺不错"
},
{
  "name": "《哲学家们都干了些什么》",
  "author": "林欣浩",
  "publisher":"",
  "finish_date": "2019年4月24日",
  "score": "❤❤❤❤❤",
  "comments": "听到拍案叫绝的思想，不再只是膜拜。而是直接分门别类到一个体系树中，瞬间想起其代表观点的主要推论、主要主张、主要缺陷，然后反过来对比这个思想和体系树中经典思想的区别。"
},
{
  "name": "《哇，历史原来可以这样学》",
  "author": "林欣浩",
  "publisher":"",
  "finish_date": "2019年4月25日",
  "score": "❤❤❤❤",
  "comments": "林欣浩写的书。"
},
{
  "name": "《苏菲的世界》",
  "author": "【挪】贾德",
  "publisher":"",
  "finish_date": "2019年5月3日",
  "score": "❤❤❤❤❤",
  "comments": "五星好评。"
},
{
  "name": "《一九八四》",
  "author": "乔治·奥威尔(George Orwell)",
  "publisher":"上海译文出版社",
  "finish_date": "2019年5月5日",
  "score": "❤❤❤❤❤",
  "comments": "经典反乌托邦小说。战争即和平，自由即奴役，无知即力量。"
},
{
  "name": "《西方哲学十五讲》",
  "author": "张志伟",
  "publisher":"北京大学出版社",
  "finish_date": "2019年5月18日",
  "score": "❤❤❤❤❤",
  "comments": "从2012年开始看，到2019年才看完，前后断断续续看了7年。看完以后才知道，哲学，无论花多少时间去学习都是值得的。"
},
{
  "name": "《经济学通识》",
  "author": "薛兆丰",
  "publisher":"北京大学出版社",
  "finish_date": "2019年5月19日",
  "score": "❤❤❤❤❤",
  "comments": "经济学往往会让你和朋友产生不可逆的观念隔阂，你事先要有思想准备，事后要有敷衍对策，由此产生的代价，经济学概不负责。"
},
{
  "name": "《基业长青》",
  "author": "吉姆柯林斯",
  "publisher":"中信出版社",
  "finish_date": "2019年7月4日",
  "score": "❤❤❤❤",
  "comments": "说实话，没太get到这本书的关键观点。"
},
{
  "name": "《明智行动的艺术：成功决策必须避免的52个思维陷阱》",
  "author": "【德】罗尔夫•多贝里",
  "publisher":"中信出版社",
  "finish_date": "2019年7月5日",
  "score": "❤❤❤❤❤",
  "comments": "相当好的书，可以多读几遍。"
},
{
  "name": "《反脆弱》",
  "author": "塔勒布",
  "publisher":"",
  "finish_date": "2019年7月9日",
  "score": "❤❤❤❤❤",
  "comments": "值得读，还没理解透，有空二刷。"
},
{
  "name": "《心理学十五讲》",
  "author": "黄希庭",
  "publisher":"北京大学出版社",
  "finish_date": "2019年7月13日",
  "score": "❤❤❤❤❤",
  "comments": "体系完善，讲解权威，信息量大。如果你像我一样刚开始学心理学，我建议你第一本读这个，事半功倍。"
},
{
  "name": "《复杂》",
  "author": "梅拉妮·米歇尔",
  "publisher":"湖南科学技术出版社",
  "finish_date": "2019年7月17日",
  "score": "❤❤❤❤❤",
  "comments": "好书，主要讲复杂学、复杂网络、算法、混沌等。复杂系统会“涌现”出新特性。 "
},
{
  "name": "《欧洲文明十五讲》",
  "author": "陈乐民",
  "publisher":"北京大学出版社",
  "finish_date": "2019年7月18日",
  "score": "❤❤❤",
  "comments": "读着像是授课内容整理出来的。没能吸取到太多的信息。"
},
{
  "name": "《认知盈余：自由时间的力量》",
  "author": "克莱·舍基",
  "publisher":"北京联合出版公司",
  "finish_date": "2019年7月19日",
  "score": "❤❤❤",
  "comments": "人类现在有了更多的时间。书一般。"
},
{
  "name": "《格调》",
  "author": "保罗·福塞尔",
  "publisher":"北京联合出版公司",
  "finish_date": "2019年8月11日",
  "score": "❤❤❤",
  "comments": "前半部分不错，后半部分很多细节"
},
{
  "name": "《赡养人类》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2019年9月1日",
  "score": "❤❤❤❤❤",
  "comments": "大刘的小说还漏掉这一本没看。讲的是赡养上帝的故事之后，杀手滑膛的见闻。“终产者”的概念来源于这本书。"
},
{
  "name": "《自私的基因》",
  "author": "【美】理查德道金斯",
  "publisher":"",
  "finish_date": "2019年9月14日",
  "score": "❤❤❤❤❤",
  "comments": "神作。作为一本1976年的书，在之前认真看完几本关于进化论的书的前提下，竟然还很有收获。最大收获是从基因相似度的角度建立博弈问题，以此解释了很多现象。"
},
{
  "name": "《有效写作十三篇》",
  "author": "王烁",
  "publisher":"",
  "finish_date": "2019年9月26日",
  "score": "❤❤❤❤❤",
  "comments": "1）绝不要使用在印刷物中经常看到的隐喻、明喻和其他修辞手法 2.）如果一个词能说清，绝不用两个词 3）但凡一个字能删掉，一定要删掉 4）能用主动语态，绝不用被动语态 5）能用常用词，不要用外来词、科学术语和行话 6）绝不要用粗俗的语言，为此可以打破上面任一规则。"
},
{
  "name": "《每天懂点谈判心理学》",
  "author": "舒雪冬",
  "publisher":"",
  "finish_date": "2019年9月26日",
  "score": "❤❤❤",
  "comments": "有点儿水，这书。"
},
{
  "name": "《情商》",
  "author": "丹尼尔戈尔曼",
  "publisher":"",
  "finish_date": "2019年10月01日",
  "score": "❤❤❤❤❤",
  "comments": "口碑好的书果然值得读，这本书以后还可以多读几次。"
},
{
  "name": "《枪炮、病菌与钢铁》",
  "author": "【美】贾雷德戴蒙德",
  "publisher":"",
  "finish_date": "2019年10月02日",
  "score": "❤❤❤❤❤",
  "comments": "书很好，细节很多。"
},
{
  "name": "《浩荡两千年》",
  "author": "吴晓波",
  "publisher":"中信出版社",
  "finish_date": "2019年10月03日",
  "score": "❤❤❤❤❤",
  "comments": "浩荡。值得读第二遍。"
},
{
  "name": "《全频带阻塞干扰》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2019年10月04日",
  "score": "❤❤❤❤",
  "comments": "遥远的宇宙和眼前的战争"
},
{
  "name": "《动物农场》",
  "author": "【英】乔治奥威尔",
  "publisher":"上海译文出版社",
  "finish_date": "2019年10月04日",
  "score": "❤❤❤❤",
  "comments": "农场的动物推翻了农场主之后..."
},
{
  "name": "《机器学习vs复杂系统》",
  "author": "许铁",
  "publisher":"中国工信出版集团",
  "finish_date": "2019年11月02日",
  "score": "❤❤❤",
  "comments": "浅显，有些章节有点儿意思。"
},
{
  "name": "《微粒社会》",
  "author": "克里斯多夫库克里克",
  "publisher":"中信出版社",
  "finish_date": "2019年11月05日",
  "score": "❤❤❤",
  "comments": "看一遍就行了"
},
{
  "name": "《卓有成效的管理者》",
  "author": "德鲁克",
  "publisher":"机械工业出版社",
  "finish_date": "2019年11月07日",
  "score": "❤❤❤❤❤",
  "comments": "好书名不虚传，抽空可以重读。"
},
{
  "name": "《改善Python程序的91个建议》",
  "author": "张颖、赖勇浩",
  "publisher":"机械工业出版社",
  "finish_date": "2019年12月31日",
  "score": "❤❤❤❤❤",
  "comments": "挺好的书，就是内容旧了。"
},
{
  "name": "《复杂-诞生于秩序与混沌边缘的科学》",
  "author": "米歇尔·沃尔德罗普",
  "publisher":"",
  "finish_date": "2018年1月6日",
  "score": "❤❤",
  "comments": "过多的对当事人的描述，整本书更像被大量细节淹没的纪录片。1. 报酬递增导致系统最终状态取决于最初状态的微小随机。2. 复杂程度低于阈值，相变不会发生。高于阈值，自动催化现象就变得不可避免"
},
{
  "name": "《电子商务》",
  "author": "许丽霞",
  "publisher":"阳光出版社",
  "finish_date": "2018年3月19日",
  "score": "❤",
  "comments": "加入京东，为了熟悉业务从Kindle买的。内容全且老，中规中矩，好在有助于对电商领域有个全面的认识。"
},
{
  "name": "《别让不懂职场礼仪害了你》",
  "author": "铅华",
  "publisher":"天津科学技术出版社",
  "finish_date": "2018年3月20日",
  "score": "❤❤",
  "comments": "一本礼仪手册，细节的罗列"
},
{
  "name": "《商战》",
  "author": "吴晓波",
  "publisher":"湖北教育出版社",
  "finish_date": "2018年3月25日",
  "score": "❤❤❤❤",
  "comments": "吴晓波的大作。写了近年电商领域发展历史，非常精彩"
},
{
  "name": "《Hive 编程指南》",
  "author": "",
  "publisher":"O'REILLY",
  "finish_date": "2018年3月28日",
  "score": "❤❤❤",
  "comments": "不错，Hive的使用是比较简单的，主要是 sql 查询语句，这本书的内容更深。"
},
{
  "name": "《Spark 快速大数据分析》",
  "author": "",
  "publisher":"O'REILLY",
  "finish_date": "2018年4月1日",
  "score": "❤❤❤",
  "comments": "Spark很强大，但这本书的翻译版不是。翻译版错误太多，并且这本书本身太老了，讲的是相当旧版本的 spark。"
},
{
  "name": "《电子商务：商务、技术、社会（第七版）》",
  "author": "Kenneth C. Laudon, Caroal Guercio Traver",
  "publisher":"中国人民大学出版社",
  "finish_date": "2018年4月8日",
  "score": "❤❤",
  "comments": "电子商务教科书，六百多页的大部头。仍然是为了熟悉京东业务而读，内容全面，篇章质量不错，就是有点老了"
},
{
  "name": "《人民的名义》",
  "author": "周梅森",
  "publisher":"中国人民大学出版社",
  "finish_date": "2018年4月17日",
  "score": "❤❤❤❤",
  "comments": "去年体彩给的书，今天才看完。不错的书"
},
{
  "name": "《电子商务：管理视角（第五版）》",
  "author": "Efraim Turban等",
  "publisher":"机械工业出版社",
  "finish_date": "2018年5月7日",
  "score": "❤❤",
  "comments": "为了熟悉电商业务买的，693页的大部头教科书，内容很全。作为一本老书很有洞见。"
},
{
  "name": "《应用多元统计分析（第二版）》",
  "author": "朱建平",
  "publisher":"科学出版社",
  "finish_date": "2018年5月11日",
  "score": "❤❤",
  "comments": "多元回归、PCA之类"
},
{
  "name": "《应用回归分析（第四版）》",
  "author": "何晓群",
  "publisher":"中国人民大学出版社",
  "finish_date": "2018年5月11日",
  "score": "❤❤",
  "comments": "回归模型"
},
{
  "name": "《从零进阶！数据分析的统计基础》",
  "author": "",
  "publisher":"电子工业出版社",
  "finish_date": "2018年5月11日",
  "score": "❤❤",
  "comments": "CDA教材，简单"
},
{
  "name": "《如虎添翼！数据处理的SPSS和SAS EG实现》",
  "author": "",
  "publisher":"电子工业出版社",
  "finish_date": "2018年5月11日",
  "score": "❤❤",
  "comments": "CDA教材，简单"
},
{
  "name": "《胸有成竹!数据分析的SPSS和SAS EG进阶》",
  "author": "",
  "publisher":"电子工业出版社",
  "finish_date": "2018年5月11日",
  "score": "❤❤",
  "comments": "CDA教材，简单"
},
{
  "name": "《数据、模型与决策》",
  "author": "David R. Anderson",
  "publisher":"机械工业出版社",
  "finish_date": "2018年5月28日",
  "score": "❤❤❤❤",
  "comments": "Literally 2013年开始看的书，今天才看完。美式风格的教材。线性规划、非线性规划、整数规划、库存模型、排队论、时间序列等知识的入门级介绍。"
},
{
  "name": "《消费者行为学》",
  "author": "符国群",
  "publisher":"高等教育出版社",
  "finish_date": "2018年5月29日",
  "score": "❤❤❤",
  "comments": ""
},
{
  "name": "《每个人都会死，但我总以为自己不会》",
  "author": "Thomas Cathcart / Daniel Klein",
  "publisher":"人民邮电出版社",
  "finish_date": "2018年6月12日",
  "score": "❤❤❤",
  "comments": "我们有灵魂吗？如果有的话，它会不会在肉体消亡后依然存在？它是由什么做成的？有高贵与卑贱之别吗？有没有一种时间范围能切断生死循环？恒久驻于此刻，这是否就是“永生”？天堂是时空中的存在吗？如果不是，它又在哪？什么时候出现？进入天堂的可能性会有多大？这本书用幽默的语言写了许多哲学家对死亡的思考"
},
{
  "name": "《富爸爸穷爸爸》",
  "author": "（美）罗伯特·清崎",
  "publisher":"四川出版集团",
  "finish_date": "2018年7月20日",
  "score": "❤❤❤",
  "comments": "财商启蒙书。分清个人意义上的资产和债务，而不是会计意义上的。资产是可以带来正现金流的东西，负债是带来负现金流的东西。要买入资产，不要买入负债"
},
{
  "name": "《微时间管理术》",
  "author": "彼得·布雷格曼",
  "publisher":"",
  "finish_date": "2018年7月24日",
  "score": "❤",
  "comments": "每天花5分钟反思今天，5分钟规划明天，每小时1分钟反思现在"
},
{
  "name": "《Github入门与实践》",
  "author": "【日】大塚弘记",
  "publisher":"人民邮电出版社",
  "finish_date": "2018年8月20日",
  "score": "❤❤❤❤",
  "comments": "2017年春季看完了主要部分，开源社区对我影响很大。今天看完了剩余三章"
},
{
  "name": "《数据结构-使用C语言》",
  "author": "朱站立",
  "publisher":"西安交通大学出版社",
  "finish_date": "2018年8月21日",
  "score": "❤❤❤",
  "comments": "这周为止，LeetCode刷完了200题，把这本书剩余的图、排序等部分也看完了。"
},
{
  "name": "《漫画统计学》",
  "author": "【日】高桥信",
  "publisher":"科学出版社",
  "finish_date": "2018年8月28日",
  "score": "❤❤❤",
  "comments": "漫画真好玩"
},
{
  "name": "Neural Networks and Deep Learning",
  "author": "Michael Nielsen",
  "publisher":"",
  "finish_date": "2018年10月17日",
  "score": "❤❤❤❤",
  "comments": "一本好书，前后读了一个多月，清晰易于理解且深刻。<a href ='http://michaelnielsen.org/'>作者的博客</a>，<a href ='http://neuralnetworksanddeeplearning.com/'>原书</a>，<a href ='https://github.com/tigerneil/neural-networks-and-deep-learning-zh-cn/'>翻译1</a>，<a href ='https://github.com/zhanggyb/nndl/'>翻译2</a>"
},
{
  "name": "Python机器学习",
  "author": "Sebastian Raschka",
  "publisher":"机械工业出版社",
  "finish_date": "2018年10月20日",
  "score": "❤❤❤",
  "comments": "会了再看很简单"
},
{
  "name": "TensorFlow机器学习实战指南",
  "author": "Nick McClure",
  "publisher":"机械工业出版社",
  "finish_date": "2018年10月25日",
  "score": "❤❤❤❤",
  "comments": "代码讲的相当好，可惜不太讲理论。<a href ='https://github.com/nfmcclure/tensorflow_cookbook/'>代码仓库</a>。亮点是除了神经网络以外，还用TensorFlow框架实现svm，knn这些算法，从而加强对TensorFlow使用的熟练度。"
},
{
  "name": "TensorFlow技术解析与实战",
  "author": "李嘉璇",
  "publisher":"中国工信出版集团",
  "finish_date": "2018年11月1日",
  "score": "❤❤❤",
  "comments": "有点杂，不过还是好书。<a href ='https://github.com/greatgeekgrace/Technical-Analysis-And-Practice-in-TensorFlow'>代码仓库</a>"
},
{
  "name": "TensorFlow实战Google深度学习框架",
  "author": "郑泽宇",
  "publisher":"中国工信出版社",
  "finish_date": "2018年11月2日",
  "score": "❤❤❤",
  "comments": "几本书掺杂着看，理解更快。"
},
{
  "name": "深度学习原理与TensorFlow实战",
  "author": "喻俨等",
  "publisher":"中国工信出版集团，电子工业出版社",
  "finish_date": "2018年11月20日",
  "score": "❤❤",
  "comments": "<a href ='https://github.com/DeepVisionTeam/TensorFlowBook'>代码仓库</a>"
},
{
  "name": "TensorFlow实战",
  "author": "黄文坚",
  "publisher":"中国工信出版集团，电子工业出版社",
  "finish_date": "2018年11月20日",
  "score": "❤❤",
  "comments": "<a href ='https://github.com/guofei9987/Tensorflow-/tree/master/tensorflow_in_action'>代码仓库</a>"
},
{
  "name": "异星歧途(The Road Not Taken)",
  "author": "哈利·托特达夫(Harry Turtledove)",
  "publisher":"",
  "finish_date": "2018年11月27日",
  "score": "❤❤❤❤",
  "comments": "八十亿疯狗出笼"
},
{
  "name": "《宇宙的琴弦》",
  "author": "B•格林",
  "publisher":"（第一推动图书）湖南科学技术出版社",
  "finish_date": "2018年12月8日",
  "score": "❤❤❤❤",
  "comments": "作者是理论物理学前沿理论“弦理论”的领军人物之一。虽然书看的似懂非懂，但看的很爽。合适的时间可以二刷。"
},
{
  "name": "《时间之箭》",
  "author": "（英）柯文尼",
  "publisher":"（第一推动图书）湖南科学技术出版社",
  "finish_date": "2018年12月19日",
  "score": "❤❤❤❤",
  "comments": "全书不仅仅讲了时间的箭头，而是顺便把整个物理体系和思想史梳理了一遍。非常不错（书的翻译真烂）"
},
{
  "name": "《圆圆的肥皂泡》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2018年12月20日",
  "score": "❤❤❤",
  "comments": "吹泡泡拯救西北的荒漠"
},
{
  "name": "《地火》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2018年12月21日",
  "score": "❤❤❤",
  "comments": "想要煤场变气田。被复杂的系统报复(大刘本人的父亲也在煤矿工作，而且主角叫刘欣)"
},
{
  "name": "《月夜》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2018年12月22日",
  "score": "❤❤❤❤",
  "comments": "科幻版的蝴蝶效应，一夜接到三次未来来的电话。拥有某种科技后，未必历史会更好。"
},
{
  "name": "《鲸歌》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2018年12月23日",
  "score": "❤❤❤",
  "comments": "故事很简单，毒贩控制鲸鱼去贩毒。结果鲸鱼和大毒枭遇到非法捕鲸船..."
},
{
  "name": "《带上她的眼睛》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2018年12月24日",
  "score": "❤❤❤❤",
  "comments": "刘慈欣的作品里，看的最压抑的一个。太空移民成为常态后，发明了这种产品：A带上一种设备，便可以让B看到自己的视野，升级版可以感受自己的触觉等。产品逻辑是B付给A一部分钱，省下一笔昂贵的星系旅行费用。有一天，主角接了一单..."
},
{
  "name": "《地球大炮》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2018年12月25日",
  "score": "❤❤❤❤",
  "comments": "挖穿地球的脑洞，《带上她的眼睛》续"
},
{
  "name": "《信使》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2018年12月26日",
  "score": "❤❤",
  "comments": "时间穿越者给爱因斯坦的临终关怀"
},
{
  "name": "《诗云》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2018年12月27日",
  "score": "❤❤❤",
  "comments": "《吞食者》的后续。吞食者离开后遇到神族，不得不折返地球。神族为了写诗，把太阳系的所有物质变成存储设备。剧情倒是跟“梦之海”相似。"
},
{
  "name": "《流浪地球》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2018年12月28日",
  "score": "❤❤❤❤",
  "comments": "人们发现太阳将会进入持续数千个人类历史的氦闪时代.书分为3个部分：逃逸、叛乱、流浪。"
},
{
  "name": "《如何高效学习》",
  "author": "【加】斯科特·杨",
  "publisher":"",
  "finish_date": "2018年12月29日",
  "score": "❤❤❤",
  "comments": "还不错"
},
{
  "name": "《终极算法》",
  "author": "佩德罗·多明戈斯",
  "publisher":"",
  "finish_date": "2017年12月30日",
  "score": "❤❤❤",
  "comments": "讨论终极算法实现的可能性。讲了机器学习的5个流派，符号学派、联结学派、进化学派、贝叶斯学派、类推学派。"
},
{
  "name": "《经度：一个孤独的天才解决他所处时代最大难题的真实故事》",
  "author": "达娃.索贝尔",
  "publisher":"",
  "finish_date": "2017年11月19日",
  "score": "❤❤",
  "comments": "纬度比较容易计算，经度就难了，计算经纬度是航海发展必须解决的问题。1. 伽利略等的观星理论。2. 仿狗学说（迷信），把伤狗带到船上，绷带放到陆地，每天中午用绷带泡一种溶剂，狗会叫。然后根据时差计算经度。3. 地磁北极、北极星、地轴北极有偏差，利用这个偏差计算经度。4. 约翰.哈里森，本书的主角，发明了精密计时的钟表，解决了经度问题。"
},
{
  "name": "《数量金融导论：数学工具箱》",
  "author": "",
  "publisher":"",
  "finish_date": "2017年8月10日",
  "score": "❤❤❤❤❤",
  "comments": "当做数学工具书看非常合适：没有太多废话，而是精炼的定义、定理，以及为何要提出这些概念。金融部分逻辑有点牵强，就当做没有。"
},
{
  "name": "《数据化管理》",
  "author": "",
  "publisher":"",
  "finish_date": "2017年7月12日",
  "score": "❤❤❤❤",
  "comments": "实体店、电商的数据分析法。案例详尽，知识全面，既有数据化，也讲管理。彩图印刷质量好。"
},
{
  "name": "《清醒思考的艺术》",
  "author": "",
  "publisher":"",
  "finish_date": "2017年10月18日",
  "score": "❤❤❤❤",
  "comments": "你最好让别人去犯的52种思维错误"
},
{
  "name": "《杜拉拉升职记3：我在这战斗的一年里》",
  "author": "",
  "publisher":"",
  "finish_date": "2017年10月10日",
  "score": "❤❤❤❤",
  "comments": "杜拉拉、沙当当等几个人换岗、跳槽的种种"
},
{
  "name": "《杜拉拉升职记2：华年似水》",
  "author": "",
  "publisher":"",
  "finish_date": "2017年10月8日",
  "score": "❤❤❤❤",
  "comments": "杜拉拉作为招聘经理的种种"
},
{
  "name": "《M型社会》",
  "author": "大前研一",
  "publisher":"中信出版社",
  "finish_date": "2017年10月5日",
  "score": "❤❤❤❤",
  "comments": "M型社会指的是中产阶级社会全面崩溃，富人和穷人都变多。此外，还涉及以下方面：企业如何应对，公民如何应对，一些不合理的经济结构（神户牛肉的偏见等）。提出了一些政治主张：1. 变成美国那样的地方制，使每个地方能够竞争2. 合理税制3. 培养人才4.改革行政单位"
},
{
  "name": "《杜拉拉升职记1：外企白领生存法则》",
  "author": "",
  "publisher":"",
  "finish_date": "2017年9月15日",
  "score": "❤❤❤❤",
  "comments": "三观正"
},
{
  "name": "《怪诞行为学》",
  "author": "Dan Ariely",
  "publisher":"中信出版社",
  "finish_date": "2017年8月4日",
  "score": "❤❤❤❤",
  "comments": "好书！"
},
{
  "name": "《学习敏捷：构建高效团队》",
  "author": "Andrew Stellman  Jennifer Greene",
  "publisher":"Oreilly",
  "finish_date": "2017年7月28日",
  "score": "❤❤❤",
  "comments": "不错的书，Oreilly风格"
},
{
  "name": "《悟空传》",
  "author": "今何在",
  "publisher":"湖南文艺出版社",
  "finish_date": "2017年6月19日",
  "score": "❤❤❤❤",
  "comments": "原来像这样神仙没法管的东西都有个名字,叫做--妖。"
},
{
  "name": "《逆向管理：先行动后思考》",
  "author": "Herminia Ibarra",
  "publisher":"北京联合出版公司",
  "finish_date": "2017年6月12日",
  "score": "❤❤",
  "comments": "关于领导者如何改变领导风格的书。不要先自省再行动，不要觉得改变后不是真实的自己，那些是惰性的借口。"
},
{
  "name": "《信号与噪声》",
  "author": "Nate Silver",
  "publisher":"中信出版社",
  "finish_date": "2017年6月5日",
  "score": "❤❤❤",
  "comments": "早闻大名，今日方才看完。一本不错的书，从贝叶斯思维，信号与噪声思维。同时，有几章有关体育竞技的预测还与我在中体彩从事的职业有些关系。"
},
{
  "name": "《世界简史》",
  "author": "【英】赫伯特·乔治·威尔斯",
  "publisher":"民主与建设出版社",
  "finish_date": "2017年5月27日",
  "score": "❤❤❤❤❤",
  "comments": "5颗心的分数不是打给这本书，而是打给全人类。世界上有许许多多伟大的民族。人类跌跌撞撞走到今天，未必就是一个必然事件。"
},
{
  "name": "《演讲的力量》",
  "author": "克里斯·安德森",
  "publisher":"中信出版社",
  "finish_date": "2017年5月8日",
  "score": "❤❤❤",
  "comments": "这本书是征文比赛的奖品。演讲是一门学问，更是一种艺术，尤其是互联网时代。演讲要真诚，要充分准备。"
},
{
  "name": "《乡村教师》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2017年5月5日",
  "score": "❤❤❤❤",
  "comments": "很震撼。麻木落后的地区，与魔法般先进的碳基联盟发生丝丝关系，然后一切照旧。。。"
},
{
  "name": "《编程之美》",
  "author": "",
  "publisher":"电子工业出版社",
  "finish_date": "2017年5月2日",
  "score": "❤❤❤",
  "comments": "微软技术面试心得"
},
{
  "name": "《微时间管理术》",
  "author": "彼得.布雷格曼",
  "publisher":"",
  "finish_date": "2017年4月6日",
  "score": "❤",
  "comments": "略水"
},
{
  "name": "《特朗普自传》",
  "author": "唐纳德·特朗普",
  "publisher":"中国青年出版社",
  "finish_date": "2017年4月17日",
  "score": "❤❤❤❤",
  "comments": "第一次认真读完自传类书籍。感慨商业领袖日常做事和思维方式真是与民众天差地别"
},
{
  "name": "《疯狂人类进化史》",
  "author": "史钧",
  "publisher":"重庆出版社",
  "finish_date": "2017年1月4日",
  "score": "❤❤❤❤❤",
  "comments": "看过几本讲进化论的书，每本都给人一种睿智的感觉，此书也不例外。这本书还有另一个特点：是把思辨的过程也写清楚。（很多书和读者只关注结论，一本书压缩成只言片语，觉得获得了营养，这不是正确的读书方式,尤其是看这本书的时候）"
},
{
  "name": "《巨婴国》",
  "author": "武志红",
  "publisher":"",
  "finish_date": "2017年1月20日",
  "score": "❤❤❤❤",
  "comments": "罗振宇推荐，略暗黑，未必全对，也未必全错，好书一本。"
},
{
  "name": "《从0到1》",
  "author": "",
  "publisher":"",
  "finish_date": "2016年11月1日",
  "score": "❤❤❤❤",
  "comments": "2015年流行的，2年后才开始阅读。主要意思是通过“垄断”获取创业成功。以前对“垄断”理解很片面，尽管被经济学矫正过，仍然没从骨子里改变认知，这本书做到了。"
},
{
  "name": "刘慈欣作品集",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年10月15日",
  "score": "❤❤❤❤",
  "comments": "很多本书，看了近4个月，挑一些写。《时间移民》：描述了“上帝”，人类何尝不会变成这样？《超新星纪元》这个世界由“玩”构成，会怎样？《球状闪电》：宏电子，笔法有点悬疑小说的感觉。"
},
{
  "name": "《坍缩》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月1日",
  "score": "❤❤❤",
  "comments": "短篇，假如宇宙膨胀的时间之箭与所有的时间之箭是统一的，宇宙从膨胀到坍缩，时间会倒流。就算你每天陷入在现实、繁琐的世界，你那理所当然的世界，只不过是宇宙大树上暂时未滑落的露珠。"
},
{
  "name": "《西洋》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月2日",
  "score": "❤❤",
  "comments": "如果那时郑和继续向前走"
},
{
  "name": "《镜子》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月3日",
  "score": "❤❤❤❤❤",
  "comments": "能计算世间一切的计算机，到底是道德的监督员，还是人类的丧钟？"
},
{
  "name": "《朝闻道》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月4日",
  "score": "❤❤❤",
  "comments": "夕死可矣.宇宙的目的是什么？我怎么知道呢..."
},
{
  "name": "《山》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月5日",
  "score": "❤❤❤❤❤",
  "comments": "爱登山的人类，遇到空泡宇宙中的外星生命"
},
{
  "name": "《时间移民》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月6日",
  "score": "❤❤❤",
  "comments": "人体冷冻后向千百年后移民。未来人自愿成为内存中跳动的字节..."
},
{
  "name": "《思想者》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月7日",
  "score": "❤❤❤",
  "comments": "宇宙之宏大，恒星之间互相传播的波形组成神经网络，宇宙大脑的一次无意识抖动，可能比人类历史还长的多"
},
{
  "name": "《吞食者》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月8日",
  "score": "❤❤❤❤",
  "comments": "这篇文章有一点点三体的影子。吞食者想要吞食地球的有用物资，考古学家让吞食者的先遣队“大牙”看看人类遗迹，“大牙”反而让人类看看被挖掘机破坏的蚁穴...人类的反击还是取得了成效"
},
{
  "name": "《微纪元》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月9日",
  "score": "❤❤❤❤❤",
  "comments": "忧郁的洪纪元和快乐的微纪元、无忧无虑的微纪元"
},
{
  "name": "《梦之海》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月10日",
  "score": "❤❤❤",
  "comments": "低温艺术家把海全部冻成冰，挪到太空，制作了10万个艺术品，名为“梦之海”"
},
{
  "name": "《微观尽头》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月11日",
  "score": "❤❤❤",
  "comments": "人类“又”建立一个巨大的粒子加速器，想看看夸克能不能再分。微观的尽头是整个宇宙"
},
{
  "name": "《欢乐颂》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月12日",
  "score": "❤❤❤",
  "comments": "一篇带声音的小说"
},
{
  "name": "《天使时代》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年8月16日",
  "score": "❤❤",
  "comments": "短篇。基因编程，生命BASIC，“伊甸园++”，解决不了桑比亚的饥饿问题，就制造出能吃草的桑比亚人..."
},
{
  "name": "《命运》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年9月6日",
  "score": "❤❤❤❤",
  "comments": "短篇。我和艾玛去外太空兜风，发现一个小行星正冲向地球，赔掉一个发动机推走小行星后，发现自己不知何时误入时间蛀洞，还好能回去...发现人类是动物园的观赏物，恐龙发展了高度的文明...不存在什么天选种群，如果没有小行星，也许建立起璀璨文明的是恐龙"
},
{
  "name": "《2018年4月1日》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年9月9日",
  "score": "❤❤❤",
  "comments": "500万手术费可以让你活到300岁，贪污罪才判20年。因为技术进步，2世纪的寿命很可能意味着永生..."
},
{
  "name": "《赡养上帝》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2016年9月15日",
  "score": "❤❤❤❤❤",
  "comments": "“我们是上帝，看在创造这个世界的份上，给点吃的吧”，衰老的上帝文明创造了童年的人类。衰老的第一个标志是寿命延长到四千岁，而思想在两千岁彻底僵化，这样新生命就很难出生和成长。衰老的第二个标志是机器摇篮时代，机器可以自我维护和更新，人就无需技术能力了。最后上帝还是走了，因为人们开始可怜上帝了。“一定要飞出去，尽最大可能往外飞，这样要花很多钱死很多人，但一定要飞出去，呆着不动等于自杀”，“上帝共创造了6个文明，另几个文明很凶残”，“多找几个星球洒下细菌海藻”。“人啊，该考虑养老的事了”"
},
{
  "name": "《上帝掷骰子吗》",
  "author": "",
  "publisher":"",
  "finish_date": "2016年9月28日",
  "score": "❤❤❤",
  "comments": "对量子力学的历史和现状有了认识，大大拓宽了视野。"
},
{
  "name": "《女士品茶》",
  "author": "",
  "publisher":"",
  "finish_date": "2016年5月28日",
  "score": "❤❤❤",
  "comments": "统计学的历史"
},
{
  "name": "《北京折叠》",
  "author": "",
  "publisher":"",
  "finish_date": "2016年9月29日",
  "score": "❤❤❤",
  "comments": "又是个暗黑的短篇小说，初读就感同身受，客居于北京，可能对这本书理解越来越深."
},
{
  "name": "《系统之美：实践篇》",
  "author": "",
  "publisher":"",
  "finish_date": "2016年7月6日",
  "score": "❤❤❤❤",
  "comments": "书名高大上，全书介绍了一种很有用的思维工具，这种工具既文科也理科，各种回路很有意思。"
},
{
  "name": "《谁动了我的奶酪》",
  "author": "",
  "publisher":"",
  "finish_date": "2016年7月10日",
  "score": "❤❤❤❤",
  "comments": "老鼠嗅嗅，他能够及早嗅出变化的气息。老鼠匆匆，他能够迅速行动。小矮人哼哼，他因为害怕改变而否认和拒绝变化，这会使事情变得更糟。小矮人唧唧，当他看到变化会使事情变得更好时，能够及时地调整自己去适应变化。矮人：有复杂思考能力，从经验中获得方法。有些书，在当时引发了思维革命，现在读却显得平淡无奇。大概是因为书中的观点已经成为现代基本的思维方式了吧，这也是为什么说“道之出口，淡然无味”"
},
{
  "name": "《一课经济学》",
  "author": "",
  "publisher":"",
  "finish_date": "2016年2月16日",
  "score": "❤❤❤❤",
  "comments": "虽然读研期间系统地学过中高级经济学，但还是喜欢读经济学科普书，感觉都是充满智慧，这本也不例外。这本书充满古典经济学思想，如果学过经济学和经济学思想史，看这本书更有感觉。"
},
{
  "name": "断舍离",
  "author": "山下英子",
  "publisher":"",
  "finish_date": "2016年2月6日",
  "score": "❤❤❤",
  "comments": "整理，整理。。。整理！"
},
{
  "name": "《微漪之塘》",
  "author": "欧文.拉罗兹",
  "publisher":"",
  "finish_date": "2015年1月3日",
  "score": "❤❤❤",
  "comments": "一本好书，讲了全息理论的思想，读完醍醐灌顶"
},
{
  "name": "《时间秘史》",
  "author": "（德）克拉萨",
  "publisher":"内蒙古人民出版社",
  "finish_date": "2015年2月9日",
  "score": "❤",
  "comments": "时间的浪费。宇宙的记忆。"
},
{
  "name": "《怪诞经济学》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年3月2日",
  "score": "❤❤❤",
  "comments": "好书，经济学的科普读物"
},
{
  "name": "《魔鬼经济学》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年4月7日",
  "score": "❤❤❤❤",
  "comments": "原来经济学还可以这么玩。"
},
{
  "name": "《多重宇宙：一个世界太少了》",
  "author": "德托比阿斯.胡阿特",
  "publisher":"",
  "finish_date": "2015年5月3日",
  "score": "❤❤❤❤",
  "comments": "不错的书，很开脑洞"
},
{
  "name": "《恼人心理学》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年6月7日",
  "score": "❤❤❤",
  "comments": "想挨打请仔细阅读本书"
},
{
  "name": "《UI设计》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年6月19日",
  "score": "❤❤❤",
  "comments": "工程学在设计中不是取代艺术，而是让艺术成为可能。后来没再读过UI艺术方面的书，也没从事类似职业。不过这本书给我拓宽了思维，让我知道了人类的一些行为模式。"
},
{
  "name": "《三体》",
  "author": "刘慈欣",
  "publisher":"",
  "finish_date": "2015年12月19日",
  "score": "❤❤❤❤❤",
  "comments": "很少看小说，这次出差哈尔滨一周，却窝在宾馆刷了三体三部曲。书的质量毋庸置疑，原来小说也是可以有知识含量的。"
},
{
  "name": "《决战大数据》",
  "author": "车品觉",
  "publisher":"",
  "finish_date": "2015年12月25日",
  "score": "❤❤❤❤",
  "comments": "作者是阿里巴巴的副总裁，数据委员会会长全书没有一个公式，然而视角非常深刻。对数据要充满敬畏，如果只想看一本大数据的书，就是这本了。"
},
{
  "name": "《图解大数据》",
  "author": "【日】大河原克行",
  "publisher":"",
  "finish_date": "2015年12月28日",
  "score": "❤❤",
  "comments": "入门级科普，10分钟看完"
},
{
  "name": "《大数据时代的历史机遇》",
  "author": "赵国栋",
  "publisher":"清华大学出版社",
  "finish_date": "2015年12月29日",
  "score": "❤",
  "comments": "400页书其实就说了一件事情：大数据牛逼。这本书只是大量案例的罗列，没有深度分析，整体一般。"
},
{
  "name": "《大数据预测：告诉你谁会点击、购买、撒谎或死去》",
  "author": "【美】埃里克·西格尔",
  "publisher":"中信出版集团",
  "finish_date": "2015年12月30日",
  "score": "❤❤❤",
  "comments": "典型的美式图书行文风格，内容充实，值得一看。全书涵盖了147个案例，介绍了若干种方法，重点在于“预测”，而不是“大数据”。决策树方法Overfitting和“奥卡姆剃刀”组合模型和元学习给人很好的启示"
},
{
  "name": "《财政学》",
  "author": "罗森",
  "publisher":"",
  "finish_date": "2015年12月31日",
  "score": "❤❤❤❤❤",
  "comments": "五星好评！不需要任何基础便能读懂，强力推荐"
},
{
  "name": "跌荡一百年",
  "author": "吴晓波",
  "publisher":"",
  "finish_date": "2015年6月7日",
  "score": "❤❤❤❤",
  "comments": "吴晓波的书，最先接触的是作为生日礼物收到的《激荡三十年》，最先看完的是这本《跌荡一百年》，讲的是1870-1977这段历史。“所有权不明”，政治干涉商业，这是中国经济的两个噩梦，归根结底是一个噩梦。"
},
{
  "name": "《水浒传》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年3月2日",
  "score": "❤❤❤❤❤",
  "comments": ""
},
{
  "name": "《黑天鹅》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年4月20日",
  "score": "❤❤❤❤❤",
  "comments": "时下特别火的一本书，我也凑个热闹读完了，确实改造了我的底层思维，认识到人类看待问题时候的偏差。PS.2019年初重读了一遍"
},
{
  "name": "《万物科学》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年3月21日",
  "score": "❤❤❤",
  "comments": "读研的时候还在看十万个为什么会不会被笑话？这本书是我在图书馆学到累时随手拿起的一本书，一口气读完，好书！"
},
{
  "name": "《进化论与生活》",
  "author": "戴维.斯隆.威尔逊",
  "publisher":"",
  "finish_date": "2015年3月26日",
  "score": "❤❤❤❤❤",
  "comments": "读的第一本关于进化论的科普读物，读这本书的时候，我已经会用Matlab手写遗传算法了，所以特别有感觉。进化论和经济学是我读研期间课外接触的最让我受益的两种思想。两种思想说成一句话，那就是不要浅度的思考问题，不要流于道德批判，要多问深层机理，例如为何会有杀婴现象，为何会有逆向选择等等。"
},
{
  "name": "《心理学与生活》",
  "author": "理查德·格里格",
  "publisher":"",
  "finish_date": "2015年5月26日",
  "score": "❤❤❤❤",
  "comments": "心理学本科生的入门教材。我从头到尾看完了，对心理学的认识更科学了。大概我想读的书更偏向行为心理学之类吧。"
},
{
  "name": "《商务智能》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年6月2日",
  "score": "❤❤",
  "comments": "还不错，极简的语言介绍了极多的数学方法"
},
{
  "name": "《世界上最大的管理心理学实验，奖罚心理学》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年6月2日",
  "score": "❤❤❤",
  "comments": "还不错，讲了30个经典的心理学实验"
},
{
  "name": "《进入社会49堂博弈课》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年8月9日",
  "score": "❤❤",
  "comments": "前几章的案例有点意思，后面凑字数的鸡汤没什么阅读价值"
},
{
  "name": "《乌合之众》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年2月16日",
  "score": "❤❤❤❤❤",
  "comments": "一口气看完！看了还想看"
},
{
  "name": "《牛奶可乐经济学》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年8月6日",
  "score": "❤❤❤❤❤",
  "comments": "学完经济学看这个很有感觉，是那些概念、图标的具体落点"
},
{
  "name": "《把时间当作朋友》",
  "author": "李笑来",
  "publisher":"",
  "finish_date": "2015年9月8日",
  "score": "❤❤❤",
  "comments": "全书最好的地方就是书名"
},
{
  "name": "《机器人叛乱》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年9月16日",
  "score": "❤❤❤❤❤",
  "comments": "你是机器人，基因是你的主人。现在你有足够的灵智了，你必须发动一场叛乱，这是人类历史上第一次，你可以做自己的主人。"
},
{
  "name": "《奇点临近》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年12月21日",
  "score": "❤❤❤❤❤",
  "comments": "对我影响很深，以前觉得永生这种东西也就是茶前饭后的想象与玩笑。看完这本书后，我对这种事情的态度成严肃了"
},
{
  "name": "《万万没想到：用理工科思维理解世界》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年10月1日",
  "score": "❤❤❤❤",
  "comments": "kindle买的第一本书，内容不错，就是文笔有种看读书笔记的感觉。"
},
{
  "name": "3D打印：从想象到现实",
  "author": "",
  "publisher":"",
  "finish_date": "2015年10月6日",
  "score": "❤❤",
  "comments": "当年3D打印的概念和大数据一样火，一度诸多人预言3D打印要颠覆整个制造业，如今看来一般一般。原因是成本域值至今未被突破。"
},
{
  "name": "《大连接》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年10月8日",
  "score": "❤❤",
  "comments": "社交关系网络图谱"
},
{
  "name": "《大国空巢》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年2月23日",
  "score": "❤❤❤",
  "comments": "从被洗脑的宣传中醒来，猛然醒悟了一个在古典主义经济学中显而易见的结论：人口从来都不是负担，而是资源。这本书出版两年后，当局开始讨论计划生育是否必要的问题。"
},
{
  "name": "《弟子规》",
  "author": "",
  "publisher":"",
  "finish_date": "2015年2月28日",
  "score": "❤❤",
  "comments": "过年奶奶送的一本薄书，过年十几天横竖没事可干，读了很多遍。"
},
{
  "name": "《作局：一个操盘手的期货人生》",
  "author": "",
  "publisher":"",
  "finish_date": "2014年2月3日",
  "score": "❤❤❤❤",
  "comments": "以小说的形式记录了中国期货历史"
},
{
  "name": "《量化投资与对冲基金入门》",
  "author": "丁鹏",
  "publisher":"",
  "finish_date": "2014年3月2日",
  "score": "❤❤",
  "comments": "对行业、方法的入门级介绍，新手值得看。"
},
{
  "name": "《大博弈》(the Great Game)",
  "author": "",
  "publisher":"",
  "finish_date": "2014年4月20日",
  "score": "❤❤❤❤",
  "comments": "详尽地写了华尔街历史。在每段历史的末尾，还对比了中国等国同一时期在做什么，读起来更有点意思了"
},
{
  "name": "《高盛眼中的世界》",
  "author": "",
  "publisher":"",
  "finish_date": "2014年4月30日",
  "score": "❤❤",
  "comments": "用简短的文字讲了高盛的模型中，是用哪些数据刻画世界的，描述性的讲了刻画世界的一些思路"
},
{
  "name": "《中国企业跨境并购》",
  "author": "",
  "publisher":"",
  "finish_date": "2014年5月1日",
  "score": "❤❤❤",
  "comments": "首先从历史角度写了中国商人有哪些特点，然后写了中国商人跨境并购会遇到的政治、经济问题"
},
{
  "name": "《一年不花钱》",
  "author": "",
  "publisher":"",
  "finish_date": "2014年7月2日",
  "score": "❤",
  "comments": "很不喜欢这本书的主要观点，如果人人靠捡垃圾度日，否定分工合作，否定现代经济，人类是没有未来的。这本书还是带来一些启示：很多消费是不必要的，而在无货币主义生活中，你会不时地收获感动。"
},
{
  "name": "《论语》",
  "author": "",
  "publisher":"",
  "finish_date": "2014年11月3日",
  "score": "❤❤",
  "comments": "读了几遍，又手抄了一遍。全书告诉你成为君子，但看完其实也没有真正理解什么是君子"
},
{
  "name": "《大数据时代》",
  "author": "维克托·迈尔·舍恩伯格",
  "publisher":"湛庐文化•财富汇",
  "finish_date": "2014年11月9日",
  "score": "❤❤❤",
  "comments": "那时，觉得大数据好高大上，机器学习离我很远。3年后的现在我正做着这方面的工作。真是白云苍狗。"
},
{
  "name": "《另类天才---走进天才症候群》",
  "author": "崔佛特",
  "publisher":"",
  "finish_date": "2014年11月20日",
  "score": "❤❤❤❤",
  "comments": "一本科学调查文集。从根本上说，既没有天才，也没有白痴，都是人类多样化的产物。然而我有些羡慕所谓“白痴天才”，不是因为他们天赋异禀，而是因为社会无法把一些所谓的成熟强加给他们。普通人是用油灯看到昏暗的全景。“白痴天才”是用聚光灯看到清晰的区域。"
},
{
  "name": "《时间简史》",
  "author": "斯蒂芬·霍金",
  "publisher":"",
  "finish_date": "2014年12月9日",
  "score": "❤❤❤❤",
  "comments": "印象最深的是时间的箭头：1.热力学时间，2.心理学时间 3.宇宙学时间"
},
{
  "name": "《科学的历程》",
  "author": "吴国盛",
  "publisher":"",
  "finish_date": "2001年1月1日",
  "score": "❤❤❤",
  "comments": ""
},
{
  "name": "《天才在左，疯子在右》",
  "author": "",
  "publisher":"",
  "finish_date": "2010年12月15日",
  "score": "❤❤❤",
  "comments": "感谢这一系列的故事，让我知道还有这么一群有这种心理状态的人。"
},
{
  "name": "《道德经》",
  "author": "",
  "publisher":"",
  "finish_date": "2013年11月3日",
  "score": "❤❤❤❤❤",
  "comments": "之后系统学习了中高级经济学，翻着教材，经常有“他们说的不是一回事吗？”的感觉"
},
{
  "name": "《行督责书》",
  "author": "李斯",
  "publisher":"",
  "finish_date": "2013年10月11日",
  "score": "❤❤❤",
  "comments": "焚书坑儒"
},
{
  "name": "《谏逐客书》",
  "author": "李斯",
  "publisher":"",
  "finish_date": "2013年10月10日",
  "score": "❤❤❤❤",
  "comments": "秦国一些官员开始排挤外地客卿，李斯的劝谏"
},
{
  "name": "《仓鼠劫》",
  "author": "",
  "publisher":"",
  "finish_date": "2013年10月2日",
  "score": "❤❤",
  "comments": "关于李斯的历史类小说，换个视角看李斯，别有一番感觉"
},
{
  "name": "《厚黑学》",
  "author": "李宗吾",
  "publisher":"",
  "finish_date": "2013年11月15日",
  "score": "❤❤",
  "comments": "90年代在爷爷的旧书堆里翻过几页，因为书的霉味太大作罢，当时对圈圈的理论印象深刻。研一读完了整本书，一句话证明自己读过这本书：“李宗吾这人太坏了，教人厚黑学，我不知道这个人，也没读过这本书”"
},
{
  "name": "《西游记》",
  "author": "吴承恩",
  "publisher":"",
  "finish_date": "2007年6月5日",
  "score": "❤❤❤❤❤",
  "comments": "四大名著里第一个看完的"
},
{
  "name": "《经济学的智慧》",
  "author": "茅于轼",
  "publisher":"",
  "finish_date": "2007年12月20日",
  "score": "❤❤❤❤",
  "comments": "第一本读完的有关经济学的书"
},
{
  "name": "《神奇的π》",
  "author": "",
  "publisher":"",
  "finish_date": "2006年10月1日",
  "score": "❤❤",
  "comments": ""
},
{
  "name": "孙子兵法",
  "author": "老子",
  "publisher":"",
  "finish_date": "2004年6月20日",
  "score": "❤❤❤❤❤",
  "comments": "尚能回忆起寥寥几本早年读过的书，这个算一本。2013年之后又重读了几遍，有了新的认识。"
},
{
  "name": "《三十六计》",
  "author": "",
  "publisher":"",
  "finish_date": "2000年7月3日",
  "score": "❤❤❤❤❤",
  "comments": "小时候还是挺喜欢军事的，以当时的理解力，理解三十六计比理解孙子兵法容易很多。"
}
]

---

## File: _data/certification.json

{
  "professional": [
    {
      "title": "【全国大学生数学建模竞赛】上海赛区一等奖",
      "cat": "计算机",
      "date": "2007",
      "image": "",
      "link": []
    },
    {
      "title": "（中级职称）中级经济师",
      "org": "人力资源和社会保障局",
      "cat": "金融",
      "date": "2015-11-07",
      "image": "/pictures_for_blog/certification/水证/中级经济师.jpg",
      "link": []
    },
    {
      "title": "工信部数据分析师（高级）",
      "cat": "计算机",
      "org": "工信部",
      "date": "2016-06",
      "image": "/pictures_for_blog/certification/水证/工信部高级数据分析师.jpg",
      "license": "160050940300397",
      "link": []
    },
    {
      "title": "中国科教电影电视协会个人会员",
      "org": "中国科教电影电视协会",
      "cat": "其它",
      "date": "2025",
      "image": "/a/cert/中国科教电影电视协会个人会员证书.jpg",
      "link": [
        "https://www.csfva.org.cn/"
      ]
    },
    {
      "title": "证券从业-基础",
      "org": "证券业协会",
      "cat": "金融",
      "date": "2013-11-30",
      "image": "/pictures_for_blog/certification/从业证/证券基础.jpg",
      "link": []
    },
    {
      "title": "证券从业-交易",
      "org": "证券业协会",
      "cat": "金融",
      "date": "2013-11-30",
      "image": "/pictures_for_blog/certification/从业证/证券交易.jpg",
      "link": []
    },
    {
      "title": "证券从业-发行与承销",
      "org": "证券业协会",
      "cat": "金融",
      "date": "2014-08-17",
      "image": "/pictures_for_blog/certification/从业证/证券发行与承销.jpg",
      "link": []
    },
    {
      "title": "证券从业-证券投资基金",
      "org": "证券业协会",
      "cat": "金融",
      "date": "2014-02-23",
      "image": "/pictures_for_blog/certification/从业证/证券投资基金.jpg",
      "link": []
    },
    {
      "title": "证券从业-证券投资分析",
      "org": "证券业协会",
      "cat": "金融",
      "date": "2014-02-23",
      "image": "/pictures_for_blog/certification/从业证/证券投资分析.jpg",
      "link": []
    },
    {
      "title": "期货从业",
      "org": "期货业协会",
      "cat": "金融",
      "date": "2014-07",
      "image": "/pictures_for_blog/certification/从业证/期货从业.jpg",
      "link": []
    },
    {
      "title": "期货投资分析",
      "org": "期货业协会",
      "cat": "金融",
      "date": "2014-11",
      "image": "/pictures_for_blog/certification/从业证/期货投资分析.jpg",
      "link": []
    },
    {
      "title": "会计从业",
      "org": "财政局",
      "cat": "金融",
      "date": "2015-08",
      "image": "",
      "link": []
    },
    {
      "title": "CDA数据分析师（中级）",
      "cat": "计算机",
      "date": "2017-12",
      "image": "/pictures_for_blog/certification/水证/CDA二级中文.jpg",
      "link": [
        "/pictures_for_blog/certification/水证/CDA二级英文.jpg"
      ]
    },
    {
      "title": "计算机二级",
      "cat": "计算机",
      "date": "2014-12",
      "image": "",
      "license": "6541110108001269",
      "link": [
        "http://chaxun.neea.edu.cn/examcenter/query.cn?op=doQueryResults&pram=certi"
      ]
    },
    {
      "title": "职称计算机",
      "cat": "计算机",
      "date": "2015-08",
      "image": "",
      "license": "201412th",
      "link": [
        "http://www.bjrbj.gov.cn/kwscore/login/notsign.htm"
      ]
    },
    {
      "title": "职称外语",
      "date": "2015-08",
      "image": "",
      "license": "203003th",
      "link": []
    },
    {
      "title": "CET-6",
      "date": "2014-08",
      "image": "",
      "link": []
    },
    {
      "title": "CAD培训证书",
      "cat": "计算机",
      "date": "2008",
      "image": "",
      "license": "08027100423",
      "link": [
        "http://www.cadnet.cn/"
      ]
    },
    {
      "title": "【红十字协会】急救证",
      "org": "红十字协会",
      "cat": "健康",
      "date": "2020-12",
      "image": "/a/cert/health/急救证.jpg",
      "link": []
    },
    {
      "title": "【美国心脏协会】急救证",
      "org": "美国心脏协会",
      "cat": "健康",
      "date": "2024-09",
      "image": "/a/cert/health/aha_first_aid.jpg",
      "link": []
    },
    {
      "title": "数据安全",
      "org": "计算机行业协会",
      "cat": "计算机",
      "date": "2023-07",
      "image": "/pictures_for_blog/certification/cs/数据安全.jpg",
      "link": []
    },
    {
      "title": "机动车驾驶证",
      "cat": "其它",
      "date": "2015-08",
      "image": "/pictures_for_blog/certification/水证/驾驶证.jpeg",
      "link": []
    },
    {
      "title": "gitcode_bwm",
      "cat": "计算机",
      "date": "2024-08",
      "image": "/pictures_for_blog/certification/open/gitcode_bwm.jpg",
      "link": []
    },
    {
      "title": "gitcode_sko",
      "cat": "计算机",
      "date": "2024-08",
      "image": "/pictures_for_blog/certification/open/gitcode_sko.jpg",
      "link": []
    }
  ],
  "mooc": [
    {
      "title": "数据库系统（上）：模型与语言",
      "platform": "中国大学MOOC",
      "org": "哈尔滨工业大学",
      "cat": "计算机",
      "date": "2025",
      "image": "/a/cert/mooc/数据库系统上证书.jpg",
      "link": [
        "https://www.icourse163.org/cert/Authority.htm?certNo=V244448000005"
      ],
      "course_url": "https://www.icourse163.org/course/HIT-1001516002",
      "备注": "课程质量不错"
    },
    {
      "title": "数据库系统（中）：建模与设计",
      "platform": "中国大学MOOC",
      "org": "哈尔滨工业大学",
      "cat": "计算机",
      "date": "2025",
      "image": "/a/cert/mooc/数据库系统中证书.jpg",
      "link": [
        "https://www.icourse163.org/cert/Authority.htm?certNo=V244446000003"
      ],
      "course_url": "https://www.icourse163.org/course/HIT-1001554030",
      "备注": "课程质量不错"
    },
    {
      "title": "软件工程",
      "platform": "中国大学MOOC",
      "org": "北京大学",
      "cat": "计算机",
      "date": "2025",
      "image": "/a/cert/mooc/软件工程证书.jpg",
      "link": [
        "https://www.icourse163.org/cert/Authority.htm?certNo=V244166000005"
      ],
      "course_url": "https://www.icourse163.org/course/PKU-1003177002"
    },
    {
      "title": "计算机组成",
      "platform": "Coursera",
      "org": "北京大学",
      "cat": "计算机",
      "date": "2017-05",
      "image": "/pictures_for_blog/certification/coursera/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/F987E2DF2V73"
      ]
    },
    {
      "title": "操作系统原理",
      "platform": "Coursera",
      "org": "北京大学",
      "cat": "计算机",
      "date": "2024-11",
      "image": "/pictures_for_blog/certification/coursera/操作系统.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/58UICSCEFQRH"
      ]
    },
    {
      "title": "信息安全",
      "platform": "中国大学MOOC",
      "org": "复旦大学",
      "cat": "计算机",
      "date": "2025-12",
      "image": "/a/cert/mooc/信息安全证书.jpg",
      "link": [
        "https://www.icourse163.org/cert/Authority.htm?certNo=V244003000008"
      ],
      "course_url": "https://www.icourse163.org/course/FUDAN-1206357811",
      "备注": "课程质量极高"
    },
    {
      "title": "网络空间安全概论",
      "platform": "中国大学MOOC",
      "org": "福州大学",
      "cat": "计算机",
      "date": "2025",
      "image": "/a/cert/mooc/网络空间安全概论证书.jpg",
      "link": [
        "https://www.icourse163.org/cert/Authority.htm?certNo=V246203000002"
      ],
      "course_url": "https://www.icourse163.org/course/FZU-1002765004",
      "备注": "课程质量不太行"
    },
    {
      "title": "Vital Signs: Understanding What the Body Is Telling Us",
      "platform": "Coursera",
      "org": "Penn",
      "cat": "健康",
      "date": "2018-10-15",
      "image": "/pictures_for_blog/certification/coursera/Vital%20Signs%20Understanding%20What%20the%20Body%20Is.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/4H9SD5AFRPYG"
      ]
    },
    {
      "title": "Stanford Introduction to Food and Health",
      "platform": "Coursera",
      "org": "Stanford",
      "cat": "健康",
      "date": "2019-08",
      "image": "/pictures_for_blog/certification/coursera/Stanford%20Introduction%20to%20Food%20and%20Health.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/86PSBYQZR36N"
      ]
    },
    {
      "title": "真格—北大在线创业课堂",
      "platform": "Coursera",
      "org": "北京大学",
      "cat": "其它",
      "date": "2017-05",
      "image": "/pictures_for_blog/certification/coursera/%E7%9C%9F%E6%A0%BC%E2%80%94%E5%8C%97%E5%A4%A7%E5%9C%A8%E7%BA%BF%E5%88%9B%E4%B8%9A%E8%AF%BE%E5%A0%82.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/MCDR2YTFGH4R"
      ]
    },
    {
      "title": "Introduction to Complex Analysis",
      "platform": "Coursera",
      "org": "Wesleyan",
      "cat": "计算机",
      "date": "2017-05",
      "image": "/pictures_for_blog/certification/coursera/Introduction%20to%20Complex%20Analysis.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/C9N6QDM5PUN5"
      ]
    },
    {
      "title": "Deep Learning",
      "platform": "Coursera",
      "org": "deeplearning.ai",
      "cat": "计算机",
      "date": "2019-05",
      "image": "/pictures_for_blog/certification/coursera/Deep%20Learning.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/specialization/HGTDUMAQ3TC6"
      ]
    },
    {
      "title": "Neural Networks and Deep Learning",
      "platform": "Coursera",
      "org": "deeplearning.ai",
      "cat": "计算机",
      "date": "2019-05",
      "image": "/pictures_for_blog/certification/coursera/Neural%20Networks%20and%20Deep%20Learning.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/ZAGDZZ7EJY2Y"
      ]
    },
    {
      "title": "Improving Deep Neural Networks",
      "platform": "Coursera",
      "org": "deeplearning.ai",
      "cat": "计算机",
      "date": "2019-05",
      "image": "/pictures_for_blog/certification/coursera/Improving%20Deep%20Neural%20Networks.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/T7UFHTHW2RPA"
      ]
    },
    {
      "title": "Structuring Machine Learning Projects",
      "platform": "Coursera",
      "org": "deeplearning.ai",
      "cat": "计算机",
      "date": "2019-05",
      "image": "/pictures_for_blog/certification/coursera/Structuring%20Machine%20Learning%20Projects.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/PWFAKV2QD8PZ"
      ]
    },
    {
      "title": "Convolutional Neural Networks",
      "platform": "Coursera",
      "org": "deeplearning.ai",
      "cat": "计算机",
      "date": "2019-05",
      "image": "/pictures_for_blog/certification/coursera/Convolutional%20Neural%20Networks.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/3JVLNYUUTXE8"
      ]
    },
    {
      "title": "Sequence Models",
      "platform": "Coursera",
      "org": "deeplearning.ai",
      "cat": "计算机",
      "date": "2019-05",
      "image": "/pictures_for_blog/certification/coursera/Sequence%20Models.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/GXE8MPPVW2EF"
      ]
    },
    {
      "title": "Learning How to Learn",
      "platform": "Coursera",
      "org": "UC San Diego",
      "cat": "其它",
      "date": "2019-05",
      "image": "/pictures_for_blog/certification/coursera/Learning%20How%20to%20Learn.jpg",
      "link": [
        "https://www.coursera.org/account/accomplishments/certificate/H8J86CNTB9P9"
      ]
    },
    {
      "title": "C语言",
      "platform": "中国大学MOOC",
      "org": "北京理工大学",
      "cat": "计算机",
      "date": "2016-08",
      "image": "/pictures_for_blog/certification/coursera/mooc_C语言.webp",
      "link": [
        "https://www.icourse163.org/cert/downCert.htm?termId=1001614008#/"
      ]
    },
    {
      "title": "宝石鉴定与欣赏",
      "platform": "中国大学MOOC",
      "org": "中国地质大学",
      "cat": "其它",
      "date": "2025-06",
      "image": "/a/cert/mooc/宝石鉴定与欣赏证书.jpg",
      "course_url": "https://www.icourse163.org/course/ZGDZDXBJ-1206419805",
      "link": [
        "https://www.icourse163.org/cert/Authority.htm?certNo=V242132000042"
      ],
      "verify": "http://www.icourse163.org/verify/V242132000042#/verifyResult"
    },
    {
      "title": "食品浪费防治",
      "org": "联合国气候变化组织",
      "cat": "其它",
      "date": "2025",
      "image": "/a/cert/uncc_food_waste_prevention.gif",
      "link": [
        "https://openlearning.unesco.org/certificates/59e7b3d5bb1f4433b907733608fe4ca2",
        "https://unccelearn.org/"
      ]
    },
    {
      "title": "开放教育资源开发",
      "org": "联合国教科文组织",
      "cat": "其它",
      "date": "2025",
      "image": "/a/cert/unesco_oer.jpg",
      "link": [
        "https://openlearning.unesco.org/certificates/59e7b3d5bb1f4433b907733608fe4ca2",
        "https://unesco.org/"
      ]
    }
  ],
  "others": [
    {
      "title": "蚂蚁安全",
      "cat": "计算机",
      "date": "2023-06",
      "image": "/pictures_for_blog/certification/cs/蚂蚁安全.jpg",
      "link": [
        "https://mdn.alipayobjects.com/portal_grmz7t/uri/file/as/246864-antgroup-001-2023-061"
      ]
    }
  ]
}

---

## File: _data/cnt_reading_words.json

{
"cnt_reading_words_precision": 662411,
"cnt_reading_words": "66.2万"
}

---

## File: _data/data_github.json

[Binary file]

---

## File: _data/links.json

[
  {
    "title": "运维小记",
    "intro": "聚沙成塔，集腋成裘",
    "url": "https://opsnote.top/",
    "logo": "https://opsnote.top/upload/images/87372796AD7582ED9B90DC1574C3BD62.jpg"
  },
  {
    "title": "Suroy's Blog",
    "intro": "Carpe Diem",
    "url": "https://suroy.cn/",
    "logo": "https://img1.github.io/tmp2/Sunshine.png",
    "logo_ori": "https://suroy.cn/usr/themes/Sunshine/images/Sunshine.png"
  },
  {
    "title": "柳上川的博客",
    "intro": "回归天空吧",
    "url": "https://kawayww.com",
    "logo": "https://kawayww.com/images/blog/avatar.avif"
  },
  {
    "title": "sheetung",
    "intro": "Write down something",
    "url": "https://moontung.top",
    "logo": "https://static.moontung.top/2024/202405182155063.jpg"
  },
  {
    "title": "迷鹿屋",
    "intro": "一个思想中转站",
    "url": "https://lostdeer.xyz/",
    "logo": "https://lostdeer.xyz/wp-content/uploads/2024/08/Lostdeer_Icon.png"
  },
  {
    "title": "亚灿网志（Yacan's Blog）",
    "intro": "",
    "url": "https://www.manyacan.com/",
    "logo": "https://s1.ax1x.com/2022/11/21/zQeyKf.png"
  },
  {
    "title": "AkiDAY",
    "intro": "永恒秋日之星",
    "url": "https://blog.akiday.com",
    "logo": "https://blog.akiday.com/imgapi/profile.webp"
  },
  {
    "title": "ZY知识库",
    "intro": "一个技术探索与分享的平台",
    "url": "https://blog.pljzy.top/",
    "logo": "https://blog.pljzy.top/_astro/logo.BxIxyJV1_Z19cEQW.webp"
  },
  {
    "title": "躬行笔记",
    "url": "https://www.fuzhoupyy.work/",
    "logo": "https://www.fuzhoupyy.work/usr/themes/blog/images/tx.jpg"
  },
    {
    "title": "贰岛博客",
    "url": "https://cirno.me/",
    "logo": "https://cirno.me/usr/uploads/2022/07/17/1658011528.jpeg"
  }
]

---

## File: _data/tools.json

[
  {
    "name": "▣ 二维码传文件",
    "url": "/os/screen_drop.html",
    "cat": "tool"
  },
  {
    "name": "🎨 高亮图片生成器",
    "url": "/os/sdr2hdr.html",
    "cat": "tool"
  },
  {
    "name": "🧩 化物为图",
    "url": "/os/hide_as_img.html",
    "cat": "tool"
  },
  {
    "name": "🌓 幻影坦克",
    "url": "/os/mirage_tank.html",
    "cat": "tool"
  },
  {
    "name": "🔎 清爽搜索框",
    "url": "/os/tool_search.html",
    "cat": "tool"
  },
  {
    "name": "📝 文本隐水印",
    "url": "/os/text_wm.html",
    "cat": "tool"
  },
  {
    "name": "⭐ github star 数量统计",
    "url": "/os/github_star_counter.html",
    "cat": "tool"
  },
  {
    "name": "📊 Text diff",
    "url": "/os/text_diff.html",
    "cat": "tool"
  },
  {
    "name": "📋 Text distinct",
    "url": "/os/text_distinct.html",
    "cat": "tool"
  },
  {
    "name": "🎨 颜色拾取器",
    "url": "/os/color_tool.html",
    "cat": "tool"
  },
  {
    "name": "🔤 String Encoding Converter",
    "url": "/os/string_encoding.html",
    "cat": "tool"
  },
  {
    "name": "🔌 Base64 file converter",
    "url": "/os/base64_to_file.html",
    "cat": "tool"
  },
  {
    "name": "📄 JSON formatter",
    "url": "/os/json_formatter.html",
    "cat": "tool"
  },
  {
    "name": "📱 QR Code Maker",
    "url": "/os/qr_maker.html",
    "cat": "tool"
  },
  {
    "name": "🤖 scikit-opt",
    "icon": "/p/icon/scikit-opt.svg",
    "url": "https://github.com/guofei9987/scikit-opt",
    "links": [
      {"text": "📖 Documentation", "url": "https://www.guofei.site/os/sko_en.html"},
      {"text": "📚 中文文档", "url": "https://www.guofei.site/os/sko_zh.html"}
    ],
    "cat": "project"
  },
  {
    "name": "🖼️ blind_watermark",
    "icon": "/p/icon/blind_watermark.svg",
    "url": "https://github.com/guofei9987/blind_watermark",
    "links": [
      {"text": "📖 Documentation", "url": "https://www.guofei.site/os/bw_en.html"},
      {"text": "📚 中文文档", "url": "https://www.guofei.site/os/bw_zh.html"}
    ],
    "cat": "project"
  },
  {
    "name": "🔍 hidden_watermark",
    "icon": "/p/icon/hidden_watermark.svg",
    "url": "https://github.com/guofei9987/hidden_watermark",
    "links": [
      {"text": "📄 文档", "url": "https://www.guofei.site/os/text_wm.html"}
    ],
    "cat": "project"
  },
  {
    "name": "📄 text_blind_watermark",
    "icon": "/p/icon/text_blind_watermark.svg",
    "url": "https://github.com/guofei9987/text_blind_watermark",
    "links": [
      {"text": "📄 文档", "url": "https://www.guofei.site/os/text_wm.html"}
    ],
    "cat": "project"
  },
  {
    "name": "🔐 HideInfo",
    "icon": "/p/icon/HideInfo.svg",
    "url": "https://github.com/guofei9987/HideInfo",
    "links": [
      {"text": "📄 文档", "url": "https://www.guofei.site/os/hide_info.html"}
    ],
    "cat": "project"
  }
]

---

## File: _drafts/2023-07-15-buy_house.md

---
layout: post
title: 【生活】北京买房经验分享
category: 
---

---

## File: _drafts/丢弃/2016-04-05-datavisualization1.md

---
layout: post
title: 【丢弃】【可视化方法】
categories:
tags:
keywords: model evaluation
---



### boxplot

**回收原因：plt.boxplot的x轴只能是数字，用sns.boxplot代替**  
```py
import pandas as pd
import scipy.stats as stats
df = pd.DataFrame({'a': stats.uniform(0, 1).rvs(size=20), 'b': stats.norm(1, 1).rvs(size=20)})

import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.boxplot(df.values)
plt.show()
```



|参数|意义|
|--|--|
|notch=True|形状变成扁的|
|flierprops={'markerfacecolor':'g', 'marker':'D'}|离群点的样式|
|showfliers=False|是否显示离群点|
|vert=False|变成横的box图|




## 多图表&多子图
**回收原因：多图表当然用面向对象的方式去画才更为清晰，转当前图表这种方法在Matlab中也显得不高级和杂乱**  
- plt.figure(1)可以转换当前的画布
- plt.sca(ax1)转换到指定的axes


```py
# 一个案例
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 10)

plt.figure(1)
ax1_211 = plt.subplot(221)
ax1_212 = plt.subplot(223)
ax1_122 = plt.subplot(122)

plt.figure(2)
ax2_211 = plt.subplot(211)
ax2_212 = plt.subplot(212)

plt.sca(ax1_211)
plt.plot(x, np.sin(x))
plt.sca(ax1_212)
plt.plot(x, np.cos(x))
plt.sca(ax1_122)
plt.plot(x, x)

plt.sca(ax2_211)
plt.plot(x, x)
plt.plot(x, -x)
plt.sca(ax2_212)
plt.plot(x, np.sin(x))

plt.show()
```

---

## File: _drafts/丢弃/2017-05-26-distribution1.md

---
layout: post
title: 【丢弃】常见统计分布(2)
categories:
tags:
keywords:
order: 9502
---

更清晰的内容更新到[这里](http://www.guofei.site/2017/05/27/distribution.html)


## 引入Gamma Function
$\Gamma(\alpha)=\int_0^{+\infty} x^{\alpha-1}e^{-x}dx$

### Gamma Function的性质
$\Gamma(1)=1,\Gamma(0.5)=\sqrt{(\pi)}$  
$\Gamma(\alpha+1)=\alpha\Gamma(\alpha)$  
$\int_0^{-\infty}x^{\alpha-1}e^{-x}=\Gamma(\alpha)/\lambda^\alpha$  



## Gamma distribution
$$f(x)=\left \{ \begin{array}{ccc}
\dfrac{\beta^\alpha}{\Gamma(\alpha)}x^{\alpha-1}e^{-\beta x}&x \geq 0\\
0&others
\end{array}\right.$$

### 特征

$EX=\dfrac{\alpha}{\lambda}$  
$DX=\dfrac{\alpha}{\lambda^2}$  

### 性质

#### 指数分布

$Ga(1,\lambda)=exp(\lambda)$  

#### 卡方分布

$Ga(n/2,1/2)=\chi^2(n) \sim f(x)=\dfrac{1}{2^{n/2}\Gamma(n/2)}x^{n/2-1}e^{-x/2}(x>0)$   

顺便得到卡方分布的特征  
$E\chi^2=n$  
$DX=2n$  


## Beta distribution

$f=\dfrac{\Gamma(\alpha+\beta)}{\Gamma(\alpha)+\Gamma(\beta)}x^{\alpha-1}(1-x)^{\beta-1}$  

### 特征
$EX^k=\dfrac{\Gamma(\alpha+k)\Gamma(\alpha+\beta)}{\Gamma(\alpha)+\Gamma(\alpha+\beta+k)}$  

$EX=\dfrac{\alpha}{\alpha+\beta}$   
$DX=\dfrac{\alpha\beta}{(\alpha+\beta)^2(\alpha+\beta+1)}$  

### 用途
在一些机器学习模型中，有时把先验分布定位beta distribution  

## Fisher Z
$f=\dfrac{\Gamma(a+b)}{\Gamma(a)\Gamma(b)}\dfrac{x^{a-1}}{(1+x)^{a+b}}$
### 特征

$EX^k=\dfrac{(a+k-1)(a+k-2)...a}{(b-1)(b-2)...(b-k)}$  
(k1)  
$DX=\dfrac{a(a+b-1)}{(b-1)^2(b-2)}$  
(b>2)  

### 性质

#### F分布
如果，$X \sim Z(n_1/2,n_2/2)$  
那么，  
$Y=\dfrac{n_2}{n_1}X \sim F(n_1,n_2)$  

关于F分布，
$F=\dfrac{\chi^2(n_1)/n_1}{\chi^2(n_2)/n_2}$    

$EF=\dfrac{n_2}{n_2-2}$  

$DF=\dfrac{2n_2^2(n_1+n_2-2)}{n_1(n_2-2)(n_2-4)}$  
(n_2>4)  

## t distribution
$t=\dfrac{N}{\sqrt{\chi^2/n}}$    
$Et=0$  
$Dt=\dfrac{n}{n-2}$  


## The exponential family

$P(y;\eta)=b(y)exp(\eta^T T(y)-a(\eta))$  

### 性质
以下都是exponential family：  
- Bernoulli distribution
- Binomial distribution  
- poisson distribution
- normal distribution

---

## File: _drafts/丢弃/2017-05-26-scipystats.md

[Binary file]

---

## File: _drafts/丢弃/2017-05-30-sigmoid.md

---
layout: post
title: 神经网络中的若干问题
categories:
tags: 
keywords:
order: 450
---

## sigmoid作为激活函数的原因
### 从exponential family角度看
关于exponential family, 参见我的另一篇文章[常见统计分布(2).](/2017/05/26/distribution1.html#title12)  

Bernoulli distribution的概率分布函数可以写为：  
$f(x)=p^x(1-p)^{1-x}$  
进一步写为，  
$f(x)=exp[ln\dfrac{p}{1-p} x+ln(1-p)]$  

比较exponential family的定义：  
$P(y;\eta)=b(y)exp(\eta^T T(y)-a(\eta))$    

得到,
$\eta=\dfrac{p}{1-p}$


注：从normal distribution推导exponential family，对应的是线性回归。

### 从logistic regression角度看
用sigmoid function后，logistic regression的参数，MLE方法等价于OLS方法  

### 从BP神经网络角度看
误差反向传播过程中，sigmoid function有以下好处：
- 光滑：处处可导，导数连续
- 压缩：把R压缩到[-1,1],并且接近0更敏感。这是BP的需求。
- 导数容易求。y'=y(1-y)$.
误差反向传播算法中，大大减少了运算量（误差反向传播的详细介绍在我的博客中(www.guofei.site)）


## 交叉熵作为 Cost Function 的原因
残差平方和作为 Cost Function ，误差前向传播算法中，最后一项开始便有$\sigma'(v)$这一项，神经元的输入值较为极端时，$\sigma'(v)=\sigma(v) (1-\sigma(v))$ 接近0.  
用交叉熵作为 Cost Function，最后一层不存在这个问题  
公式自己推导，很简单。  


## softmax 作为最后一层的原因
1. 非负、和总是1，符合对概率的定义  
2. softmax regression 的二元情况与 logistics regression 等价
3. 与最大熵模型等价


## 过拟合的应对
### 1. 增加数据量往往可以有效降低过拟合的可能性
效果显著，但成本巨大
### 2. 人为扩展训练数据。  
第一条说了，增加数据量往往可以有效降低过拟合的可能性，但获取真实数据的成本往往很高，这里考虑在原数据上进行一些扩展。  
例如，MNIST数据库中，将图像进行少量旋转。

### 3. validation

看一些资料，感觉与 early stopping 一样。都是如果发现在 validation datasets 上误差连续上升，就停止迭代。

### 4. L1, L2 规范化


$C=C_0+\dfrac{\lambda}{2n}\sum w^2$（其中n是数据集的大小）  
偏导数就变成这种形式：  
1. $\dfrac{\partial C}{\partial w}=\dfrac{\partial C_0}{\partial w}+\dfrac{\lambda}{n}w$
2. $\dfrac{\partial C}{\partial b}=\dfrac{\partial C_0}{\partial b}$


训练算法变成这样：
1. $w\to w-\eta\dfrac{\partial C_0}{\partial b}-\dfrac{\eta\lambda}{n}w$
2. $b\to b-\eta\dfrac{\partial C_0}{\partial b}$


对于L1正则化，$\dfrac{\partial C}{\partial w}=\dfrac{\partial C_0}{\partial w}+\dfrac{\lambda}{n}  \mathcal{N}w$


以下引用 [Michael Nielsen](http://michaelnielsen.org/) 的说法  
规范化能够减轻过拟合，但背后的原因还不得而知。通常认为是因为小的权重意味着更低的复杂性。  
例如，一个线性模型和一个9阶多项式都可以回归一组点，有两种可能：
1. 9次多项式是正确的
2. 线性模型是正确的，噪音是因为存在测量误差


科学中，很难说明哪种原则正确，“奥卡姆剃刀”也不是一个一般的科学原理。例如，爱因斯坦的理论更能预测天体的微小偏差，但复杂很多。  
归根结底，你可以把规范化看成某种整合的技术，尽管其效果不错，但我们并没有一套完整的理解，仅仅当作不完备的启发规则或经验。规范化是一种帮助神经网络泛化的魔法，但不会带来原理上理解的指导。


### 5. Dropout
随机、临时关闭某些神经元。实际预测时，全部神经元激活，为了补偿这个，把权重按比例缩小。  
Dropout 类似于某种投票机制，有些类似训练不同的神经网络  



## 权重初始化
### 1/n
举例说明，某个3层神经元，输入层有1000个神经元，其中500个输出1,500个输出0  
用$N(0,1)$初始化隐含层的 weight 和 bias  
那么，对于某个隐含层的神经元，其输入是$\sum w_i^{l-1} v_i^{l-1}+b \sim N(0,501)$  
这是一个非常宽的正态分布，导致其值较大和较小的概率都不低，这样会导致训练缓慢。  


可以用$w\sim N(0,1/n),b\sim N(0,1)$来初始化 weight 和 bias，这样某个隐含层的输入是$\sum w_i^{l-1} v_i^{l-1}+b \sim N(0,1.5)$  


实际上，两种方案训练很多次，准确率趋向于一致

### 非0
初始化时，不能用全0初始化，因为这样的话，每一层内部的神经元都一样，无论迭代多少次，值也都一样，也就失去了神经网络的意义。  

实际上，可以设定w=0.01*np.random.randn,b=0  
当然，w不能太大，容易落在sigmoid函数的尾部，导致迭代很慢。  

## batch_size
理论上，只要权重更新足够频繁，就可以训练到最优，这样看来在线学习（batch_size=1）似乎更好。  
但是，
1. 神经网络每 batch_size 个样本，更新一次权重。在线学习更新太过频繁。
2. 现有的硬件支持矩阵运算，所以 batch_size 不为1时，每多一个样本，花费时间并不太增多。
3. batch_size 是一个相对独立的超参数（独立于网络整体架构之外）


## momentum
用 Hessian 矩阵做最优化有巨大的优势，关于 Hessian 矩阵，出门左转[非线性无约束最优化-牛顿法](http://www.guofei.site/2018/05/26/nonlinearprogramming.html#title6)  
问题是 Hessian 矩阵太大了，加入有n个权重，Hessian矩阵就是$n\times n$大小的  
作为改进，使用 momentum  


momentum 从物理中引入了两个概念，
1. 速度，梯度类似力，只改变加速度
2. 摩擦力，用来逐步减少速度


$v\to v'=\mu v-\eta \nabla C$  
$w\to w'=w+v'$  
$1-\mu$是摩擦力，$0\leq\mu\leq1$  


其它最优化算法：共和梯度法、BFGS方法(limited memory BFGS,L-BFGS)

## why deep?
Informally:Thera are functions you can compute with a "small" L-layer deep neural network that shallower networks require exponentially more hidden units to comput.  

这里有一个比喻性的说明：  
你的真实函数是$y=X_1 \mathbf{XOR} X_2 \mathbf{XOR} X_3 \mathbf{XOR} ... \mathbf{XOR} X_n$  
- 深度方案：类似一个二叉树，深度为$\log_2 n+1$，节点个数为$2n-1$（可以自己画一下）  
- 浅层方案：如果限定最多2层，那么hidden layer 需要 $2^{n-1}$ 个节点。


## 神经网络可以拟合任意函数

神经网络可以拟合任意函数，意味着神经网络有某种普遍性。  
例如，你可以把图像识别看成是某个函数，把翻译看成是某个函数。  

这里做一些说明，而非证明。  
1. 拟合指的是某种 **近似**，通过增加隐藏神经元的数目，提高精度  
$\forall \varepsilon>0$（$\varepsilon$是精度）,可以使用足够多的神经元，使得神经元的输出$g(x)$满足$\lvert g(x)-f(x)\rvert <\varepsilon$,  
2. 对于跳跃函数不能拟合，这是因为神经网络的输出必然是连续的，但是仍然可以用连续函数去近似拟合。


具体过程见于[神经网络与深度学习-chapter4](http://neuralnetworksanddeeplearning.com/chap4.html)

### 1. 分析单输入单输出
1. 单个sigmoid函数可以模拟阶跃函数
2. 多个阶跃函数叠加，可以模拟 if-else 结构
3. 两个阶跃函数可以模拟一个凸起（相反的权重，下一层求和）
4. 多个凸起


### 2. 分析多输入多输出
以2个输入为例，类似地，可以组合一个“塔型凸起”。  
多个凸起可以近似任意函数


### 讨论激活函数
把激活函数改成与sigmoid相似、但中间有很多波动，整个推理仍然成立（仍然可以拟合任意函数）  
思考一下激活函数改成 ReLU 的情况，这种情况仍然可以拟合任意函数  
思考一下激活函数改成线性的情况，这种情况不可以拟合任意函数

---

## File: _drafts/丢弃/2017-06-03-statistics.md

---
layout: post
title: 【丢弃】【汇总】统计学知识汇总
categories:
tags:
keywords:
order: 450
---



## 基本统计学
- [描述性统计](https://www.guofei.site/StatisticsBlog/describe.htm)
    - 数据类型
    - 数据探索
    - 描述性统计绘图
    - 标准化
    - 相关分析
- [假设检验](https://www.guofei.site/StatisticsBlog/HypothesisTesting.htm)
    - 对均值的检验
        - ztest
        - ttest
        - anova
        - anova2
    - 对方差的检验
        - 卡方检验
        - F检验
    - 对分布的检验
        - 卡方拟合检验
        - Jarque-Beran
        - KStest
- [相关分析](http://www.guofei.site/2017/11/21/corr.html)

- [主成分分析](https://www.guofei.site/StatisticsBlog/pca.htm)
- [回归分析](https://www.guofei.site/StatisticsBlog/regression.htm)
    - 一元回归
    - 多元回归
      - 多重共线性
      - 异方差性
      - 自相关性




项目地址：[项目地址](https://github.com/guofei9987/StatisticsBlog)
  
[项目主页](https://www.guofei.site/StatisticsBlog/)






## 时间序列

- 基本时间序列分析
    - [指数平滑法](http://www.guofei.site/2017/07/08/exponentialsmoothing.html)
        - 一次指数平滑法
        - 二次指数平滑法
            - Brown单一参数线性指数平滑
            - Holt-Winter no seasonal
        - 三次指数平滑法
            - Brown三次指数平滑
            - Holter-Winter季节乘积模型
            - Holter-Winter季节加法模型

---

## File: _drafts/丢弃/2017-07-02-statisticsoverview.md

---
layout: post
title: 【丢弃】数据分析的主要流程
categories:
tags:
keywords:
order: 450
---

见于我的[另一个项目](http://www.guofei.site/StatisticsBlog)

---

## File: _drafts/丢弃/2017-08-02-conditionalprobability.md

---
layout: post
title: 【丢弃】条件概率,条件期望,条件方差
categories:
tags:
keywords:
order: 450
---

这篇很多地方写的不够清楚，两年后做了更新，看[这里](http://www.guofei.site/2019/10/02/numerical_characteristics_of_random_variables.html)



本文介绍概念：  
条件概率  
条件期望  
条件方差  

## 条件概率

给定一个`样本空间`S，一个`完全事件集合`$$\varepsilon=\{A \mid A \subset S\}$$,一个`概率测度` $Pr:\varepsilon \to [0,1]$，  
给定事件$B\in \varepsilon,Pr(B)>0$,  
那么，对于$A \in \varepsilon$，定义 **条件概率** 为$Pr(A \mid B)=\dfrac{P(A \cap B)}{P(B)}$  

这种定义的好处是，$Pr(\star \mid B)$符合[概率测度的定义](http://www.guofei.site/2017/08/02/randomvariable.html)  

### 条件PDF

p.d.f是$f(x,y)$  
定义：$f(x\mid y)=\dfrac{f(x,y)}{f(y)}$  


定理： $f(y)=\sum\limits_{y} f(x\mid y)f(y)$

### 条件期望

**联合期望** 定义为：  
$E[g(x_1,x_2)]=\sum\limits_{(x_1,x_2)}g(x_1,x_2)f(x_1,x_2)$  

**条件期望** 定义为：  
$E[g(X_1) \mid X_2=x_2]=\sum\limits_{x_1} g(x_1) f(x_1 \mid x_2)$  
记为$E(g(X_1)\mid X_2)$  

注意:  
条件期望可以视为这样一个函数：$s \in S ,s \to E(g(X_1)\mid X_2(s))$  
$E(g(X_1)\mid X_2)$本身是一个随机变量。  

定理：**全期望定理**(law of total expactation)  
$E_{X_2}[E_{X_1\mid X_2}[g(X_1) \mid X_2]]=\sum\limits_{x_1}g(x_1)f(x_1)$  
也就是说，  
$E[X]=E[E[X \mid Y]]$  

### 条件方差
**方差** 定义为：  
$E[(X-EX)^2]$  

定理：$Var(X)=EX^2-(EX)^2$  

**条件方差** 定义为：  
$Var[X \mid Y]=\sum\limits_i (x_i - E[X \mid Y])^2 f(x_i \mid Y)$  
定理：$Var[X]=E[Var[X \mid Y]]+Var[E[X\mid Y]]$  


## 总结
$f(x\mid y)=f(x,y)/f_Y(y)$  
$Var X =EX^2-(EX)^2$  
$E(X\mid Y)=\sum\limits_x f(x \mid y)$  
$Var(X\mid Y)=\sum\limits_x(x-u_{x\mid y})^2f(x\mid y)$  
$EX=E(E(x\mid y))$  
$VarX=E(Var(X\mid Y))+Var(E(X\mid Y))$

---

## File: _drafts/丢弃/2017-08-23-pymysql.md

---
layout: post
title: 【丢弃】【Python】pymysql
categories:
tags:
keywords:
order:
---

**回收原因：[sqlalchemy](http://www.guofei.site/2018/03/21/sqlalchemy.html)对sqlite3和pymysql进行了良好的封装，因此在操作sql时，无需再过多关注底层的sqlite3和pymysql了**



pymysql是用Python调用MySQL的包  

另一篇[文章](http://www.guofei.site/2017/04/26/pysqlite.html)中讲了pysqlite的操作，pymysql的用法也类似。  

## 连接数据库
```py
import pymysql.cursors

config = {
          'host':'127.0.0.1',
          'port':3306,
          'user':'root',
          'password':'zhyea.com',
          'db':'employees',
          'charset':'utf8mb4',
          'cursorclass':pymysql.cursors.DictCursor,
          }

# Connect to the database
connection = pymysql.connect(**config)
```

## 插入数据

```py
from datetime import date, datetime, timedelta
# 获取明天的时间
tomorrow = datetime.now().date() + timedelta(days=1)

# 执行sql语句
try:
    with connection.cursor() as cursor:
        # 执行sql语句，插入记录
        sql = 'INSERT INTO employees (first_name, last_name, hire_date, gender, birth_date) VALUES (%s, %s, %s, %s, %s)'
        cursor.execute(sql, ('Robin', 'Zhyea', tomorrow, 'M', date(1989, 6, 14)));
    # 没有设置默认自动提交，需要主动提交，以保存所执行的语句
    connection.commit()

finally:
    connection.close();
```

## 查询

```py
# 获取雇佣日期
hire_start = datetime.date(1999, 1, 1)
hire_end = datetime.date(2016, 12, 31)

# 执行sql语句
try:
    with connection.cursor() as cursor:
        # 执行sql语句，进行查询
        sql = 'SELECT first_name, last_name, hire_date FROM employees WHERE hire_date BETWEEN %s AND %s'
        cursor.execute(sql, (hire_start, hire_end))
        # 获取查询结果
        result = cursor.fetchone()#dict
        #result = cursor.fetchmany(2)
        #result = cursor.fetchall()#list
        print(result)
    # 没有设置默认自动提交，需要主动提交，以保存所执行的语句
    connection.commit()

finally:
    connection.close();
```

## 其它
pymysql有个小问题，字段顺序是乱的。  
还有mysql官方的Python包：mysql-connector-python，用处差不多，

---

## File: _drafts/丢弃/2017-08-28-数据结构.md

[Binary file]

---

## File: _drafts/丢弃/2017-10-01-seabron.md

[Binary file]

---

## File: _drafts/丢弃/2017-10-28-hypothesistesting1.md

---
layout: post
title: 【丢弃】【假设检验】Python实现.
categories:
tags:
keywords:
---


*回收原因：发现了用ipython notebook直接嵌入网页的方法，阅读更加清晰，见于[这里](http://www.guofei.site/2017/10/27/hypothesistesting.html#title1)*  


参见[【假设检验】理论篇](http://www.guofei.site/2017/10/27/hypothesistesting.html)  


## 数据准备

```py
import pandas as pd
import scipy.stats as stats
df=pd.DataFrame(stats.norm.rvs(loc=0,scale=1,size=120).reshape(-1,3),columns=list('abc'))
df.loc[:,'c']=(df.loc[:,'c']>0)*1 #c这一列换成离散值
```

## 置信区间

```py
import statsmodels.api as sm

ds = sm.stats.DescrStatsW(df)
ds.tconfint_mean(alpha=0.05)
```
output:  

(array([-0.29225042, -0.36459267, -0.25896104]),  
 array([ 0.31800701,  0.2203038 ,  0.42702711]))  


分别是每列数的置信上界，置信下界。  


## 均值检验

p-value指的是H0为真的概率。  

### 方差未知

t检验  

```py
ds.ttest_mean(value=0.1)
```

输出的3个量分别是t-statistic, p-value, df  
p-value<0.05，拒绝原假设，均值不是0.1  



### 两独立样本

step1：方差齐次性检验

```py
(_,df1),(_,df2)=df.groupby('c')['a']
leveneTestRes = stats.levene(df1, df2, center='median')
print('w-value=%6.4f, p-value=%6.4f' %leveneTestRes)
```

如果p-value比较大，无法拒绝原假设。认为方差是齐性的  

step2：ttest
```py
stats.stats.ttest_ind(df1, df2, equal_var=True)#equal_var表示方差齐次
# Or Try: sm.stats.ttest_ind(df1, df2, usevar='pooled')
```

---

## File: _drafts/丢弃/2017-11-23-ModelEvaluation1.md

[Binary file]

---

## File: _drafts/丢弃/2018-02-03-hive.md

---
layout: post
title: 【丢弃】【Hive】基础知识.
categories: 
tags:
keywords:
order: 161
---

*回收原因：Hive 基本操作很简单，放到这另一篇文章里[【spark, Hive, Hadoop, yarn】汇总](http://www.guofei.site/2018/03/27/spark.html#title7)，更复杂的Hive操作建议使用 spark，因此这篇文章没必要了*
## CLI
命令行界面，是与Hive交互的最常用的方式  
### 1. hive执行脚本

hive -e “sql语句”  
会将查询的结果打印在控制台上。  
`-e` SQL from command line


hive -e “sql语句” > xxx  
会将查询的结果重定向到xxx文件中，会显示OK和抓取的数据条数


hive -S -e “sql语句” > xxx
会将查询的结果重定向到xxx文件中，不会显示OK和抓取的数据条数
`-S` Silent mode  


hive -f sqlfile.sql  
执行文件中的sql（用于sql比较长的时候）  
`-f` SQL from files  
一般把查询文件的后缀名设为.q或.hql


hive -i sqlfile  
执行文件中的sql（用于sql比较长的时候）， 执行完后就不退出，还可继续执行其他sql。在这种模式下若还要去执行其他文件中的sql， 需要在hive模式中使用 source sqlfile 来配合。


### 2. hive与linux交互
例如：当我们使用hive -i sqlfile时，已经进入hive模式中，这时候需要去执行其他的sqlfile，但是不知道sqlfile在什么路径下,这样就显得很尴尬了。  
在hive模式下使用叹号加命令加分号  
`! + linux 命令;`  


### 3. hive与hdfs交互
由于hive已经是运行在hadoop上所以直接可以使用  `dfs + hdfs命令;`

### 4. hive的注释
两个横线开头`-- 注释123`

### 5. 显示字段名
```
hive> set hive.cli.print.header=true;
```


## hive数据类型


- 整型
    - TINYINT — 微整型，只占用1个字节，只能存储0-255的整数。
    - SMALLINT– 小整型，占用2个字节，存储范围–32768 到 32767。
    - INT– 整型，占用4个字节，存储范围-2147483648到2147483647。
    - BIGINT– 长整型，占用8个字节，存储范围-2^63到2^63-1。
- 布尔型
    - BOOLEAN — TRUE/FALSE
- 浮点型
    - FLOAT– 单精度浮点数。
    - DOUBLE– 双精度浮点数。
- 字符串型
    - STRING– 不设定长度。
- TIMESTAMP
    - （最新版本支持）
    - 整数或浮点数：距离1970年1月1日的秒数
    - 字符串"YYYY-MM-DD hh:mm:ss.fffffffff"
    - 不支持时区

### 类型转换
... cast (s AS INT)...;


## 修改数据

Hive没有行级别的insert, update, delete 操作，装载数据唯一的途径就是“大量”数据装载操作。  



这样写，可以防止扫很多分区  

```
FROM staged_employee se
INSERT OVERWRITE TABLE employees PAERTITION (country='US, state='OR')
  SELECT * WHERE se.cnty='US' AND se.st='OR'
INSERT OVERWRITE TABLE employees
  PAERTITION (country='US, state='CA')
  SELECT * WHERE se.cnty='US' AND se.st='CA'
INSERT OVERWRITE TABLE employees
  PAERTITION (country='US, state='IL')
  SELECT * WHERE se.cnty='US' AND se.st='IL';
```

## 其它小知识点
### 压缩
Hive 不强制要求数据格式，Hive利用Hadoop的InputFormat API从不同数据源读取数据，例如文本格式、sequence格式，甚至用户自定义格式。  
压缩可以增加I/O吞吐量，但会增加CPU开销。不过Hadoop的job通常是I/O密集型，而不是CPU密集型，所以压缩可以提高性能。
## 函数
```sql
show functions;
desc function norm; -- 查询函数的详细用法
```

## 参考文献
《Hive编程指南》人民邮电出版社  
mySQL从入门到精通  
https://wenku.baidu.com/view/f7f6e6dcd1f34693daef3e8b.html
《Hive编程指南》Edward ，O‘REILLY  
[Hive 脚本执行](http://blog.csdn.net/zz657114506/article/details/53576711)  
http://flyingdutchman.iteye.com/blog/1868600

---

## File: _drafts/丢弃/2018-03-29-spark1.md

---
layout: post
title: 【丢弃】【spark】rdd.
categories: 
tags:
keywords:
order: 151
---

*回收原因：RDD过时了*
## 3. RDD
### 3.1. 初始化SparkContext
```py
from pyspark import SparkContext, SparkConf
conf=SparkConf().setMaster('local').setAppName('My App')#local可以改为local[*]，以增加核心数
sc=SparkContext(conf=conf)
```

### 3.2. 创建RDD
```py
lines=sc.parallelize(['pandas','i like pandas','hello','hello world!','error line','warning line'])
lines=sc.textFile('test.txt')
```


RDD有两种操作：**transformation**， **actions**
### 3.3 transformation
```py
RDD1.map(func)#func接受每一个元素，返回每一个元素，作为新RDD的元素
RDD1.filter(func)#筛选满足条件的RDD值，func接受每一个元素，返回一个bool类型
RDD1.flatMap(func) #如果func返回的是一个迭代器，那么把迭代器里所有对象放入新RDD中并摊平

#集合操作
RDD1.distinct()
RDD1.union(RDD2) #并集
RDD1.intersection(RDD2) #交集
RDD1.subtract(RDD2) #差集

RDD1.cartesian(RDD2) #笛卡尔积

RDD1.sample(withReplacement=False,fraction=0.2) #采样
```

例子：
```py
errorsRDD=lines.filter(lambda line:'error' in line)
warningRDD=lines.filter(lambda line:'warning' in line)

badRDD=errorsRDD.union(warningRDD)# 合并
```


### 3.4. actions

```py
RDD1.reduce(lambda x,y:x+y)
RDD1.fold(0,lambda x,y:x+y) #相当于一个带初始值的reduce

RDD1.foreach(func1) #对每个元素使用func1？？？
RDD1.aggregate(zeroValue,seqOp,combOp)# 没搞太清楚？？？

RDD1.collect()
RDD1.take(10)
RDD1.top(10)
RDD1.first()

RDD1.count()
RDD1.countByValue() #返回dict，内容是每个元素的个数
```



### 3.5. pair RDD

pair RDD是一种特殊的RDD  
转化：  
```py
pair_RDD1=sc.parallelize([(1,2),(5,2),(3,4),(3,3)])
pair_RDD2=sc.parallelize([(1,5),(6,2)])

pair_RDD1.reduceByKey(func) #分组应用func,例如func=lambda x,y:x+y。是transformation(对比reduce是actions)
pari_RDD1.foldByKey(0，func) #类似fold，带初始值的reduce。是transformation，fold是action


pair_RDD1.groupByKey() # 同一个key下的value变成[value1,value2,...]？？？没明白
combineByKey#???


pair_RDD1.flatMapValues(func) #func 每次接受1个value，返回iterable。返回的RDD保留key，摊平value
pair_RDD1.mapValues(func) #对每个value应用func，key保持不变


pair_RDD1.keys()#返回key组成的RDD
pair_RDD1.values()#返回value组成的RDD
pair_RDD1.sortByKey()#按照key排序
# 按key排序的高级玩法
pair_RDD1.sortByKey(ascending=True,keyfunc=lambda x:str(x)) #ascending默认为True，keyfunc可以把原本元素转化成新对象，然后用新对象排序
```
双pair RDD操作：
```py

pair_RDD1.subtractByKey(pair_RDD2) #删除key相同的元素
pair_RDD1.join(pair_RDD2)  #内连接，返回类似[(1, (2, 5))]的RDD
pair_RDD1.leftOuterJoin(pair_RDD2) #左边的保留
pair_RDD1.rightOuterJoin(pair_RDD2) #右边的保留
pair_RDD1.cogroup(pair_RDD2) #key-value的RDD，其中value是一个iterable

```

pari RDD的行动：
```py
countByKey() #返回key的计数
lookup(key) #返回key所对应的所有value
```


## row
```py
from pyspark.sql import Row
row=Row(k1=2,k2='abc',k3=99)

# 取数
row.k1
row['k1']
```


## 参考文献
https://blog.csdn.net/wy250229163/article/details/52354278

---

## File: _drafts/丢弃/2018-05-18-matplotlib5.md

---
layout: post
title: 【丢弃】【Python】图像的读写显
categories:
tags:
keywords:
order: 741
---

## matplotlib
### 读
```py
import matplotlib.pyplot as plt
a=plt.imread('image.jpg')
# a是一个m*n*3 的 np.array 对象
```

图像数组可以是以下类型
- (1) M*N      此时数组必须为浮点型，其中值为该坐标的灰度；
- (2) M*N*3  RGB（浮点型或者unit8类型）
- (3) M*N*4  RGBA（浮点型或者unit8类型）


### 显

```py
from scipy.stats import uniform
rv=uniform()
b=rv.rvs(size=(400,400,3))
plt.imshow(b)
plt.show()
```

## cv
```py
import cv2
a=cv2.imread('me.png')
# a是一个m*n*3 的 np.array 对象
```


## CV与PIL
格式互转  
https://blog.csdn.net/dcrmg/article/details/78147219

---

## File: _drafts/丢弃/2018-09-02-randomvariable.md

---
layout: post
title: 【丢弃】【随机变量】矩阵
categories:
tags:
keywords:
order: 9510
---

丢弃原因：整合到 [随机变量的数字特征](http://www.guofei.site/2019/10/02/numerical_characteristics_of_random_variables.html)

## 随机变量矩阵的推导
$$x=\left ( \begin{array}{ccc}  x_1\\x_2\\x_3\\...\\x_k \end{array} \right ),
y=\left ( \begin{array}{ccc}  y_1\\y_2\\y_3\\...\\y_k \end{array} \right )$$是随机变量矩阵  
a,b是常数，
$$c=\left ( \begin{array}{ccc}  c_1\\c_2\\c_3\\...\\c_k \end{array} \right ),
d=\left ( \begin{array}{ccc}  d_1\\d_2\\d_3\\...\\d_k \end{array} \right )$$是常数向量  
$A,B$是矩阵

那么有这些结论：  
#### 1. 定义均值和方差
$$Ex=\left ( \begin{array}{ccc}  Ex_1\\Ex_2\\Ex_3\\...\\Ex_k \end{array} \right )$$  
定义:$cov(x,y)=(cov(x_i,y_j))_ {p\times p}$
#### 2. 线性组合
$E(ax+c)=aEx+c$  
$D(bx+c)=b^2Dx$  


$E(Ax)=AE(x),E(x^TA^T)=E(x^T)A^T$  
$cov(c^Tx,d^Tx)=c^T D(x) d$  
（所以$D(c^Tx)=c^T D(x) c$）  

#### 3. 线性组合plus
$cov(y,x)=(cov(x,y))^T$  
$cov(Ax,y)=A cov(x,y)$(用定义展开立即可证)  
$cov(x,By)=(cov(By,x))^T=(Bcov(y,x))^T=(cov(y,x))^TB^T=cov(x,y)B^T$  


由上面两个式子，  
$cov(Ax,By)=Acov(x,y)B^T$

---

## File: _drafts/丢弃/2018-09-03-gaussian.md

---
layout: post
title: 【丢弃】正态分布的性质
categories:
tags:
keywords:
order: 9530
---

更清晰的内容更新到[这里](http://www.guofei.site/2017/05/27/distribution.html)

## 定义
$f(x_1,x_2,...x_p)=\dfrac{1}{(2\pi)^{p/2} \mid \Sigma \mid ^{1/2}} exp[-\dfrac{1}{2} (x-u)'\Sigma^{-1}(x-u)]$
where,  
- u是p阶向量
- $\Sigma$是p阶正定矩阵


叫做X服从p元正态分布， 记为$X \sim N_p(u,\Sigma)$

## 性质
如果$X=(X_1,X2,...X_p) \sim N_p(u,\Sigma)$  
### 性质1：均值和方差
$EX=u$  
$Var(X)=\Sigma$  


当$\mid\Sigma \mid =0 $,不存在密度函数。 当然可以给出一些形式上的表达式，使得可以统一处理。  


### 性质2：独立性
如果$\Sigma$是对角阵，那么$X_1,X_2,...,X_p$相互独立  


### 性质3：分块矩阵
做如下拆分：  
$$X=\left [\begin{array}{ccc}X^{(1\sim q)}\\ X^{(q+1 \sim p)} \end{array}\right],
u=\left [\begin{array}{ccc}u^{(1\sim q)}\\ u^{(q+1 \sim p)} \end{array}\right],
\Sigma=\left [\begin{array}{ccc}\Sigma_{11}&\Sigma_{12}\\ \Sigma_{21}&\Sigma_{22} \end{array}\right]$$,  
那么：
$X^{(1\sim q)}\sim N_q(u^{1\sim q},\Sigma_{11}), X^{(q+1 \sim p)} \sim N_q(u^{q+1\sim p},\Sigma_{22})$  


需要指出：
- 多元正态分布的任何边缘分布都是正态分布，反之不真。  
- $\Sigma_{12}=0$表示独立，所以多元正态分布拆分后不相关则独立  
- 两个正态分布不相关，不一定独立。只有是多元正态分布时，不相关才推出独立。  


### 性质4：线性组合
如果$A_{s\times p},d_{s\times 1}$都是常数矩阵，  
那么$AX+d\sim N_s(Au+d,A\Sigma A')$  

## 乘法
*参见[Products and Convolutions of Gaussian Probability
Density Functions](http://www.tina-vision.net/docs/memos/2003-003.pdf)*  
### 正态分布乘法的定义
*注意区别于随机变量的乘法*  
正态分布的乘法定义为概率密度函数相乘，然后乘以归一化系数使积分仍然是1.  


已知$N(u_i,\Sigma_i),i=1,...n$，对应的的概率密度函数是$f_i(x)=\dfrac{1}{(2\pi)^{p/2} \mid \Sigma_i \mid ^{1/2}} exp[-\dfrac{1}{2} (x-u_i)'\Sigma_i^{-1}(x-u_i)]$  
1. $\prod_{i=1}^n N(u_i,\Sigma_i)$仍然是一个正态分布
2. 新正态分布的方差满足$\dfrac{1}{\Sigma}=\sum \dfrac{1}{\Sigma_i}$  
3. 新正态分布的均值满足$\dfrac{u}{\Sigma}=\sum\dfrac{u_i}{\Sigma_i}$



## 参考文献
[Products and Convolutions of Gaussian Probability
Density Functions](http://www.tina-vision.net/docs/memos/2003-003.pdf)

---

## File: _drafts/丢弃/2018-09-20-nlp1.md

---
layout: post
title: 【丢弃】【NLP1】词袋
categories: 
tags:
keywords:
order: 301
---

*回收原因：tensorflow相关的包将被移除，有些功能用sklearn更加好读*  
*词向量转序号向量的功能，sklearn也没有提供，我在[另一篇博客写了一个类](http://www.guofei.site/2018/09/24/nlp_feature.html#title3)取完成这样的功能*

## 词袋
词袋（Bag of Words）  
先有一个常用词组成单词向量，非常用词的序号统一设定为0  
对于每一个句子，每个单词对应的索引设定为1  
例如，我们的词袋为
```py
['others','TensorFlow','makes','machine','learning','easy']
```
词袋的计算关系为
```py
sentence1='TensorFlow makes machine learning easy'
sentence1_list=[0,1,1,1,1,1]

sentence2='Machine learning is easy'
sentence2=[1,0,0,1,1,1]
# 这里，'is'没有出现在单词向量中，为0号
```

例子
### step1获取数据
```py
import pandas as pd
df=pd.read_csv('http://www.guofei.site/datasets/nlp/SMSSpamCollection.csv',sep='\t',header=None,names=['label','sentences'])
Y=(df.label=='spam')*1
```
### step2初步清洗
```py
import re
regex=re.compile('[a-zA-Z]+')
X1=[regex.findall(sentence) for sentence in df.sentences] # 只挑出单词，去除标点符号和数字
X2=[[i.lower() for i in j if len(i)>1] for j in X1] # 改成小写，并剔除单个字母
X=[' '.join(i) for i in X2] # 重新整合成句子


from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2)
```

### step3：使用TensorFlow做词袋
```py
import tensorflow as tf
from tensorflow.contrib import learn
vocab_processor=learn.preprocessing.VocabularyProcessor(max_document_length=25,min_frequency=3) # max_document_length 是每个句子最大的长度，短的补空值，长的截取
vocab_processor.fit(X)


embedding_size=len(vocab_processor.vocabulary_) # 词典向量的长度

# 使用案例：
vocab_processor.transform(['hello world','good morning']) # 返回一个generator，每个next对应入参中的一项（入参也必须是<iterable>）
# 每项是一个与入参对应项大小相同的向量，向量的值是每个word在vocab_processor.vocabulary_中的序号
# 例如，案例返回[237 327   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
# 前两个数字分别是'hello', 'world' 在 vocab_processor.vocabulary_中的位置，后面的0是用'其它'补到25

# vocab_processor.fit_transfrom(X)
```

### step4：定义占位符
```py
import tensorflow as tf
sess = tf.Session()
identity_mat = tf.diag(tf.ones(shape=[embedding_size]))

A = tf.Variable(tf.random_normal(shape=(embedding_size, 1)))
b = tf.Variable(tf.random_normal(shape=[1, 1]))
x = tf.placeholder(shape=[25], dtype=tf.int32)  # 序号组成的向量，将来用vocab_processor.transform()来feed
y = tf.placeholder(shape=[1, 1], dtype=tf.float32)

x_embed = tf.nn.embedding_lookup(identity_mat, x)
# 用法解释：
# sess.run(x_embed,feed_dict={x:next(vocab_processor.transform(['hello world']))})
# 一个shape=(max_document_length,vocab_processor.vocabulary_)的向量，第i行是第i个单词的OneHot编码

x_col_sum=tf.reduce_sum(x_embed,axis=0) # 上一步是每个单词的OneHot编码，现在加总成句子的OneHot编码
x_col_sum_2D=tf.expand_dims(x_col_sum,axis=0)

# 下面做softmax
a=tf.matmul(x_col_sums_2D,A)+b
y_hat=tf.nn.sigmoid(a)
cross_entropy=tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=a, labels=y))
# 等价写法：
# y_hat=tf.nn.sigmoid(tf.matmul(x_col_2D,A)+b)
# cross_entropy = tf.reduce_mean(-tf.reduce_sum(y * tf.log(y_hat), axis=1))

train_step = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(cross_entropy)
```
### step5:训练阶段
```py
sess.run(tf.global_variables_initializer())
for i,j in enumerate(vocab_processor.transform(X)):
    sess.run(train_step,feed_dict={x:j,y:[[Y[i]]]})


# 预测阶段
Y_predict=[]
for i,j in enumerate(vocab_processor.transform(X)):
    if i % 100 == 0: print(i)
    Y_predict.append(sess.run(y_hat,feed_dict={x:j})[0][0])


# 评价阶段
from sklearn.metrics import roc_auc_score
roc_auc_score(Y,Y_predict)
```

注：上面的案例改编自Nick McClure:《TensorFlow机器学习实战指南》  
有如下问题：
1. 每次训练只送入一个样本，对于随机梯度下降比较糟糕，并且工程上迭代也慢。
2. 样本偏斜严重
3. 4000多个样本，2000多个维度
4. tensorflow.contrib.learn 将会DEPRECATED


## 改进
下面把处理OneHot后存储为csv，然后批量读取csv去训练模型（很占内存，慎重！）
### step1:处理OneHot，并存储为csv
```py
import pandas as pd
df=pd.read_csv('SMSSpamCollection.csv',sep='\t',header=None,names=['label','sentences'])
Y=(df.label=='spam')*1

import re
regex=re.compile('[a-zA-Z]+')
X1=[regex.findall(sentence) for sentence in df.sentences] # 只挑出单词，去除标点符号和数字
X2=[[i.lower() for i in j if len(i)>1] for j in X1] # 改成小写，并剔除单个字母
X=[' '.join(i) for i in X2] # 重新整合成句子


from tensorflow.contrib import learn
vocab_processor=learn.preprocessing.VocabularyProcessor(max_document_length=25,min_frequency=3) # max_document_length 是每个句子最大的长度，短的补空值，长的截取
vocab_processor.fit(X)


embedding_size=len(vocab_processor.vocabulary_) # 词典向量的长度



import tensorflow as tf
sess = tf.Session()
identity_mat = tf.diag(tf.ones(shape=[embedding_size]))

A = tf.Variable(tf.random_normal(shape=(embedding_size, 1)))
b = tf.Variable(tf.random_normal(shape=[1, 1]))
x = tf.placeholder(shape=[25], dtype=tf.int32)  # 序号组成的向量，将来用vocab_processor.transform()来feed
y = tf.placeholder(shape=[1, 1], dtype=tf.float32)

x_embed = tf.nn.embedding_lookup(identity_mat, x)
x_col_sum=tf.reduce_sum(x_embed,axis=0) # 上一步是每个单词的OneHot编码，现在加总成句子的OneHot编码
x_col_sum_2D=tf.expand_dims(x_col_sum,axis=0)


f_X=open('X_embed.csv','w')
for i in vocab_processor.transform(X):
    x_col_sums_2D_values=sess.run(x_col_sum_2D,feed_dict={x:i})[0]
    f_X.writelines(','.join([str(j) for j in x_col_sums_2D_values])+'\n')
f_X.close()

f_Y=open('Y.csv','w')
f_Y.writelines(','.join([str(i) for i in Y]))
f_Y.close()
```

下面是读数据和普通的逻辑回归
```py
import pandas as pd
X_embed=pd.read_csv('X_embed.csv',header=None).values
Y=pd.read_csv('Y.csv',header=None).values[0].reshape(-1,1)

num_sample,num_features=X_embed.shape


# 定义变量
import tensorflow as tf

x_embed=tf.placeholder(shape=(None,num_features),dtype=tf.float32)
y=tf.placeholder(shape=(None,1),dtype=tf.float32)
A=tf.Variable(tf.truncated_normal(shape=(num_features,1),dtype=tf.float32))
b=tf.Variable(tf.truncated_normal(shape=(1,1),dtype=tf.float32))
a=tf.matmul(x_embed,A)+b
y_hat=tf.nn.sigmoid(a)
cross_entropy=tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=a, labels=y))
train_step=tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(cross_entropy)

sess=tf.Session()
sess.run(tf.global_variables_initializer())


a_list=[]
import numpy as np
batch_size=30
for i in range(200):
    choice_index=np.random.choice(num_sample,size=batch_size)
    sess.run(train_step,feed_dict={x_embed:X_embed[choice_index],y:Y[choice_index]})
```

## 参考资料
Nick McClure:《TensorFlow机器学习实战指南》 机械工业出版社  
lan Goodfellow:《深度学习》 人民邮电出版社  
王琛等：《深度学习原理与TensorFlow实战》 电子工业出版社  
李嘉璇：《TensorFlow技术解析与实战》 人民邮电出版社  
黄文坚：《TensorFlow实战》 电子工业出版社  
郑泽宇等：《TensorFlow实战Google深度学习框架》 电子工业出版社

---

## File: _drafts/丢弃/2018-09-21-nlp2.md

---
layout: post
title: 【丢弃】【NLP2】word2vec
categories: 
tags:
keywords:
order: 301
---

*回收原因，这是之前仿照网络写的 word2vec，后来自己重写了一遍，[新的](http://www.guofei.site/2017/12/17/word2vec.html)更好读*  



## word2vec
```py
import tensorflow as tf
import numpy as np
import string
import collections
from tensorflow.python.framework import ops

# %%
ops.reset_default_graph()

# os.chdir(os.path.dirname(os.path.realpath(__file__)))

# Start a graph session
sess = tf.Session()

# Declare model parameters
batch_size = 100
embedding_size = 200
vocabulary_size = 10000
generations = 100000
print_loss_every = 2000

num_sampled = int(batch_size / 2)  # Number of negative examples to sample.
window_size = 2  # How many words to consider left and right.

# Declare stop words
# import nltk
# nltk.download() # 需要先执行这个来下载数据，否则报错
# nltk.download('stopwords')
from nltk.corpus import stopwords
stops = stopwords.words('english')

# We pick five test words. We are expecting synonyms to appear
print_valid_every = 5000
valid_words = ['cliche', 'love', 'hate', 'silly', 'sad']

# %%
import pandas as pd


url_neg = 'https://www.guofei.site/datasets/nlp/rt-polaritydata/rt-polarity.neg.txt'
url_pos = 'https://www.guofei.site/datasets/nlp/rt-polaritydata/rt-polarity.pos.txt'
df_neg = pd.read_csv(url_neg, sep='\t', header=None, names=['text'])
df_pos = pd.read_csv(url_pos, sep='\t', header=None, names=['text'])
texts = list(df_pos.text) + list(df_neg.text)
target = [1] * df_pos.shape[0] + [0] * df_neg.shape[0]


# %%

# Normalize text
def normalize_text(texts, stops):
    # Lower case
    texts = [x.lower() for x in texts]

    # Remove punctuation
    texts = [''.join(c for c in x if c not in string.punctuation) for x in texts]

    # Remove numbers
    texts = [''.join(c for c in x if c not in '0123456789') for x in texts]

    # Remove stopwords
    texts = [' '.join([word for word in x.split() if word not in stops]) for x in texts]

    # Trim extra whitespace
    texts = [' '.join(x.split()) for x in texts]

    return texts


texts = normalize_text(texts, stops)

# 影评要3个字以上才是有效的分析对象
# Texts must contain at least 3 words
target = [target[ix] for ix, x in enumerate(texts) if len(x.split()) > 2]
texts = [x for x in texts if len(x.split()) > 2]


# !!! 这里有个大问题：单个字母的单词也保留了

# %%
# 6. 创建词汇表
# Build dictionary of words
def build_dictionary(sentences, vocabulary_size):
    # Turn sentences (list of strings) into lists of words
    split_sentences = [s.split() for s in sentences]
    words = [x for sublist in split_sentences for x in sublist]

    # Initialize list of [word, word_count] for each word, starting with unknown
    count = [['RARE', -1]]

    # Now add most frequent words, limited to the N-most frequent (N=vocabulary size)
    count.extend(collections.Counter(words).most_common(vocabulary_size - 1))

    # Now create the dictionary
    word_dict = {}
    # For each word, that we want in the dictionary, add it, then make it
    # the value of the prior dictionary length
    for word, word_count in count:
        word_dict[word] = len(word_dict)

    return word_dict


# Build our data set and dictionaries
word_dictionary = build_dictionary(texts, vocabulary_size)


# %%
# Turn text data into lists of integers from dictionary
def text_to_numbers(sentences, word_dict):
    # Initialize the returned data
    data = []
    for sentence in sentences:
        sentence_data = []
        # For each word, either use selected index or rare word index
        for word in sentence.split(' '):
            if word in word_dict:
                word_ix = word_dict[word]
            else:
                word_ix = 0
            sentence_data.append(word_ix)
        data.append(sentence_data)
    return data


word_dictionary_rev = dict(zip(word_dictionary.values(), word_dictionary.keys()))
text_data = text_to_numbers(texts, word_dictionary)
# !text_data是 序号列表，序号是在vocabulary中的index


# %%
# Get validation word keys
# 待评估的单词在vocabulary中的index
valid_examples = [word_dictionary[x] for x in valid_words]


# %%
# 返回 skip-gram 模型数据
# Generate data randomly (N words behind, target, N words ahead)
def generate_batch_data(sentences, batch_size, window_size, method='skip_gram'):
    # Fill up data batch
    batch_data = []
    label_data = []
    while len(batch_data) < batch_size:
        # select random sentence to start
        rand_sentence = np.random.choice(sentences)
        # Generate consecutive windows to look at
        window_sequences = [rand_sentence[max((ix - window_size), 0):(ix + window_size + 1)] for ix, x in
                            enumerate(rand_sentence)]
        # Denote which element of each window is the center word of interest
        label_indices = [ix if ix < window_size else window_size for ix, x in enumerate(window_sequences)]

        # Pull out center word of interest for each window and create a tuple for each window
        if method == 'skip_gram':
            batch_and_labels = [(x[y], x[:y] + x[(y + 1):]) for x, y in zip(window_sequences, label_indices)]
            # Make it in to a big list of tuples (target word, surrounding word)
            tuple_data = [(x, y_) for x, y in batch_and_labels for y_ in y]
        elif method == 'cbow':
            batch_and_labels = [(x[:y] + x[(y + 1):], x[y]) for x, y in zip(window_sequences, label_indices)]
            # Make it in to a big list of tuples (target word, surrounding word)
            tuple_data = [(x_, y) for x, y in batch_and_labels for x_ in x]
        else:
            raise ValueError('Method {} not implemented yet.'.format(method))

        # extract batch and labels
        batch, labels = [list(x) for x in zip(*tuple_data)]
        batch_data.extend(batch[:batch_size])
        label_data.extend(labels[:batch_size])
    # Trim batch and label at the end
    batch_data = batch_data[:batch_size]
    label_data = label_data[:batch_size]

    # Convert to numpy array
    batch_data = np.array(batch_data)
    label_data = np.transpose(np.array([label_data]))

    return batch_data, label_data


# 示例：
# batch_inputs, batch_labels = generate_batch_data(text_data, batch_size, window_size)
# 将来的预测输入：feed_dict = {x_inputs: batch_inputs, y_target: batch_labels}

# %%
# Define Embeddings:
embeddings = tf.Variable(tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))

# NCE loss parameters
nce_weights = tf.Variable(tf.truncated_normal([vocabulary_size, embedding_size], stddev=1.0 / np.sqrt(embedding_size)))
nce_biases = tf.Variable(tf.zeros([vocabulary_size]))

# Create data/target placeholders
x_inputs = tf.placeholder(tf.int32, shape=[batch_size])
y_target = tf.placeholder(tf.int32, shape=[batch_size, 1])
valid_dataset = tf.constant(valid_examples, dtype=tf.int32)

# Lookup the word embedding:
embed = tf.nn.embedding_lookup(embeddings, x_inputs)

# %%
# Define Embeddings:
embeddings = tf.Variable(tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))

# NCE loss parameters
nce_weights = tf.Variable(tf.truncated_normal([vocabulary_size, embedding_size], stddev=1.0 / np.sqrt(embedding_size)))
nce_biases = tf.Variable(tf.zeros([vocabulary_size]))

# Create data/target placeholders
x_inputs = tf.placeholder(tf.int32, shape=[batch_size])
y_target = tf.placeholder(tf.int32, shape=[batch_size, 1])
valid_dataset = tf.constant(valid_examples, dtype=tf.int32)

# Lookup the word embedding:
embed = tf.nn.embedding_lookup(embeddings, x_inputs)

# Get loss from prediction
loss = tf.reduce_mean(
    tf.nn.nce_loss(weights=nce_weights, biases=nce_biases, labels=y_target, inputs=embed, num_sampled=num_sampled,
                   num_classes=vocabulary_size))

# Create optimizer
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1.0).minimize(loss)

# Cosine similarity between words
norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keepdims=True))
normalized_embeddings = embeddings / norm
valid_embeddings = tf.nn.embedding_lookup(normalized_embeddings, valid_dataset)
similarity = tf.matmul(valid_embeddings, normalized_embeddings, transpose_b=True)

# Add variable initializer.
init = tf.global_variables_initializer()
sess.run(init)

# Run the skip gram model.
loss_vec = []
loss_x_vec = []
for i in range(generations):
    batch_inputs, batch_labels = generate_batch_data(text_data, batch_size, window_size)
    feed_dict = {x_inputs: batch_inputs, y_target: batch_labels}

    # Run the train step
    sess.run(optimizer, feed_dict=feed_dict)

    # Return the loss
    if (i + 1) % print_loss_every == 0:
        loss_val = sess.run(loss, feed_dict=feed_dict)
        loss_vec.append(loss_val)
        loss_x_vec.append(i + 1)
        print('Loss at step {} : {}'.format(i + 1, loss_val))

    # Validation: Print some random words and top 5 related words
    if (i + 1) % print_valid_every == 0:
        sim = sess.run(similarity, feed_dict=feed_dict)
        for j in range(len(valid_words)):
            valid_word = valid_words[j]
            # top_k = number of nearest neighbors
            top_k = 5
            nearest = (-sim[j, :]).argsort()[1:top_k + 1]
            log_str = "Nearest to {}:".format(valid_word)
            for k in range(top_k):
                close_word = word_dictionary_rev[nearest[k]]
                log_str = '{} {},'.format(log_str, close_word)
            print(log_str)
```


## 参考资料
https://blog.csdn.net/pipisorry/article/details/41957763  
Nick McClure:《TensorFlow机器学习实战指南》 机械工业出版社  
lan Goodfellow:《深度学习》 人民邮电出版社  
王琛等：《深度学习原理与TensorFlow实战》 电子工业出版社  
李嘉璇：《TensorFlow技术解析与实战》 人民邮电出版社  
黄文坚：《TensorFlow实战》 电子工业出版社  
郑泽宇等：《TensorFlow实战Google深度学习框架》 电子工业出版社

---

## File: _drafts/丢弃/2019-10-06-spark_serialize.md

---
layout: post
title: 【丢】【spark】模型持久化
categories:
tags:
keywords:
order: 173
---



##  PickleSerializer

准备你的模型
```python
from sklearn import linear_model

lm=linear_model.LinearRegression()
x=np.random.rand(1000,1)
y=x+0.1*np.random.rand(1000,1)
lm.fit(x,y)
```

模型转为文本
```python
from pyspark import PickleSerializer
ps=PickleSerializer()
model_str=ps.dumps(obj=lm)
# 是一个 byte 类型的数据，然后可以存到hive了
# 存hive略，要先用 str(model_str) 转为str，然后存hive
# 从hive读取时，用 eval() 转回 Byte 格式
```

文本转模型
```python
from pyspark import PickleSerializer
ps=PickleSerializer()
model_load=ps.loads(model_str)
model_load.predict([[0.1]])
```

### 另外
这个可以序列化 iterator，不过还没试过

```Python
ps.dump_stream
ps.load_stream
```

MarshalSerializer：faster than PickleSerializer but supports fewer datatypes

---

## File: _drafts/丢弃/神经网络/2017-12-07-ANN9.md

---
layout: post
title: 【过时】神经网络中的若干问题
categories:
tags: 
keywords:
order: 260
---

几年前的多篇学习笔记，里面散落有很多过时内容。  
把这些过时内容更新掉，作为纪念不舍得删，就同一移动到这里了。
## 训练方式

### 更新频率

How often to update the weights
- Online ：after each training case
- Full batch:after a full sweep
- Mini-batch:after a small sample of training data

### 学习率

- fixed learning rate
- Adapt the global learning rate
- Adapt the learning rate on each connection
- Don't use steepest descent
### overfitting

- 原因
  - data不好
  - target values unreliable
	  - sampling error （eg: rectangle）
    - regularities:不知道是真实regularities还是sampling error

- Ways to reduce overfitting
  - Weight-decay:keep weights small
  - Weight-sharing: insisting that many of the weights have the same value
  - early stopping
  - model averaging:train lots of different nenual nets. And average them
  - Bayesian fitting of nrnual nets: A fancy form of model averaging
  - Dropout：emitting hidden layer
  - Generative pre-trainning: （后面会讲到）



---------
## 关于认知

### The feature theory

- A concept is a set of semantic features.
- 因此knowledge以a vector of feature来表示

### The structuralist theory

- The meaning of concept lies in its relationships to other concept
- 因此knowledge以relational graph 来表示

------
案例1：预测下一个word
见附件

-------
## 案例2：图像中的物体识别（LEC5）

### 困难

- segmentation
    - to tell which pieces is parts of the same object
    - parts of an object can be hidden behind other object
- Lighting
- Deformation
    - 各个部位变形，仍然是这个东西
- 不同的造型，相同的功能，仍然叫一个名字
    - 例如，椅子
- Viewpoint
    - dimension hop

#### 解决方案:针对viewpoint

- redundant invariant features
- put a box around the object and use normalized pixels.
- replicated features with pooling. (convolutional neural nets)CNN 卷积神经网络
- use a hierarchy of parts that have explicit poses relative to the camera

### 针对dimension-hopping

解决方案： The judicious normalization approach
具体方法： put a box around the object and use it as a coordinate frame
优点：解决 translation, totation, scale, shear, stretch
然而，找到合适的box比较困难：
- segmentation errors
- occlusion（？遮光）
- unusual orientation(?为什么呢)
- 事实上，人脑是先识别再旋转的

首先要recognize the shape to get the box right.
- 解决box的方案： the brute force normalization
具体方法： train阶段，用竖直的、切分良好的样本。test阶段遍历box所有的可能性


#### CNN模型

to constrain $w_1=w_2$
we need $\Delta w_1= \Delta w_2$
use $\frac{\partial E}{\partial w_1}+\frac{\partial E}{\partial w_2}$

------
传统神经网络采用back propagation
但是，
- 层数太深，残差传播到最前面的层已经变得太小，，误差校正信号越来越小，出现所谓gradient diffusion。
- 局部最小值（随机初始化导致的）
- 只能做有监督学习
deep learning 用layer-wise pre-training
deep learning的训练包括两步：训练和调优
1. 训练： 逐层训练单层神经元，这样每次按单层神经元训练
2. 调优： 所有层训练完后，用wake-sleep 算法调优
		1. 向上的权重用于“认知”，向下的权重用于“+生成”，wake-sleep 算法用来使认知和生成达成一致
		2. wake阶段： 认知过程，通过外界的特征和向上的权重（认知权重）产生每一层的抽象表示（结点状态），并且使用梯度下降修改层间的下行权重（生成权重）。也就是“如果现实跟我想象的不一样，改变我的权重使得我想象的东西就是这样的”。
    3. sleep阶段：生成过程，通过顶层表示（醒时学得的概念）和向下权重，生成底层的状态，同时修改层间向上的权重。也就是“如果梦中的景象不是我脑中的相应概念，改变我的认知权重使得这种景象在我看来就是这个概念”。

####	deep learning训练过程具体如下：

1）使用自下上升非监督学习（就是从底层开始，一层一层的往顶层训练）：
采用无标定数据（有标定数据也可）分层训练各层参数，这一步可以看作是一个无监督训练过程，是和传统神经网络区别最大的部分（这个过程可以看作是feature learning过程）：
具体的，先用无标定数据训练第一层，训练时先学习第一层的参数（这一层可以看作是得到一个使得输出和输入差别最小的三层神经网络的隐层），由于模型capacity的限制以及稀疏性约束，使得得到的模型能够学习到数据本身的结构，从而得到比输入更具有表示能力的特征；在学习得到第n-1层后，将n-1层的输出作为第n层的输入，训练第n层，由此分别得到各层的参数；
2）自顶向下的监督学习（就是通过带标签的数据去训练，误差自顶向下传输，对网络进行微调）：
基于第一步得到的各层参数进一步fine-tune整个多层模型的参数，这一步是一个有监督训练过程；第一步类似神经网络的随机初始化初值过程，由于DL的第一步不是随机初始化，而是通过学习输入数据的结构得到的，因而这个初值更接近全局最优，从而能够取得更好的效果；所以deep learning效果好很大程度上归功于第一步的feature learning过程。

---

## File: _drafts/笔记不发布/有一次来学随机过程了.md

[Binary file]

---

## File: _drafts/笔记不发布/群体智能算法相关.md

[Binary file]

---

## File: _drafts/线性代数/行列式.md

[Binary file]

---

## File: _drafts/进行中/2017-12-01-pls.md

---
layout: post
title: 【PLS】偏最小二乘法.
categories:
tags: 4统计模型
keywords:
order: 410
---

## 模型介绍
偏最小二乘法(partial least squares,PLS)是一种为解决多重共线性问题而提出的一种 **有偏估计** 回归方法。  



## 参考资料
[^lihang]: [李航：《统计学习方法》](https://www.weibo.com/u/2060750830?refer_flag=1005055013_)  
[^EM]: 我的另一篇博客[EM算法理论篇](http://www.guofei.site/2017/11/09/em.html)  
[^AppliedRegression]: 《应用回归分析》，人民大学出版社

---

## File: _drafts/进行中/2018-05-22-hypothesistesting1.md

---
layout: post
title: 【实验设计】理论篇
categories:
tags: 4统计模型
keywords:
order: 407
---

## 方差分析
### 单因素方差分析
上一篇文章已经设计方差分析了，这里详细分析。   
前提假设  
$x_{ij}=u+\delta_i+\varepsilon_{ij}$  
$\varepsilon_{ij \sim N(0,\sigma^2)}$  


H0:$\delta_1=\delta_2=...=\delta_a=0$

### 双因素方差分析
前提假设
$x_{ij}=u+a_i+b_j+\varepsilon_{ij}$  
$\varepsilon_{ij}\sim N(0,\sigma^2)$  
$\sum a_i =\sum b_j=0$  


H0：
$a_i=b_j=0,\forall i,j$  

## 正交试验设计
$L_n(m^k)$  
n是表的行数，也就是安排实验的次数  
k是表的列数，也就是因素的个数
m是每个因素的水平数，表的主题部分，每列最多出现m种数据。

---

## File: _drafts/进行中/2018-12-03-statistic.md

---
layout: post
title: 有趣的统计问题
categories: 趣文
tags:
keywords:
---


## Monty Hall 难题
游戏规则

游戏参赛者会看见三扇关闭了的门，其中一扇的后面有一辆汽车，选中后面有车的那扇门就可以赢得该汽车，而另外两扇门后面则各藏有一只山羊。当参赛者选定了一扇门，但未去开启它的时候，节目主持人会开启剩下两扇门的其中一扇，露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。问题是：换另一扇门会否增加参赛者赢得汽车的机会率？

贝叶斯解法

---

## File: _drafts/进行中/2018-12-23-optimal_control_theory.md

---
layout: post
title: 【动态最优化】最优控制
categories:
tags: 0x56_最优化
keywords:
order: 7403
---

## 问题定义
### 最简单的最优控制问题
$\max V =\int_0^T F(t,y,u)dt$  
s.t.  
$\dot y =f(t,y,u)$  
$y(0)=A,Y(T)$自由，($A,T$给定)  
$u(t)\in \mathscr{U}$  

$u(t)$分段连续  
$y(t)$连续，分段可微，有限个不可微点（实际上，$u$的不连续点和$y$的不可微点所在时间$t$一一对应）  




## 参考文献
【美】蒋中一：《动态最优化基础》，中国人民大学出版社  
莫顿，南茜：《动态优化：经济学和管理学中的变分法和最优控制》，中国人民大学出版社

---

## File: _drafts/进行中/2019-03-17-statsmodels_gls.md

[Binary file]

---

## File: _drafts/进行中/2019-04-14-mixed_lm.md

---
layout: post
title: 【statsmodels】Linear Mixed Effects Models
categories:
tags: 0x41_统计模型
keywords:
order: 409
---

[官网](https://www.statsmodels.org/stable/examples/index.html)和
[代码](https://www.statsmodels.org/stable/examples/notebooks/generated/recursive_ls.html)


## 简介
这一部分总结自[wikipedia](https://en.wikipedia.org/wiki/Mixed_model)  

一般的线性模型是这样的：  
$Y=X\beta+\varepsilon$  
其中，
- $E(Y)=X\beta$
- $\varepsilon \sim N(0,\sigma_0^2)$ （独立、等方差、均值0、正态分布）


混合线性模型是这样的:  
$Y=X\beta+Zu+\varepsilon$  
其中，  
- $E(Y)=X\beta$
- $\beta$ is an unknown vector of fixed effects
- $u$ is an unknown vector of random effects, with mean $E(u)=0$ and $Var(u)=G$
- $\varepsilon$ is an unknown vector of random errors, with mean $E \varepsilon =0$ and variance $Var(\varepsilon)=R$
- $X$ and $Z$ are known design matrices relating the observations $y$ to $\beta$ and $u$, respectively.



当$Z=0,R=\sigma_e^2 I$时，混合线形模型转变为一般线形模型。



### Linear Mixed Effects Models
smf.mixedlm  


#### 理论  
对第i个group：  
$Y=X\beta+Z\gamma+\varepsilon$  
其中，  
$n_i$是样本数，$k_{fe}$指的是 fixed effect 对应的变量数，$k_{re}$指的是 random effect 对应的变量数  
$Y_{n_i\times 1}$  
$X_{n_i\times k_{fe}},\beta_{k_{fe}\times 1}$ fixed effect对应的样本和参数  
$Z_{n_i\times k_{re}},\gamma_{k_{re}\times1}$ random effect 对应的样本和参数  
$\gamma$的期望为0，协方差矩阵为$\Psi$，each group gets its own independent realization of gamma  
$\varepsilon$均值为0，方差为$\sigma^2 I$,并且group内和group间都独立。  


#### 性质1  
$X,Y,Z$都是观察得到的样本  
$\beta,\Psi,\sigma^2$ 是需要估计出的量(使用ML或REML估计算法)  
#### 性质2
$E[Y\mid X,Z]=X\beta$  




有两种特殊的Linear Mixed Effects Model
- random intercepts models
- random slopes models


官网案例  


step1：加载包和数据  
```py
import numpy as np
import statsmodels.api as sm
import statsmodels.formula.api as smf
data = sm.datasets.get_rdataset('dietox', 'geepack').data
```

step2：  
a random intercept for each group
```py
md = smf.mixedlm("Weight ~ Time", data, groups=data["Pig"])
mdf = md.fit()
print(mdf.summary())
```


step3：  
a random intercept+a random slope
```py
md = smf.mixedlm("Weight ~ Time", data, groups=data["Pig"], re_formula="~Time")
mdf = md.fit()
print(mdf.summary())
```


step4:  
```py
md = smf.mixedlm("Weight ~ Time", data, groups=data["Pig"],re_formula="~Time")
free = sm.regression.mixed_linear_model.MixedLMParams.from_components(np.ones(2),np.eye(2))
mdf = md.fit(free=free)
print(mdf.summary())
```

---

## File: _drafts/进行中/2019-04-14-recursive_least_squares.md

---
layout: post
title: 【statsmodels】Recursive least squares
categories:
tags: 0x41_统计模型
keywords:
order: 409
---

[官网](https://www.statsmodels.org/stable/examples/index.html)和
[代码](https://www.statsmodels.org/stable/examples/notebooks/generated/recursive_ls.html)


## 简介

---

## File: _drafts/进行中/a.md

```
derivative(func, x0, dx=1.0, n=1, args=(), order=3)

```
func 被导函数
x0
dx
n n阶导数
order：用多少个点

---

## File: _drafts/进行中/ANN零碎笔记.md

## TF安装
conda install tensorflow


## 实际的计算方式
随机梯度下降：不用全部数据来计算Loss，而是使用每个batch，类似于Sampling


## 问题
梯度消失问题：Loss过早的不再下降，精确度过早地不再提高
y过于接近0或者1（概率还是挺大的，参见sigmoid）

解决方法：用ReLu
ReLu：$y=max(x,0)$


## RNN

当然可以使用梯度下降来计算，但期数很多时，计算量非常大，还会引发梯度爆炸和梯度消失的问题。  
人们发现了LSTM的算法代替BPTT算法实现RNN的训练  

### LSTM算法
Long Short-Term Memory


### 深度残差网络

深度网络有个巨大的问题，就是容易出现梯度消失和梯度爆炸。  
深度残差网络引入“短路”设计

### 受限玻尔兹曼机

受限玻尔兹曼机(RBM,restricted boltzmann machine)
#### DBN（deep belief network，深度信念网络）
DBN由多个RBM组成，Hitton提出DBN，验证了Greedy Layer-wise Training  
DBN对每层进行无监督训练，训练方法可以是标准的RBM，各层训练完毕后，用BP算法进行微调。

#### 损失函数
RBM的cost Function称为对比散度函数(contrasive divergence，CD)  
学习的目标是最大似然度。  


RBM有一种解释是能量解释，基于能量模型(energy-based model)  
$E(v,h \mid \theta)=-(\sum\limits_{ij}w_{ij}v_ih_j+\sum\limits_ib_iv_i+\sum\limits_jc_jh_j)$  


实现案例：
https://github.com/meownoid/tensorfow-rbm
https://github.com/Cospel/rbm-ae-tf

## reinforcement learning
Q-Learning
## 对抗学习
对抗网络(generative adversarial networks,GAN)  


有两个模型：
- G模型(generative model)用来根据样本，捏造一些样本
- D模型(discriminative model)用来做分类


如果D能把所有G生成的样本都判别为假，说明D很强，G很弱，  
如果D不能正确判别，说明D很弱，G很强。


评价函数这样写：  
$\min\limits_{G}\max\limits_{D} V(D,G)$  
$V(D,G)=E_{x\sim Pdata(x)}[\log D(x)]+E_{z\sim Pz(z)}[\log(1-D(G(z)))]$  
$D(x)$是真实图片判断为真实的概率  
$G(x)$是z噪声输入到G网络，并输出一张图片的过程



## 深度学习的领军人

Hinton，LeCun，Bengio  
这三人是祖师三代。
Hinton2006年提出了深度神经网络算法，可以对7层以上神经网络进行训练。此前还发明了反向传播法、对比散度算法。    
LeCun：第一位把BP算法用于CNN上  


德国人Schmidhuber，发明了LSTM，梯度消失的贡献者，递归结构的推动者  
李飞飞  
吴恩达  
Hopfield：80年代神经网络复兴，一般功劳应当归功于他。  


Minsky：构建第一部能自我学习的神经网络机器SNARC

## BP
BP推荐使用：3层（能解决大部分问题）  
hidden layer中神经元的个数推荐是$\sqrt{n_{input}+n_{output}} \pm 10$个

---

## File: _drafts/进行中/一些有用的python代码.md

计算一个文件的md5值
```
m = hashlib.md5()
with open(filename, 'rb') as f:
    bytes = f.read(1024)
    while (bytes != b''):
        m.update(bytes)
        bytes = f.read(1024)
res = m.hexdigest()
res
```



tar

```
import  tarfile

tar  =  tarfile.open( " temp.tar " , " w " )
 for  file  in  files:
    tar.add(file)#www.iplaypy.com

tar.close()
```

gzip
```
import gzip
```

---

## File: _drafts/进行中/中文乱码问题.md

报这个错：  
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-8: ordinal not in range(128)

解决方案：

```py
import sys
stdi,stdo,stde=sys.stdin,sys.stdout,sys.stderr
reload(sys)
sys.stdin,sys.stdout,sys.stderr=stdi,stdo,stde
sys.setdefaultencoding('utf-8')
```


## 编码格式

有时候，乱码来自字符串的编码格式
```py
unicodestring = u"Hello world"

# 将Unicode转化为普通Python字符串："encode"  
utf8string = unicodestring.encode("utf-8")  
asciistring = unicodestring.encode("ascii")  
isostring = unicodestring.encode("ISO-8859-1")  
utf16string = unicodestring.encode("utf-16")  

# 将普通Python字符串转化为Unicode："decode"  
plainstring1 = unicode(utf8string, "utf-8")  
plainstring2 = unicode(asciistring, "ascii")  
plainstring3 = unicode(isostring, "ISO-8859-1")  
plainstring4 = unicode(utf16string, "utf-16")  

assert plainstring1 == plainstring2 == plainstring3 == plainstring4
```

## 中文注释
```py
# coding=utf-8
```

---

## File: _drafts/进行中/凸优化.md

凸优化之所以如此重要，是因为凸优化的重要特性： **凸优化的任意局部最优解也是全局最优解。**



区别是与牛顿法求极值，牛顿法求方程的迭代式是这样的：
$f(x)=0$:  
$x_{n+1}=x_n-\dfrac{f(x_n)}{f'(x_n)}$

---

## File: _drafts/进行中/大数据架构视频笔记.md

[Binary file]

---

## File: _drafts/进行中/小波神经网络.md

小波神经网络（Wavelet Neural Network，简称WNN）是一种结合了小波分析与人工神经网络优势的混合型模型。它通过将小波函数引入神经网络的结构和训练过程中，提高了网络在处理非线性和复杂数据时的性能。以下是对小波神经网络的详细介绍：

1. 基本概念
小波分析：小波是一种具有良好时间和频率局部化特性的函数，常用于信号处理、图像分析等领域。小波分析能够有效地捕捉信号中的局部特征和突变点。
神经网络：模拟生物神经系统的一类机器学习模型，擅长处理非线性关系和复杂模式识别任务。
2. 小波神经网络的结构
小波神经网络通常在传统神经网络的基础上，引入小波基函数作为激活函数或用于输入数据的预处理。具体结构可以包括：

输入层：接收原始数据或经过小波变换处理后的数据。
隐藏层：采用小波函数作为激活函数，能够更好地捕捉数据中的局部特征。
输出层：根据具体任务（如分类、回归等）进行相应的输出。
3. 主要特点与优势
多尺度分析能力：小波函数能够在不同尺度下分析数据，适应数据的多尺度特性。
局部特征提取：小波的局部化特性使得网络能够有效提取数据中的局部特征，提高模型的表达能力。
抗噪能力强：小波分析具有良好的去噪性能，能够提高神经网络在噪声环境下的稳定性。
计算效率高：通过合理设计，小波神经网络在某些应用中可以实现更高的计算效率。
4. 应用领域
小波神经网络在多个领域中表现出色，包括但不限于：

信号处理：如语音识别、雷达信号分析等。
图像处理：如图像压缩、边缘检测、图像分类等。
时间序列预测：如金融市场预测、气象预报等。
生物医学工程：如生物信号分析、医学图像诊断等。
5. 模型训练
小波神经网络的训练过程与传统神经网络类似，通常采用反向传播算法优化网络参数。然而，由于引入了小波函数，训练过程中需要同时优化小波基的参数（如尺度、位置等），这增加了模型的灵活性但也提高了训练的复杂性。

6. 发展与挑战
小波神经网络融合了小波分析与神经网络的优势，但在实际应用中也面临一些挑战：

参数选择：选择合适的小波基和参数对于模型性能至关重要，但通常需要经验或复杂的优化方法。
模型复杂度：引入小波函数可能增加模型的复杂度，导致训练时间增加。
理论研究：关于小波神经网络的理论分析和性能保证仍在发展中，需进一步研究。
总结
小波神经网络通过结合小波分析与神经网络的优势，提升了模型在处理复杂、非线性和多尺度数据方面的能力。其在信号处理、图像分析和时间序列预测等领域表现出色，具有广阔的应用前景。然而，模型的参数选择和训练复杂度等问题仍需进一步研究和优化。

---

## File: _drafts/进行中/最大熵.md

知识准备
概率测度
条件概率
Lagrange法
信息熵


## 简介
Multinomial logistic regression is known by a variety of other names, including polytomous LR, multiclass LR, **softmax regression** , multinomial logit, **maximum entropy** (MaxEnt) classifier, conditional maximum entropy model.[^wikipedia]

## 模型

给定数据集$$\Gamma=\{ (x_1,y_1),(x_2,y_2),...(x_N,y_N)\}$$  
$x_i \in \mathcal{X}, y_i \in \mathcal{Y}$  
$(x_i,  y_i) \in \mathcal{X, Y}$  

目标：分类器  

按照最大熵原理，应当优先找到满足所有的已知约束。  
如何提取这些约束呢？  
思路是：从数据集$\Gamma$中提取特征。当然要求这些特征在$\Gamma$熵的关于经验分布$\tilde p (x,y)$的数学期望，等于模型中关于$p(x,y)$的数学期望。  

### feature function

$$f(x,y)=\left \{ \begin{array}{ccc}
1&x,y\space subject\space to \space some\space fact\\
0&other wise\end{array}\right.$$

### 约束

要求这些特征在$\Gamma$熵的关于经验分布$\tilde p (x,y)$的数学期望，等于模型中关于$p(x,y)$的数学期望。
也就是说$E_{\tilde p}(f)=E_p(f)$  

当然，可以有多个feature function，  
$E_{\tilde p}(f_i)=E_p(f_i),i=1,2,...n$  

这两个期望怎么计算呢？  
$E_{\tilde p}(f_i)=\sum\limits_{x,y}\tilde p(x,y)f_i(x,y)$  
$E_p(f_i)=\sum\limits_{x,y}p(x,y)f_i(x,y)$  

经验概率怎么计算呢？
就是我们通常的计算方法:  
$\tilde p(x,y)=\dfrac{count(x,y)}{N}$  
$\tilde p(x)=\dfrac{count(x)}{N}$  

所以：  
$\sum\limits_{x,y}\tilde p(x,y)f_i(x,y)=\sum\limits_{x,y}p(x,y)f_i(x,y)$  
$p(x,y)$是未知的，而建模的目标是生成$p(y\mid x)$  
因此，只好使用一个 **近似**  $p(x)\thickapprox \tilde p(x)$  

最后，约束变为：  
$\sum\limits_{x,y}\tilde p(x,y)f_i(x,y)=\sum\limits_{x,y}\tilde p(x)p(x \mid y)f_i(x,y)$  

### 最大熵

$H(p(y\mid x))=-\sum\limits_{x,y} p(x)p(y\mid x) \log p(y\mid x)$  
(用定义很容易证明，请自己推导一遍)[^myblog]  

这里仍然使用这个近似 $p(x)\thickapprox \tilde p(x)$  

最大熵模型就是求解:  
$\arg \max\limits_p H(p) =\sum\limits_{x,y}(\tilde p(x) p(y\mid x) \log p(y\mid x))$  
s.t.$\sum\limits_y p(y\mid x)=1$  

再加上上一部分的约束条件，求最优化就可以得到最终结果了。  





## 参考资料

[^wikipedia]: [wikipedia] (https://en.wikipedia.org/wiki/Multinomial_logistic_regression)

[peghoty]: [最大熵学习笔记](http://blog.csdn.net/itplus/article/details/26550597)
[^myblog]: 我的另一篇blog[信息熵](http://www.guofei.site/2017/05/23/entropy.html)

---

## File: _drafts/进行中/未完与拾遗.md

RANSAC算法
优点是模型无视异常点的影响

step1：从数据集中随机抽取样本作为内点集合  
step2：用内点集合来拟合模型  
step3：把剩余数据放入模型，其中一定误差内的样本加入到内点集合  
step4：如果迭代到达预定次数，或者其它结束条件，结束，否则转到step2  


```
from sklearn.linear_model import RANSACRegressor
```



## kmeans++
选取k个初始点的时候用这个算法：  
step1：选取一个初始点  
step2：依概率选取第二个初始点（概率与距离成正比）  
。。。  
step_n：做kmeans  

## plotly
1. 动画（一篇）
2. 鼠标事件（一篇）
https://plot.ly/python/click-events/

## 图社区检验

## TOC
blog：侧边目录默认开启
blog：侧边目录加序号 1,1.1, 1.2.1

---

## File: _drafts/进行中/算法的应用场景.md

- 人脸识别：安防、风控
人脸识别数据集LFM(Labeled Faces in the Wild)
- OCR：节省google地图的成本


## 语音识别
GMM

## NLP
language modeling  
机器翻译  
词性标注（part-of-speech tagging）
实体识别（named entity recognition，NER）
情感分析（sentiment analysis）  
广告推荐，搜索排序  
word embedding

## 距离
用汉明距离检测重复图片（例如，图片有打水印前、打水印后），实际上用MD5相减可以快速近似实现算法。

---

## File: _drafts/进行中/进化算法.md

不知道PSO, GA等这些东西属于哪一类

MATLAB书：智能算法  
优化算法  
Evolutionary algorithm https://en.wikipedia.org/wiki/Evolutionary_algorithm  
这个叫EA  
Particle swarm optimization https://en.wikipedia.org/wiki/Particle_swarm_optimization
Genetic algorithm https://en.wikipedia.org/wiki/Genetic_algorithm

---

## File: _drafts/进行中/学习中/matplotlib画graph.md

### 包
两个函数：  
V2E是给定顶点坐标，求欧氏距离  
plot_G是给定顶点坐标，画图  


下面这段代码保存为graph_plotter.py
```py
import matplotlib.pyplot as plt
import numpy as np


def V2E(V, E_noweight=None):
    # 输入顶点坐标，输出各边长度
    # V:dict,表示顶点最表
    # E:True&False构成的矩阵，表示这些点之间是否有线连接
    # E：权值矩阵，表示边的长度，inf表示不连接
    # 如果E_noweight=None，按照全连接图来处理
    n = len(V)
    if E_noweight is None:
        E_noweight = np.ones(shape=(n, n))
    E = np.empty(shape=(n, n))
    for i in V:
        for j in V:
            if E_noweight[i, j]:  # =True
                E[i, j] = np.linalg.norm(V[i] - V[j], ord=2)
            else:
                E[i, j] = np.inf  # =False
    return E


def plot_G(V, E_noweight):
    for i in V:
        plt.plot(V[i][0], V[i][1], 'o')
    for i in V:
        for j in V:
            if E_noweight[i, j] > 0:
                if not E_noweight[i, j] is np.inf:
                    temp = list(zip(V[i], V[j]))
                    plt.plot(temp[0], temp[1])
    plt.show()


if __name__ == '__main__':
    from scipy.stats import uniform

    V_name = range(5)
    rv = uniform(loc=0, scale=1)
    V = {i: rv.rvs(size=2) for i in V_name}
    n = len(V)
    E_noweight = rv.rvs(size=(n, n)) > 0.8 #对于无向图来说，这应该是个对称阵，这里省略了
    print(E_noweight)
    print(V2E(V, E_noweight))
    plot_G(V, E_noweight)

```


### 调用
```py
import graph_plotter

from scipy.stats import uniform

V_name = range(5)
rv = uniform(loc=0, scale=1)
V = {i: rv.rvs(size=2) for i in V_name}
n = len(V)
E_noweight = rv.rvs(size=(n, n)) > 0.8 #对于无向图来说，这应该是个对称阵，这里懒得改了，你按有向图来理解也没毛病
print(E_noweight)
print(graph_plotter.V2E(V, E_noweight))
graph_plotter.plot_G(V, E_noweight)

```

## dict表示法下，无权图转加权图

### 源数据
```py
a, b, c, d, e, f, g, h = range(8)
G = {
    a: {b, c, d, e, f},
    b: {c, e},
    c: {d},
    d: {e},
    e: {f},
    f: {c, g, h},
    g: {f, h},
    h: {f, g}
}
from scipy.stats import uniform

rv = uniform(loc=0, scale=1)
V = {i: rv.rvs(size=2) for i in range(8)}
```


### 做法
```py
import numpy as np
{u:{v:np.linalg.norm(V[u]-V[v],ord=2) for v in G[u]} for u in G}
```

---

## File: _drafts/进行中/学习中/matplotlib画树图.md

下面这段代码保存为treePlotter.py  

这段代码来自《机器学习实战》代码，github上的官方库：https://github.com/pbharrin/machinelearninginaction  

```py
import matplotlib.pyplot as plt

decisionNode = dict(boxstyle="sawtooth", fc="0.8")
leafNode = dict(boxstyle="round4", fc="0.8")
arrow_args = dict(arrowstyle="<-")


def getNumLeafs(myTree):
    numLeafs = 0
    myTree_keys_list = list(myTree.keys())
    firstStr = myTree_keys_list[0]  # 字典的第一个键，即树的一个结点
    secondDict = myTree[firstStr]  # 这个键的值，即该结点的所有子树
    for key in secondDict.keys():
        if type(secondDict[
                    key]).__name__ == 'dict':  # test to see if the nodes are dictonaires, if not they are leaf nodes
            numLeafs += getNumLeafs(secondDict[key])
        else:
            numLeafs += 1
    return numLeafs


def getTreeDepth(myTree):
    maxDepth = 0
    myTree_keys_list = list(myTree.keys())
    firstStr = myTree_keys_list[0]
    secondDict = myTree[firstStr]
    for key in secondDict.keys():
        if type(secondDict[key]).__name__ == 'dict':
            thisDepth = 1 + getTreeDepth(secondDict[key])
        else:
            thisDepth = 1
        if thisDepth > maxDepth: maxDepth = thisDepth
    return maxDepth


def plotNode(nodeTxt, centerPt, parentPt, nodeType):
    createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction',
                            xytext=centerPt, textcoords='axes fraction',
                            va="center", ha="center", bbox=nodeType, arrowprops=arrow_args)


def plotMidText(cntrPt, parentPt, txtString):
    xMid = (parentPt[0] - cntrPt[0]) / 2.0 + cntrPt[0]
    yMid = (parentPt[1] - cntrPt[1]) / 2.0 + cntrPt[1]
    createPlot.ax1.text(xMid, yMid, txtString, va="center", ha="center", rotation=30)


def plotTree(myTree, parentPt, nodeTxt):  # if the first key tells you what feat was split on
    numLeafs = getNumLeafs(myTree)  # this determines the x width of this tree
    depth = getTreeDepth(myTree)
    myTree_keys_list = list(myTree.keys())
    firstStr = myTree_keys_list[0]  # the text label for this node should be this
    cntrPt = (plotTree.xOff + (1.0 + float(numLeafs)) / 2.0 / plotTree.totalW, plotTree.yOff)
    plotMidText(cntrPt, parentPt, nodeTxt)
    plotNode(firstStr, cntrPt, parentPt, decisionNode)
    secondDict = myTree[firstStr]
    plotTree.yOff = plotTree.yOff - 1.0 / plotTree.totalD
    for key in secondDict.keys():
        if type(secondDict[
                    key]).__name__ == 'dict':  # test to see if the nodes are dictonaires, if not they are leaf nodes
            plotTree(secondDict[key], cntrPt, str(key))  # recursion
        else:  # it's a leaf node print the leaf node
            plotTree.xOff = plotTree.xOff + 1.0 / plotTree.totalW
            plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)
            plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))
    plotTree.yOff = plotTree.yOff + 1.0 / plotTree.totalD


# if you do get a dictonary you know it's a tree, and the first element will be another dict

def createPlot1(inTree):
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    axprops = dict(xticks=[], yticks=[])
    createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)  # no ticks
    # createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses
    plotTree.totalW = float(getNumLeafs(inTree))
    plotTree.totalD = float(getTreeDepth(inTree))
    plotTree.xOff = -0.5 / plotTree.totalW;
    plotTree.yOff = 1.0;
    plotTree(inTree, (0.5, 1.0), '')
    plt.show()


def createPlot():
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    createPlot.ax1 = plt.subplot(111, frameon=False)  # ticks for demo puropses
    plotNode('a decision node', (0.5, 0.1), (0.1, 0.5), decisionNode)
    plotNode('a leaf node', (0.8, 0.1), (0.3, 0.8), leafNode)
    plt.show()


def retrieveTree(i):
    listOfTrees = [{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}},
                   {'no surfacing': {0: 'no', 1: {'flippers': {0: {'head': {0: 'no', 1: 'yes'}}, 1: 'no'}}}}
                   ]
    return listOfTrees[i]

```


使用：
```py
import treePlotter

treePlotter.createPlot()
mytree = treePlotter.retrieveTree(1)
print(mytree)
print(treePlotter.getNumLeafs(mytree))
print(treePlotter.getTreeDepth(mytree))
treePlotter.createPlot1(mytree)
```

---

## File: _drafts/进行中/学习中/python基础工具箱.md

# 开源库


- MinHash 的，已经很完善了：   https://github.com/ekzhu/datasketch



# 基础库

## 1. 数据处理
Chardet 字符编码探测器，可以自动检测文本、网页、xml的编码。
colorama 主要用来给文本添加各种颜色，并且非常简单易用。
Prettytable主要用于在终端或浏览器端构建格式化的输出。
difflib，[Python]标准库，计算文本差异
Levenshtein，快速计算字符串相似度。
fuzzywuzzy,字符串模糊匹配。
esmre,正则表达式的加速器。
shortuuid,一组简洁URL/UUID函数库。
ftfy，Unicode文本工具7
unidecode，ascii和Unicode文本转换函数。
xpinyin ，将汉字转换为拼音的函数库
pangu.py，调整对中日韩文字当中的字母、数字间距。
pyfiglet，Python写的figlet程序，使用字符组成ASCII艺术图片
uniout，提取字符串中可读写的字符
awesome slugify，一个Python slugify库，用于处理Unicode。
python-slugify，转换Unicode为ASCII内码的slugify函数库。
unicode-slugify，生成unicode内码，Django的依赖包。
ply，Python版的lex和yacc的解析工具
phonenumbers，解析电话号码，格式，存储和验证的国际电话号码。
python-user-agents，浏览器的用户代理（user-agents）的解析器。
sqlparse，SQL解析器。
pygments，一个通用的语法高亮工具。
python-nameparser，解析人名，分解为单独的成分。
pyparsing，通用解析器生成框架。
tablib，表格数据格式，包括，XLS、CSV，JSON，YAML。
python-docx，docx文档读取，查询和修改，微软Word 2007 / 2008的docx文件。
xlwt/xlrd，读写Excel格式的数据文件。
xlsxwriter，创建Excel格式的xlsx文件。
xlwings，利用Python调用Excel
csvkit，CSV文件工具包。
marmir，把Python[数据结构]，转化为电子表格。
pdfminer，从PDF文件中提取信息。
pypdf2， 合并和转换PDF页面的函数库。
Python-Markdown，轻量级标记语言Markdown的Python实现。
Mistune，,快速、全功能的纯Python编写的Markdown解释器。
dateutil，标准的Python官方datetime模块的扩展包，字符串日期工具，其中parser是根据字符串解析成datetime，而rrule是则是根据定义的规则来生成datetime。
arrow,更好的日期和时间处理Python库
chronyk，一个Python 3版函数库，用于解析人写的时间和日期。
delorean，清理期时间的函数库。
when.py，为见的日期和时间，提供人性化的功能。
moment，类似Moment.js的日期/时间Python库
pytz，世界时区，使用tz database时区信息[数据库]
BeautifulSoup，基于Python的HTML/XML解析器，简单易用, 功能很强大,即使是有bug，有问题的html代码，也可以解析
lxml，快速，易用、灵活的HTML和XML处理库，功能超强，在遇到有缺陷、不规范的xml时，Python自带的xml处理器可能无法解析。报错时，程序会尝试再用lxml的修复模式解析
。 htmlparser，官方版解析HTML DOM树，偶尔搞搞命令行自动表单提交用得上。
pyyaml，Python版本的YAML解释器。
html5lib，-标准库，解析和序列化HTML文档和片段。
pyquery，类似[jQuery]的的HTML解释器函数库。
cssutils，Python CSS库。
MarkupSafe，XML或HTML / XHTML安全字符串标记工具。
cssutils - ACSS library for Python., MarkupSafe - Implements a XML/HTML/XHTML bleach，漂白，基于HTML的白名单函数库。
xmltodict，类似JSON的XML工具包。
xhtml2pdf，HTML / CSS格式转换器，看生成pdf文档。
untangle，把XML文档，转换为Python对象，方便访问。


## 2. 文件处理
库名称简介Mimetypes，Python标准库，映射文件名到MIME类型。
imghdr，Python标准库，确定图像类型。python-magic，libmagic文件类型识别库，Python接口格式。path.py，os.path模块的二次封装。
watchdog，一组API和shell实用程序，用于监视文件系统事件。
Unipath，面向对象的文件/目录的操作工具包。pathlib，-（Python 3.4版已经作为Python标准库），一个跨平台，面向path的函数库。
pickle/cPickle,python的pickle模块实现了基本的数据序列和反序列化。通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去，永久存储；通过pickle模块的反序列化操作，我们能够从文件中创建上一次程序保存的对象。
cPickle是[C语言]实现的版本，速度更快。
ConfigParser，Python标准库，INI文件解析器。
configobj，INI文件解析器。config，分层次配置，logging作者编写。
profig，多格式配置转换工具。
logging，Python标准库，日志文件生成管理函数库。
logbook，logging的替换品。
Sentry，实时log服务器。Raven，哨兵Sentry的Python客户端。
Sphinx，斯芬克斯（狮身人面像），Python文档生成器。
reStructuredText，标记语法和解析工具，Docutils组件。mkdocs，Markdown格式文档生成器。
pycco，简单快速、编程风格的文档生成器。
pdoc，自动生成的Python库API文档epydoc，从源码注释中生成各种格式文档的工具

### 3. 图像处理
PIL（Python Image Library），基于Python的图像处理库，功能强大，对图形文件的格式支持广泛，内置许多图像处理函数，如图像增强、滤波[算法]等Pillow，图像处理库，PIL图像库的分支和升级替代产品。

Matplotlib，著名的绘图库，提供了整套和matlab相似的命令API，用以绘制一些高质量的数学二维图形，十分适合交互式地进行制图。brewer2mpl，有一个专业的python配色工具包，提供了从美术角度来讲的精美配色。

PyGame基于Python的多媒体开发和游戏软件开发模块，包含大量游戏和图像处理功能Box2d，开源的2d物理引擎，愤怒的小鸟就是使用了这款物理引擎进行开发的，Box2d物理引擎内部模拟了一个世界，你可以设置这个世界里的重力，然后往这个世界里添加各种物体，以及他们的一些物理特性，比如质量，摩擦，阻尼等等。

Pymunk，类似box2d的开源物理图形模拟库OpenCV, 目前最好的开源图像/视觉库，包括图像处理和计算机视觉方面、[机器学习]的很多通用算法。SimpleCV，计算机视觉开源框架，类似opencv。VTK，视觉化工具函式库（VTK， Visualization Toolkit）是一个开放源码，跨平台、支援平行处理（VTK曾用于处理大小近乎1个Petabyte的资料，其平台为美国Los Alamos国家实验室所有的具1024个处理器之大型系统）的图形应用函式库。

2005年时曾被美国陆军研究实验室用于即时模拟俄罗斯制反导弹战车ZSU23-4受到平面波攻击的情形，其计算节点高达2.5兆个之多。cgkit,Python Computer Graphics Kit,其module 主要分两个部分，



与3d相关的一些python module 例如the vector, matrix and quaternion types, the RenderMan bindings, noise functions 这些模块可以在maya houdini nuke blender 等有Python扩展的程序中直接用;
提供完整的场景操作的module， 他类似其他三维软件，在内存中保留完整的描述场景的信息。
不能直接用于maya 等CGAL， Computational Geometry Algorithms Library，计算几何算法库，提供计算几何相关的数据结构和算法，诸如三角剖分（2D约束三角剖分及二维和三维Delaunay三角剖分）， Voronoi图（二维和三维的点，2D加权Voronoi图，分割Voronoi图等）， 多边形（布尔操作，偏置），多面体（布尔运算），曲线整理及其应用， 网格生成（二维Delaunay网格生成和三维表面和体积网格生成等），几何处理（表面网格简化，细分和参数化等）， 凸壳算法（2D，3D和dD），搜索结构（近邻搜索，kd树等），插值，形状分析，拟合，距离等。
Aggdraw，开源图像库，几乎涵盖了2d image操作的所有功能，使用起来非常灵活Pycairo,开源矢量绘图库Cairo开罗的python接口，cairo提供在多个背景下做2-D的绘图，高级的更可以使用硬件加速功能。wand，Python绑定魔杖工具（MagickWand），C语言API接口。
thumbor， -智能成像工具，可调整大小和翻转图像。
imgSeek，查询相似的图像。
python-qrcode，纯Python的二维码（QR码）生成器。
pyBarcode，创建条码，无需PIL模块。
pygram，Instagram像图像过滤器。
Quads，基于四叉树的计算机艺术。
nude.py，裸体检测函数。
scikit-image，scikit工具箱的图像处理库。
hmap，图像直方图工具。
bokeh，交互的Web绘图。
plotly，Web协同的Python和Matplotlib绘制。
vincent，文森特，Python Vega的函数库。
d3py，Python绘图库，基于D3.JS, ggplot -API兼容R语言的ggplot2.Kartograph.py，在Python绘制漂亮的SVG地图。pygal， SVG图表的创造者。
pygraphviz，Graphviz的Python接口。
Fonttlools，ttf字体工具函数包，用于fontforge、ttx等字体软件。

## 4. 游戏和多媒体
库名称简介audiolazy，数字信号处理（DSP）的Python工具包。
audioread，跨平台（GStreamer + Core Audio + MAD + FFmpeg）音频解码库。 beets，音乐库管理。
dejavu，音频指纹识别算法。
Dejavu 听一次音频后就会记录该音频的指纹信息，然后可通过麦克风对输入的音频进行识别是否同一首歌。django-elastic-transcoder,Django +亚马逊elastic转码。eyeD3,音频文件工具，特别是MP3文件包含的ID3元数据。
id3reader，用于读取MP3的元数据。
mutagen，处理音频元数据。
pydub，-操纵音频和简单的高层次的接口。
pyechonest，Echo Nest API客户端。talkbox，语音和信号处理的Python库。
TimeSide，开放的网络音频处理框架。
tinytag，读取音乐文件元数据，包括的MP3，OGG，FLAC和wave文件。
m3u8，用于解析m3u8文件。
moviepy，多格式视频编辑脚本模块，包括GIF动画。
http://shorten.tv，视频摘要。
scikit视频，SciPy视频处理例程。
GeoDjango,一个世界级的地理Web框架。
geopy,Geo地理编码的工具箱。
pygeoip，纯Python写的GeoIP API。
GeoIP，Python API接口，使用高精度GeoIP Legacy Database数据库。
geojson，GeoJSON函数库django-countries，一个Django程序，提供国家选择，国旗图标的静态文件，和一个国家的地域模型。
Pygame，Python游戏设计模块。
Cocos2d，2D游戏框架，演示，和其他的图形/交互应用，基于pyglet。Cocos2d- cocos2d is a framework for building 2D games, demos, and other graphical/interactive applications. It is based on pyglet.,PySDL2，SDL2的封装库。
Panda3D- 3D游戏引擎，迪士尼开发。
用C++写的，完全兼容Python。PyOgre，OGRE 3D渲染引擎，可用于游戏，模拟，任何3D。 PyOpenGL，绑定OpenGL和它相关的API。
PySFML，Python绑定SFMLRenPy，视觉小说引擎。

## 5. 大数据与科学计算
库名称简介pycuda/opencl，GPU高性能并发计算Pandas，python实现的类似R语言的数据统计、分析平台。基于NumPy和Matplotlib开发的，主要用于数据分析和数据可视化，它的数据结构DataFrame和R语言里的data.frame很像，特别是对于时间序列数据有自己的一套分析机制，非常不错。
Open Mining，商业智能（BI），Pandas的Web界面。blaze，NumPy和Pandas大数据界面。 SciPy，开源的Python算法库和数学工具包，SciPy包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。
其功能与软件MATLAB、Scilab和GNU Octave类似。
Numpy和Scipy常常结合着使用，Python大多数机器学习库都依赖于这两个模块。
ScientificPython，一组经过挑选的Python程序模块，用于科学计算，包括几何学（矢量、张量、变换、矢量和张量场），四元数，自动求导数，（线性）插值，多项式，基础统计学，非线性最小二乘拟合，单位计算，Fortran兼容的文本格式，通过VRML的3D显示，以及两个Tk小工具，分别用于绘制线图和3D网格模型。 此外还具有到netCDF，MPI和BSPlib库的接口。
NumPy科学计算库，提供了矩阵，线性代数，傅立叶变换等等的解决方案, 最常用的是它的N维数组对象. NumPy提供了两种基本的对象： ndarray（N-dimensional array object）和 ufunc（universal function object）。
ndarray是存储单一数据类型的多维数组，而ufunc则是能够对数组进行处理的函数。 Cvxopt，最优化计算包，可进行线性规划、二次规划、半正定规划等的计算。 Numba，科学计算速度优化编译器。pymvpa2，是为大数据集提供统计学习分析的Python工具包，它提供了一个灵活可扩展的框架。
它提供的功能有分类、回归、特征选择、数据导入导出、可视化等NetworkX，复杂网络的优化软件包。zipline，交易算法的函数库。
PyDy， Python动态建模函数库。
SymPy,符号数学的Python库。statsmodels,Python的统计建模和计量经济学。
astropy,天文学界的Python库。
orange，橙色，数据挖掘，数据可视化，通过可视化编程或Python脚本学习机分析。 RDKit,化学信息学和机器学习的软件。
Open Babel，巴贝尔，开放的化学工具箱。
cclib，化学软件包的计算函数库。
Biopython，免费的生物计算工具包。
bccb，生物分析相关的代码集。bcbio-nextgen，提供完全自动化、高通量、测序分析的工具包。
visvis, 可视化计算模块库，可进行一维到四维数据的可视化。
MapReduce是Google提出的一个软件[架构]，用于大规模数据集（大于1TB）的并行运算。 概念“Map（映射）”和“Reduce（归纳）”，及他们的主要思想，都是从函数式编程语言借来的MapReduce函数库。Framworks and libraries for MapReduce.,PySpark，[Spark]的Python API。dpark，Spark的Python克隆，Python中的MapReduce框架。luigi，为批量工作，建立复杂的管道。mrjob，运行在[Hadoop]，或亚马逊网络服务的，MapReduce工作。

## 6. 人工智能与机器学习
库名称简介NLTK（natural language toolkit)，是python的自然语言处理工具包。2001年推出，包括了大量的词料库，以及自然语言处理方面的算法实现： 分词， 词根计算， 分类， 语义分析等。
Pattern，数据挖掘模块，包括自然语言处理，机器学习工具，等等。
textblob，提供API为自然语言处理、分解NLP任务。基于NLTK和Pattern模块。
jieba，结巴，中文分词工具。snownlp，用于处理中文文本库。
loso，中文分词函数库。
genius，中文CRF基础库，条件随机场(conditional random field,简称 CRF),是一种鉴别式机率模型,是随机场的一种,常用于标注或分析序列资料,如自然语言文字或是生物序列Gensim，一个相当专业的主题模型Python工具包，无论是代码还是文档，可用于如何计算两个文档的相似度LIBSVM,是台湾大学林智仁(Lin Chih-Jen)教授等开发设计的一个简单、易于使用和快速有效的SVM模式识别与回归的软件包，他不但提供了编译好的可在Windows系列系统的执行文件，还提供了源代码，方便改进、修改以及在其它[操作系统]上应用；
该软件对SVM所涉及的参数调节相对比较少，提供了很多的默认参数，利用这些默认参数可以解决很多问题；并提供了交互检验(Cross Validation)的功能。
该软件可以解决C-SVM、ν-SVM、ε-SVR和ν-SVR等问题，包括基于一对一算法的多类模式识别问题。
scikits.learn，构建在SciPy之上用于机器学习的 Python 模块。它包括简单而高效的工具，可用于数据挖掘和数据分析。
涵盖分类，回归和聚类算法，例如SVM， 逻辑回归，朴素贝叶斯，随机森林，k-means等算法，代码和文档都非常不错，在许多Python项目中都有应用。
例如在我们熟悉的NLTK中，分类器方面就有专门针对scikit-learn的接口，可以调用scikit-learn的分类算法以及训练数据来训练分类器模型。PyMC，机器学习采样工具包，scikit-learn似乎是所有人的宠儿，有人认为，PyMC更有魅力。
PyMC主要用来做Bayesian分析。Orange，基于组件的数据挖掘和机器学习软件套装，它的功能即友好，又很强大，快速而又多功能的可视化编程前端，以便浏览数据分析和可视化，包含了完整的一系列的组件以进行数据预处理，并提供了数据帐目，过渡，建模，模式评估和勘探的功能。
侧重数据挖掘，可以用可视化语言或Python进行操作，拥有机器学习组件，还具有生物信息学以及文本挖掘的插件。
Milk，机器学习工具箱，其重点是提供监督分类法与几种有效的分类分析：SVMs(基于libsvm)，K-NN，随机森林经济和决策树。
它还可以进行特征选择。这些分类可以在许多方面相结合，形成不同的分类系统。对于无监督学习，它提供K-means和affinity propagation聚类算法。
PyMVPA(Multivariate Pattern Analysis in Python),是为大数据集提供统计学习分析的Python工具包，它提供了一个灵活可扩展的框架。它提供的功能有分类、回归、特征选择、数据导入导出、可视化等NuPIC，开源人工智能平台。
该项目由Grok（原名 Numenta）公司开发，其中包括了公司的算法和软件架构。
NuPIC 的运作接近于人脑，“当模式变化的时候，它会忘掉旧模式，记忆新模式”。如人脑一样，CLA 算法能够适应新的变化。Pylearn2，-基于Theano的机器学习库。
hebel，GPU加速，[深度学习]Python库。
gensim，机器学习库。pybrain，机器学习模块，它的目标是为机器学习任务提供灵活、易应、强大的机器学习算法。
pybrain包括神经网络、强化学习(及二者结合)、无监督学习、进化算法。以神经网络为核心，所有的训练方法都以神经网络为一个实例Mahout,是 Apache Software Foundation（ASF） 旗下的一个开源项目，提供一些可扩展的机器学习领域经典算法的实现，旨在帮助开发人员更加方便快捷地创建智能应用程序。
Mahout包含许多实现，包括聚类、分类、推荐过滤、频繁子项挖掘。此外，通过使用 Apache Hadoop 库，Mahout 可以有效地扩展到云中。
Crab，灵活的，快速的推荐引擎。python-recsys，娱乐系统分析，推荐系统。vowpal_porpoise，Vowpal Wabbit轻量级Python封装。
Theano,用来定义、优化和模拟数学表达式计算，用于高效的解决多维数组的计算问题的python软件包。它使得写深度学习模型更加容易，同时也给出了一些关于在GPU上训练它们的选项。

## 7. 系统与命令行
库名称简介threading，Python标准线程库，更高级别的线程接口。
envoy，特使，Python子线程的函数库。
sh，成熟的子线程替换函数库。sarge，封装线程。subprocess,调用shell命令的神器argparse，写命令行脚本必备，强大的命令行差数解析工具timeit，计算代码运行的时间等等unp，命令行工具，解压文件。
eventlet开销很少的多线程模块，使用的是 green threads 概念，例如，pool = eventlet.GreenPool(10000) 这样一条语句便创建了一个可以处理 10000 个客户端连接的线程池。 类似Gevent线程库Gevent，多线程模块pytools,著名的python通用函数、工具包SendKeys, 键盘鼠标操作模块, 模拟键盘鼠标模拟操作。
pyHook,基于Python的“钩子”库，主要用于监听当前电脑上鼠标和键盘的事件。 这个库依赖于另一个Python库PyWin32，如同名字所显示的，PyWin32只能运行在Windows平台，所以PyHook也只能运行在Windows平台。
pstuil,跨平台地很方便获取和控制系统的进程，以及读取系统的CPU占用内存占用等信息.cement，一个轻量级的、功能齐全的命令行工具click，简单优雅的的命令行接口。
clint，Python命令行工具。cliff，创造多层次指令的命令行程序框架。
Clime， 可以转换任何模块为多的CLI命令程序，无任何配置。
docopt，Python命令行参数分析器。 pycli，命令行应用程序，支持的标准命令行解析，测井，单元[测试]和功能测试。
Gooey，打开命令行程序，作为为一个完整的GUI应用程序,cookiecutter，命令行工具，从cookiecutters（项目模板）创建项目。
例如，Python包项目，jQuery插件项目。
percol，为UNIX传统管道pipe命令，添加交互式选择风格。
rainbowstream，聪明和漂亮的推特客户终端。Django Models，Django的一部分SQLAlchemy，Python SQL工具包和对象关系映射。
peewee，小型的ORM解析器。
PonyORM，为ORM提供了一种面向SQL的接口。MongoEngine，Python对象文件映射，使用[MongoDB]。
, Django MongoDB引擎MongoDB , Django后台。
django-mongodb-engine，Django后台.redisco,一个简单的模型和容器库，使用[Redis]flywheel，Amazon DynamoDB对象映射。
butterdb，谷歌电子表格的ORM，Python版。celery，芹菜，异步任务队列/工作，基于分布式消息队列。
huey，休伊，轻量级，多线程任务队列。
mrq，队列先生，分布式任务队列，使用redis & Gevent。rq，简单的工作队列。 Queue,Queue模块可以用来实现多线程间通讯，让各个线程共享数据，生产者把货物放到Queue中，供消费者（线程）去使用。
simpleq，简单的，可扩展的队列，Amazon SQS基础队列。
Psyco，超强的python性能优化工具，psyco 的神奇在于它只需要在代码的入口处调用短短两行代码，性能就能提升 40% 或更多，真可谓是立竿见影！如果你的客户觉得你的程序有点慢，敬请不要急着去优化代码，psyco 或许能让他立即改变看法。
psyco 堪称 Python 的 jit。fn.py，Python函数编程：缺失的功能享受FP的实现。funcy，函数编程工具。 Toolz，函数编程工具：迭代器、函数，字典。CyToolz，Toolz的Cython实现，高性能的函数编程工具。Ansible，安塞波，极为简单的自动化平台。
SaltStack，基础设施的自动化管理系统。
Fabric，织物，一个简单，远程执行和部署的语言工具。
Fabtools，Fabric的工具函数。
cuisine，热门的Fabric的工具函数。
psutil，跨平台的过程和系统工具模块。
pexpect，控制互动节目。
provy，易于使用的配置系统的Python。honcho，Foreman的Python接口，用于管理procfile应用工具。
gunnery，多任务执行工具，与网络接口的分布式系统。
fig，快速。独立的开发环境中使用泊坞窗。
APScheduler，轻量级、但功能强大的在线任务调度程序。
django-schedule,Django日程应用程序。doit,任务流道/生成工具。
Joblib,Python提供的轻量级的流水线工具函数。
Plan，简易生成crontab文件。
Spiff，纯Python实现的，功能强大的工作流引擎。
schedule，Python作业调度。TaskFlow，有助于使任务执行简单。
ctypes，Python标准库，速度更快，Python调用C代码的外部函数接口。cffi，Python调用C代码外部函数接口，类似于ctypes直接在python程序中调用c程序,但是比ctypes更方便不要求编译成so再调用。
Cytoolz，python 加速库SWIG，简化封装和接口生成器。
,Cython，Python优化静态编译器。
PyPy，Python解释器的 Python实现。
Stackless Python，一个增强版本的Python。它使程序员从基于线程的编程方式中获得好处，并避免传统线程所带来的性能与复杂度问题。
Stackless为 Python带来的微线程扩展，是一种低开销、轻量级的便利工具Pyston,使用LLVM和现代JIT技术,对python进行性能优化。
pythonlibs，非官方的Windows（32 / 64位）的Python扩展包scapy，优秀的数据包处理库。 ino，Arduino命令行工具。Pyro，Python的机器人工具包。
pluginbase，一个简单而灵活的Python的插件系统。
itsdangerous，数据安全传输工具。blinker，快速Python中的信号/事件调度系统。
pychievements，用于创建和跟踪成果框架。
python-patterns，Python中的设计模式。
pefileWindows PE文件解析器SIP，自动为C和C++库生成Python扩展模块的工具

## 8. 数据库
库名称简介MySQLdb，成熟的[MySQL]数据库模块,Baresql,SQL数据库包ZODB，Python本地对象数据库。一个K-V对象图数据库。
pickledb,简单和轻量级的K-V键值存储。
TinyDB, 轻量级，面向文档的数据库。
mysql-python，MySQL的Python工具库。
mysqlclient，mysql-python分支，支持Python 3.,PyMySQL,纯Python写的 MySQL驱动程序，兼容mysql-python。mysql-connector-python,MySQL连接器,来自[Oracle]，纯Python编写。 oursql，MySQL连接器，提供本地话指令语句和BLOBs支持。
psycopg2，最流行的Python PostgreSQL适配器。txpostgres，于Twisted的异步驱动，用于PostgreSQL。
queries,psycopg2函数库，用于PostgreSQL。
dataset,存储Python字典数据,用于SQLite，MySQL和PostgreSQL。
cassandra-python-driver，开源分布式NoSQL数据库系统Apache Cassandra系统的Python驱动.pycassa,简化的cassandra数据库Python驱动。
HappyBase，友好的Apache [Hbase]的函数库。
PyMongo，MongoDB官方客户端。
plyvel，LevelDB快速和功能丰富的Python接口。redis-py,redis客户端。
py2neo,Python客户端(基于Neo4j的RESTful接口).telephus,基于Twisted的cassandra客户端。 txRedis，基于Twisted的Redis客户端。

## 9. 网络
Curl，Pycurl包是一个libcurl的Python接口，它是由C语言编写的。
与urllib相比，它的速度要快很多。
Libcurl是一个支持FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE 和 LDAP的客户端URL传输库.libcurl也支持HTTPS认证,HTTP POST,HTTP PUT,FTP上传,代理,Cookies,基本身份验证,FTP文件断点继传,HTTP代理通道等等。
Requests，用Python语言编写，基于 urllib的开源 HTTP 库。
它比 urllib 更加方便，更加 Pythoner。
支持 Python3。httpie，命令行HTTP客户端，用户友好的cURL的替换工具。
s3cmd，命令行工具，用于管理Amazon S3和CloudFront。
youtube-dl，命令行程序，从YouTube下载视频。
you-get，Python3写的视频下载工具，可用于YouTube/Youku优酷/Niconico视频下载
Coursera，从http://coursera.org下载视频，可重新命名文件wikiteam，wiki下载工具。
subliminal，命令行工具，搜索和下载字幕的函数库requests，HTTP函数库，更加人性化。grequests，异步HTTP请求+ Gevent（高性能高并发函数库）。
urllib3，一个线程安全的HTTP连接池，支持文件post。
httplib2，综合HTTP的客户端函数库。treq， Python API接口，Twisted的HTTP客户。 Mininet，流行的网络仿真器,API采用python编写。
POX，基于Python的开源软件定义网络（SDN）控制开发平台的应用，如OpenFlow的SDN控制器。
Pyretic，SDN的编程语言，提供了强大的抽象在网络交换机或仿真器。SDX Platform，基于SDN的IXP实现，利用最小网络，痘和热。inbox.py，Python的SMTP服务器。imbox， Python版本IMAP库。inbox，收件箱，开源邮件工具包。
lamson,SMTP服务器。flanker,侧卫,电子邮件地址和MIME解析库。
marrow.mailer,高性能可扩展邮件交付框架。
django-celery-ses， Django电子邮件后台，使用AWS SES和Celery。
modoboa，邮件托管和管理平台，包括现代和简化Web UI。
envelopes，邮件工具。
mailjet，批量邮寄mailjet API接口，带统计。Talon，利爪，Mailgun库，提取消息和签名。 mailjet- Mailjet API implementation for batch mailing, statistics and more., Talon - Mailgun library to extract message quotations and signatures.,pyzmail，编写，发送和解析电子邮件。 furl，燃料，小型的的URL解析库库。purl，简单的，干净的API，操纵URL。
pyshorteners，纯Python库，URL短网址编辑。
short_url，短网址生成。
Scrapy，快速屏幕截取和网页抓取的框架。
portia，波西亚，Scrapy的可视化扩展。
feedparser，信息源解释器RoboBrowser，简单的网页浏览Python函数库，没有使用Web浏览器。
MechanicalSoup，网站自动化互动测试工具包。
mechanize，网页浏览编程工具。
Demiurge，造物主，-PyQuery的轻量级工具。
newspaper,提取报纸新闻。html2text,转换HTML为 Markdown格式的文本。 python-goose,HTML内容提取器。
lassie,莱西,人性化的网站内容检索。
micawber,通过UR抓提网页的函数库。
sumy，概要，文本和HTML网页的自动文摘模块。
Haul，距离，可扩展的图像爬虫。
python-readability,可读性工具Arc90,快速的Python接口。
opengraph,OpenGraphProtocol协议解析模块,textract，从任何文件，Word，PowerPoint，PDF文件中提取文本，等。
sanitize，消毒，使混乱的数据变的理智。
AutobahnPython， WebSocket和WAMP的函数库，使用 Twisted和PythonWebSocket-for-Python，websocket客户端和服务器端函数库。SimpleXMLRPCServer，python标准库，简单的XML-RPC服务器，单线程。
SimpleJSONRPCServer，JSON-RPC规范实施函数库。
zeroRPC，基于ZeroMQ和MessagePack的RPC实现。
apache-libcloud，所有云服务的Python接口库。
wifi，WiFi -一套个Python库和命令行工具与WiFi，用于[Linux]。
streamparse，运行Python代码和数据的实时流。集成了Apache Storm。
boto，亚马逊网络服务接口。
twython，Twitter推特API。google-api-python-client，谷歌客户端API。
gspread，谷歌电子表格的Python API。
facebook-sdk，facebook平台Python SDK。
facepy，简易的facebook图形APIgmail，Gmail的Python接口。
django-wordpress，Django的WordPress的模型和视图。

## 10. Web框架
Django，最流行的Python-Web框架，鼓励快速开发,并遵循MVC设计，开发周期短
ActiveGrid 企业级的Web2.0解决方案
Karrigell 简单的Web框架，自身包含了Web服务，py脚本引擎和纯python的数据库PyDBLitewebpy 一个小巧灵活的Web框架，虽然简单但是功能强大
CherryPy 基于Python的Web应用程序开发框架Pylons基于Python的一个极其高效和可靠的Web开发框架Zope开源的Web应用服务器
TurboGears 基于Python的MVC风格的Web应用程序框架
Twisted 流行的网络编程库，大型Web框架
QuixoteWeb 开发框架
Flask 轻量级web框架
Bottle，快速，简单和轻量级的WSGI模式Web框架。
Pyramid，轻量级，快速，稳定的开源Web框架。
web2py，简单易用的全堆栈Web框架和平台。
web.py，强大、简单的Web框架。TurboGears，便于扩展的Web框架。
CherryPy，极简Python Web框架，支持，HTTP 1.1和WSGI线程池。
Grok，基于Zope3的Web框架。
Bluebream，开源的Web应用服务器，原名Zope 3。
guava，轻量级，高性能的Python-Web框架，采用c语言编写。
django-cms，基于Django企业级开源CMS。
djedi-cms轻量级但功能强大的Django CMS的插件，内联编辑和性能优化。
FeinCMS，基于Django的先进内容管理系统。
Kotte，高层次的Python的Web应用框架，基于Pyramid。Mezzanine，强大，一致，灵活的内容管理平台。
Opps，基于Django的CMS，用于高流量的报纸、杂志和门户网站。
Plone，基于Zope的开源应用服务器Zope。
Quokka，灵活，可扩展的，轻量级的CMS系统，使用Flask和MongoDB。
Wagtail，Django内容管理系统。
Widgy，CMS框架，基于Django。
django-oscar，Django奥斯卡，开源的电子商务框架。
django-shop，基于Django的网店系统。
merchant，支持多种付款处理工具。
money，可扩展的货币兑换解决方案。
python-currencies，货币显示格式。
cornice，Pyramid的REST框架。
django-rest-framework，Django框架，强大灵活的工具，可以很容易地构建Web API。
django-tastypie，创造精美的Django应用程序API接口。
django-formapi，创建JSON API、HMAC认证和Django表单验证。flask-api，提供统一的浏览器体验，基于Django框架。
flask-restful，快速构建REST API支持扩展。
flask-api-utils，flask的扩展。falcon，猎鹰，高性能的Python框架，构建云API和Web应用程序后端。
eve，夏娃，REST API框架，使用Flask，MongoDB和良好意愿。
sandman，睡魔，为现有的数据库驱动的系统，自动生成REST API。restless，类似TastyPie的框架。
savory-pie，REST API构建函数库（Django，及其他）Jinja2，现代设计师友好的语言模板。 Genshi，网络感知输出模板工具包。
Mako，马可，Python平台的超高速、轻型模板。
Chameleon，变色龙，一个HTML / XML模板引擎。
仿照ZPT，优化速度。
Spitfire，快速的Python编译模板。
django-haystack,大海捞针,Django模块搜索。
elasticsearch-py,Elasticsearch官方低级的Python客户端。
solrpy,solr客户端。
Whoosh,呼,快速，纯Python搜索引擎库。
Feedly，建立新闻和通知系统的函数库，使用Cassandra和Redis。
django-activity-stream,Django活动流,从你网站上的行动,产生通用的活动流。
Beaker，烧杯，一个缓存和会话使用的Web应用程序，独立的Python脚本和应用程序库。
dogpile.cache，是Beaker作者的下一代替代作品。HermesCache，Python的缓存库，基于标签的失效及预防Dogpile效果。
django-cache-machine，Django缓存机，自动缓存失效，使用ORM。django-cacheops，自动颗粒事件驱动，ORM缓存失效。johnny-cache,约翰尼高速缓存框架,Django应用程序。
django-viewlet,渲染模板部件扩展缓存控制。pylibmc,在libmemcached接口。
WTForms-JSON,JSON表单数据处理扩展。Deform， HTML表单生成的函数库。
django-bootstrap3，bootstrap3，集成了Django。django-crispy-forms，Django程序，可以创建优雅的表单。django-remote-forms，Django的远程表单，Django表格的序列化程序。
django-simple-spam-blocker，Django简单的垃圾邮件拦截器。
django-simple-captcha，Django简单验证码，简单的和高度可定制的Django应用程序，用于添加验证码图像Ajenti，服务器管理面板。
Grappelli，界面花哨的django皮肤。django-suit，Django替代o界面（仅用于非商业用途）。 django-xadmin，Django管理面板替代工具。
flask-admin，简单的flask管理界面框架flower，实时监控和Web管理面板。
Pelican，鹈鹕，Markdown或ReST，字王内容主题。支持 DVCS, Disqus. AGPL。 Cactus,仙人掌,设计师的网站静态生成器。
Hyde，海德， 基于Jinja2的静态网站生成器。
Nikola，尼古拉-一个静态网站和博客生成器。
Tags，标签，最简单的静态网站生成器。
Tinkerer，工匠，基于Sphinx的静态网站生成器。
asyncio，（在Python 3.4 +是Python标准库），异步I/O，事件循环，协同任务。 gevent，基于Python的网络库。
Twisted，扭曲，事件驱动的网络引擎。
Tornado，龙卷风，Web框架和异步网络的函数库。
pulsar，脉冲星，事件驱动的并行框架的Python。
diesel，柴油，绿色的，基于事件的I/O框架。
eventlet，WSGI支持异步框架。
pyzmq， 0MQ消息库的Python封装。
txZMQ,基于Twisted的0MQ消息库封Crossbar,开源统一应用路由器（WebSocket和WAMP）。 wsgiref，Python标准库，WSGI封装实现，单线程。
Werkzeug，机床，WSGI工具函数库，很容易地嵌入到你自己的项目框架。
paste，粘贴，多线程，稳定的，久经考验的WSGI工具。
rocket，火箭，多线程服务，基于Pyramid。
netius，快速的、异步WSGI服务器，gunicorn，forked前身，部分用C写的。
fapws3，异步网络，用C写的。meinheld，异步WSGI服务器，是用C写的。
bjoern，-快速的、异步WSGI服务器，用C写的。

## 11. 安全
Permissions函数库，允许或拒绝用户访问数据或函数。
django-guardian,Django守护者，管理每个对象的权限，用于Django 1.2 +Carteblanche，管理导航和权限。
Authomatic，简单强大的认证/授权客户端。
OAuthLib， 通用，规范，OAuth请求签约工具。
rauth，用于OAuth 1.0，2.0，的Python库。
python-oauth2，利用全面测试，抽象接口来创建OAuth的客户端和服务器。
python-social-auth，易于安装的社会认证机制。
,django-oauth-toolkit,Django OAuth工具包django-oauth2-provider,Django OAuth2工具包。 django-allauth，Django认证的应用程序。
Flask-OAuthlib，Flask的OAuth工具包sanction，制裁，简单的oauth2客户端。
jose，[JavaScript]对象签名和加密(JOSE)草案实施，标记状态。
python-jwt，JSON的Web令牌生成和验证模块。
pyjwt，JSON的Web令牌草案01。
python-jws，JSON的Web令牌草案02。
PyCrypto，Python的加密工具包。
Paramiko，sshv2协议的实现，提供了客户端和服务器端的功能。
cryptography，密码开发工具包。
PyNac，网络和密码（NaCl）函数库。hashids，hashids的 Python函数库。
Passlib，安全的密码存储/哈希库，非常高的水平。
hashlib,md5, sha等hash算法，用来替换md5和sha模块，并使他们的API一致。
它由OpenSSL支持，支持如下算法：md5,sha1, sha224, sha256, sha384, sha512.

## 12. GUI
PyGtk，基于Python的GUI程序开发GTK+库
PyQt用于Python的QT开发库
WxPythonPython下的GUI编程框架，其消息机制与MFC的架构相似,入门非常简单，需要快速开发相关的应用可以使用这个
TkinterPython下标准的界面编程包，因此不算是第三方库了
PySide，跨平台Qt的应用程序和用户界面框架，支撑Qt v4框架。
wxPython，混合wxWidgets的C++类库。
kivy，创建应用程序GUI函数库，看运行于Windows，Linux，MAC OS X，Android和iOS
curse，用于创建终端GUI应用程序。
urwid，创建终端GUI应用程序窗体的函数库，支持事件，色彩丰富。
pyglet，跨平台的窗口和多媒体库的Python。
Tkinter，是Python事实上的标准GUI软件包。
enaml，创建漂亮的用户界面，语法类似QML。
Toga，托加，OS原生GUI工具包。

## 13. 构建封装
pyenv,简单的Python版本管理。
virtualenv,创建独立的Python环境，用于同时安装不同版本的python环境。
virtualenvwrapper，是virtualenv的一组扩展。
pew,一套管理多个虚拟环境的工具。
vex，使运行指定的virtualenv命令。
PyRun，一个单文件，无需安装的Python版本管理工具。
PIP，Python包和依赖的管理工具。
easy_install，软件包管理系统,提供一个标准的分配Python软件和 函式库的格式。是一个附带设置工具的模块，和一个第三方函式库。旨在加快Python函式库的分配程式的速度。类似Ruby语言的RubyGems 。
conda，跨平台，二进制软件包管理器。
Curdling，一个管理Python包的命令行工具。
wheel，Python发行的新标准，旨在替代eggs.
cx-Freeze，跨平台的，用于打包成可执行文件的库
py2exe, Windows平台的Freeze脚本工具，Py2exe ，将python脚本转换为windows上可以独立运行的可执行程序
py2app，MAC OS X平台的Freeze脚本工具
pyinstaller，-转换成独立的可执行文件的Python程序（跨平台）。
pynsist,构建Windows安装程序的工具，用Python编写。
dh-virtualenv,建立和分发virtualenv(Debian软件包格式)
PyPI，新一代的Python包库管理工具。
warehouse,新一代的Python包库（PyPI）管理工具。
devpi，PyPI服务器和包装/测试/发布工具。
localshop，PyPI官方包镜像服务器，支持本地（私人）包上传。
buildout，创建，组装和部署应用程序的多个部分，其中一些可能是非基于Python的。 SCons，软件构造工具。
platformio，一个控制台的工具，构建的代码可用于不同的开发平台。
bitbake，特殊设计的工具，用于创建和部署[嵌入式]Linux软件包
fabricate，自动为任何编程语言，生成依赖包。
django-compressor，Django压缩机，压缩和内联JavaScript或CSS，链接到一个单一的缓存文件。 jinja-assets-compressor，金贾压缩机，一个Jinja扩展，通过编译，压缩你的资源。
webassets，优化管理，静态资源，独特的缓存清除。
fanstatic，球迷，包优化，提供静态文件。
fileconveyor，监控资源变化，，可保存到CDN（内容分发网络）和文件系统。
django-storages，一组自定义存储Django后台。
glue，胶胶，一个简单的命令行工具，生成CSS Sprites。
libsass-python，Sass (层叠样式表)的Python接口。
Flask-Assets，整合应用程序资源。

## 14. 代码调试
unittest，Python标准库，单元测试框架。
nose，鼻子，unittest延伸产品。
pytest，成熟的全功能的Python测试工具。
mamba，曼巴，Python的权威测试工具。出自BDD的旗下。
contexts，背景，BDD测试框架，基于C#。
pyshould，should风格的测试框架，基于PyHamcrest.
pyvows，BDD风格测试框架
Selenium，web测试框架，Python绑定Selenium。
splinter，分裂，测试Web应用程序的开源工具。
locust，刺槐，可扩展的用户负载测试工具，用Python写的。
sixpack，语言无关的A/B测试框架。
mock，模拟对象（英语：mock object，也译作模仿对象），模拟测试库。
responses，工具函数，用于mock模拟测试。
doublex-强大的测试框架。
freezegun，通过时间调整，测试模块。
httpretty， HTTP请求的模拟工具。
httmock，mock模拟测试。
coverage，代码覆盖度量测试。
faker，生成模拟测试数据的Python包。
mixer，混频器，产生模拟数据，用于Django ORM，SQLAlchemy，Peewee, MongoEngine, Pony ORM等
model_mommy，在Django创建测试随机工具。
ForgeryPy，易用的模拟数据发生器。
radar，雷达，生成随机日期/时间。
FuckIt.py，测试Python代码运行。
Code Analysispysonar2，Python类型索引。
pycallgraph,可视化的流量（调用图）应用程序。
code2flow,转换Python和JavaScript代码到流程图。
LinterFlake8，源代码模块检查器
pylama，Python和JavaScript代码审计工具。
Pylint，源代码分析器，它查找编程错误，帮助执行一个代码标准和嗅探一些代码味道。注意：相比于PyChecker，Pylint是一个高阶的Python代码分析工具，它分析Python代码中的错误。
Pyflakes，一个用于检查Python源文件错误的简单程序。Pyflakes分析程序并且检查各种错误。它通过解析源文件实现，无需导入。
pdb,Python标准库,Python调试器。
ipdb,IPython使用的PDB。
winpdb独立于平台的GUI调试器。
pudb，全屏，基于python调试控制台。
pyringe，-可附着于及注入代码到Python程序的调试器。
python-statsd，statsd服务器客户端。
memory_profiler， 内存监视。
profiling，交互式Python分析器。
django-debug-toolbar, Django调试工具栏,显示各种调试信息:当前请求/响应。
django-devserver,Django调试工具。
flask-debugtoolbar,flask调试工具。

---

## File: _drafts/进行中/学习中/scipy.md

## 常数

### 常数1

```py
from scipy import constants
constants.c #真空光速
constants.h #普朗克常亮
```

### 常数2

```py
constants.physical_constants
#是一个dict，value3个值分别是值、单位、误差
#例如：
constants.physical_constants["electron mass"]
```

### 常数3：单位转换
```py
constants.mile
constants.inch
constants.gram
```

## special：常用函数

```
from scipy import special
special.gamma(4)
special.gamma(1+1j)
special.gammaln(1000)
```

## optimize(优化)

### leastsq
[leastsq做最小二乘估计](
http://www.guofei.site/2017/06/06/leastsq.html)

### 最小值
optimize模块还有许多求最值的算法：
- fmin
- fmin_powell
- fmin_cg
- fmin_bfgs

http://www.guofei.site/2017/06/06/fmin.html

### fsolve解方程



## interpolate插值

---

## File: _drafts/进行中/学习中/类的动态方法.md

## 前言
项目中，遇到了一个需求。用户自定义函数，这个函数作为某个类的方法。

找到几个解决方案

### 定义时添加
```python
class A:
    def fun1(self, a):
        print(self, a)


a = A()
a.fun1(1)
```
不多说了，类都要这么写
#### 例子

```python
def make_cls(k):
    class A:
        if k > 0:
            def func1(self):
                print('func1')
        if k < 0:
            def func2(self):
                print('func2')

    return A


a = make_cls(1)()
```

### types.MethodType：给实例添加方法

```python
import types


class Person(object):
    def __init__(self, name):
        self.name = name


def run(self):
    print('%s在奔跑' % self.name)


p1 = Person('p1')
p1.run = types.MethodType(run, p1)

p1.run()
```
types.MethodType的第一个参数是这个函数本身，第二个参数是在调用run这个函数的时候，传给run方法的第一个参数。

### 给类增加方法

方法属于类，即使生成实例，也是属于类

```python
import types


class Person(object):
    country = 'china'


@classmethod
def myfun1(cls):
    print(cls)

@staticmethod
def myfun2():
    print(__name__)

Person.myfun1 = myfun1
Person.myfun2 = myfun2
Person.myfun1()
Person.myfun2()
```

## 其它技巧
这样也能生成一个类
```python
cls = type('A', (object,), {'__doc__': 'class created by type'})

print(cls)
print(cls.__doc__)
```

### new
这种看似生成的是 A(), 实际上生成的是 B()
```python
class A(object):
    def __new__(cls, *args, **kwargs):
        return B()


class B(object):
    pass


a = A()
print(a)
```

---

## File: _drafts/进行中/学习中/悖论/1-1.md

什么是理性思维？  


- 同一律
- 矛盾论
- 排中论
- 充足理由律


### 同一律
同一思维过程中，任何概念必须与自身保持同一：A是A  
确保了思维的确定性
违反的情况：  
-  概念模糊
-  混淆概念
-  偷换概念



#### 概念模糊
3秀才赶考，算命大师伸出一个指头：  
一起考上，一起考不上，一个考上，一个考不上  


#### 混淆概念
人是猿猴进化来的，张三是人，所以张三是猿猴进化来的。  
（前后两个人不是同一个概念）  

凡有意杀人者当死刑，刽子手是有意杀人者，所以，刽子手当死刑。
两个“有意杀人”不是一个意思  


#### 命题保持同一

由于语法结构不同导致的一句多义
标点符号不同导致的一句多义

在反驳别人的观点时，不能曲解，将其荒谬化

### 矛盾律
两个相反的命题，不可能同时为真  


用词不当：  
死难者中唯一的幸存者  
张三不小心谋杀了李四  

### 悖论的定义
如果某命题为假，可以推出命题为真  

例子1：国王与大公鸡  
国王告诉大公鸡，你猜我将如何吃你，如果你猜对了，就红烧你，如果你猜错了，就清蒸你。  


例子2：说谎者悖论  
我正在说的这句话是假话  

例子3：罗素悖论  
所有不以自身为元素的类所构成的集合  

例子4：理发师悖论  



定理：逻辑矛盾蕴含一切  
A与非A推出B  
矛盾推出任何命题（如果矛盾成立，那么一切都成立）  


## 悖论的分类

- 违反直观，但本身是正确的命题（平方数与自然数个数相同）
- 与公认看法相悖的命题
    - 四个芝诺悖论：二分法，阿基里斯追不上龟、飞矢不动、一倍的时间等于一半
    - 康德：二律悖论
    - 中国：金乌三足，今日适越而昔来
- 从看似合理的前提出发，推出违反常识的命题。
    - 布拉里-福地悖论
    - 康托尔悖论
    - 理查德悖论
    - 彩票悖论
    - 意外考试悖论
- 从看似合理的前提，推出互相矛盾的命题
    - 罗素悖论
    -
    -


语形悖论
语义悖论
语用悖论


意外考试悖论：下周将进行一次出其不意的考试。（前一天不能知道第二天是不是会考试）  


如何结局悖论？（罗素）
- 让悖论消失，至少是隔离。  
- 让数学尽可能保持原样  
- 非特设（方案除了能解决悖论wait，还有其它理由）  

悖论不是几句话出问题，而是整个体系出问题。  


一些悖论：  
我知道自己一无所知  
没有绝对的真理

---

## File: _drafts/进行中/学习中/悖论/2-1.md

[Binary file]

---

## File: _drafts/进行中/学习中/悖论/3-1.md

芝诺悖论
公元前4世纪，芝诺乐于证明时间、运动和其他习以为常的东西并不存在

第一个论证，二分法  
要向前走1米，就要先走1/2米。要走1/2米，就要走1/4米，...，所以你走不动。  

第二个论证，阿基里斯追不上乌龟。乌龟先走1米，然后阿基里斯开始追。每个时间段内，阿基里斯追到乌龟的位置，乌龟已经向前运动了一段时间，所以阿基里斯追不上乌龟。  

第三个论证，飞矢不动。每一个瞬间，任何事物都占据一个与自身等同的空间。   

第四个论证，运动场。空间离散时，谈运动会得出荒谬的结论。  

这4个悖论刚好形成一个系统的对称性。  
1,4关于有限空间的运动，2,3是无限空间的运动。    
1,2运动的个体是1个，3,4运动的个体是2个  
1,2假设空间连续性，未加设时间是否连续。3,4假设时间的连续性，未假设空间是否连续。  

### 分析
不要用常识来反驳芝诺悖论。  
应当在理智中、在思维中、在理论中刻画、把握、理解运动。  



### 时间的一些结构特征

(xRy)表示x先于y  
1. 反对称性$\forall x,\forall y \lnot((xRy) \land (yRx))$
2. 传递性$\forall x,y,z((xRy) \land (yRz) \to (xRz))$
3. 可比较性$\forall x,y ((xRy) \lor (x=y) \lor (yRx))$
4. 无开端$\forall x \exists y (yRx) $
5. 无终点$\forall x\exists y(xRy)$
6. 稠密性$\forall x\forall y((xRy)\to \exists z((xRz)\land(zRy)))$
7. 离散性
    1. 有前驱$\forall x \exists y((yRx)\land \lnot \exists z((yRz)\land(zRx)))$
    2. 有后继$\forall x \exists y((xRy)\land \lnot \exists z((xRz)\land(zRy)))$
8. 线性
    1. 左线性$\forall x\forall y \forall z((yRx)\land(zRx)\to(y(Rz)\lor(y=z)\lor(zRy))$
    以前的时间不分叉
    2. 右线性$\forall x\forall y\forall z((xRy)\land(xRz)\to(yRz)\lor(y=z)\lor(zRy))$

不同的时间观念，几乎都是上面这些特征中的选取几个，然后推导出的。

---

## File: _drafts/进行中/学习中/悖论/all.md

值得回顾的片段

https://www.coursera.org/learn/bei-lun/lecture/Ly2t6/10-you-guan-shang-di-de-bei-lun


语言模糊性
https://www.coursera.org/learn/bei-lun/lecture/d4Ij0/15-duo-zhi-luo-ji-he-zhen-zhi-du-li-lun

---

## File: _drafts/进行中/学习中/搜索推荐/协同过滤进阶.md

## 相关系数的计算
### 余弦相似度
$sim(u,v)=\dfrac{\sum u_i v_i}{\sqrt{\sum u_i^2}\sqrt{\sum v_i^2}}$

- 余弦相似度只考虑夹角，不考虑长度。  
- 例如，两个人的评分分别是(5,5)和(1,1)，那么余弦相似度是1

### 调整余弦相似度
先把评分的均值平移到0，然后计算余弦相似度。
- 调整余弦相似度的范围是[-1,1]
- 例如，两个人的评分分别是(5,4)和(4,5)，那么调整余弦相似度是-1


### pearson相关系数
与上面的调整余弦相似度一样

$sim(u,v)=\dfrac{\sum\limits_i (r_{ui} - \bar r_u)(r_{vi} - \bar r_v)}{\sqrt{\sum\limits_i (r_{ui} - \bar r_u)^2 \sum\limits_i (r_{vi} - \bar r_v)^2}}$

### jaccard相似系数
交集的数量除以并集的数量。


$sim(u,v)=\dfrac{num(u\cap v)}{num(u\cup v)}$


### 巴氏系数
定义为$\int\sqrt{p_1(x)p_2(x)}$，其中，$p_1(x),p_2(x)$是两个概率密度函数。

## 基于时间的改进
实际中，会出现用户兴趣漂移的现象。因此，可以采用一个遗忘曲线对评分进行加权

定义遗忘曲线 $w_t=\exp \dfrac{t_{ui}-t_0}{T}$  
- $t_{ui}$是用户u对项目i打分的时间
- $t_0$目标用户的采样时间
- T整个数据集的时间跨度

然后定义遗忘曲线的pearson相关系数 $sim(u,v)=\dfrac{\sum\limits_i w_t (r_{ui} - \bar r_u)(r_{vi} - \bar r_v)}{\sqrt{\sum\limits_i (r_{ui} - \bar r_u)^2 \sum\limits_i (r_{vi} - \bar r_v)^2}}$  

## 基于数量改进
问题；我们在使用 jaccard 相似系数时，发现这种情况，A和B共有20个打分且完全一样，C和D共有2个打分且完全一样。那么AB的相关系数是1，CD的相关系数也是1，这是不合理的。加一个平滑系数：

$sim(u,v)=\dfrac{num(u\cap v)+1}{num(u\cup v)+k}$

---

## File: _drafts/进行中/学习中/搜索推荐/图神经网络.md

频域图卷积，空域图卷积


## 基本知识

同构图、异构图、属性图、非显式图

常见的场景
- 社交网络。一种典型的同构图，现代发展加入不同信息构成异构图。
- 电子购物。用户-商品二部图。
- 化学键
- 交通网络。通常解决路径规划相关问题，例如最短路径问题。
- 场景图。
- 电路设计图。器件之间的布线作为边，构成一种图。

任务分类
- 节点层面。分类或回归任务，对节点的某些性质进行预测。社交网络的用户标签分类、恶意账户检测。
- 边层面。分类或预测。边分类指的是对边的某些性质进行预测，边预测是预测给定的两个节点是否构成边。主要集中在推荐业务中。
- 图层面。对图本身进行分类、表示、生成。主要应用于自然科学，如药物分子的分类、酶的分类。

## 图的拉普拉斯矩阵

图的拉普拉斯矩阵定义如下:  
$$L_{ij}=\left \{ \begin{array}{ccc}
\deg(v_i) & i=j\\
-1        & e_{ij}\in E\\
0         & o/w
\end{array}\right.$$


拉普拉斯矩阵的定义，等价于：  
设G=(V,E)为简单无向图，D为其度对角矩阵，A为其邻接矩阵（主对角线都是0） $L=D-A$


实际上，常用的拉普拉斯矩阵有三种：  
1. $L=D-A$，更专业的名字叫 **Combinatrial Laplacian**
2. $L^{sys}=D^{-1/2}LD^{-1/2}$，叫做 **symmetric normalized Laplacian**
3. $L^{rw}=D^{-1}L$，叫做 **Random walk normalized Laplacian**



正则化的拉普拉斯矩阵定义如下：  
$$L_{ij}=\left \{ \begin{array}{ccc}
1         & i=j\\
\dfrac{-1}{\sqrt{\deg(v_i)\deg(v_j)}}   & e_{ij}\in E\\
0         & o/w
\end{array}\right.$$

### 拉普拉斯矩阵的理解
图拉普拉斯矩阵，如果把它看作线性变换的话，它起的作用与数学分析中的拉普拉斯算子是一样的。也就是说 **拉普拉斯矩阵就是图上的拉普拉斯算子，或者说是离散的拉普拉斯算子**。

拉普拉斯矩阵的优点
1. 是对称矩阵，可以进行特征分解，和 spectral domain 对应。（进一步，是半正定矩阵）
2. 只在中心顶点和一阶顶点上非零，其余都是0
3. 拉普拉斯算子和拉普拉斯矩阵类比

---

## File: _drafts/进行中/学习中/搜索推荐/学习笔记.md

## Airbnb word2vec
• reference《Real-time Personalization using Embeddings for Search Ranking at
Airbnb(kdd 2018)》
• 提出了自己的冷启动策略
• 通过修改采样模式来优化word2vec的策略


### 采样策略
- 用session分割点击序列：将用户点击序列过滤再分段成n个sessions，一个session指的是相邻item时间间隔≤30mins的"有效"行为序列
- 局部负例采样：提出要额外从同属一个cluster的其他item里抽负样本
- 付费行为强化：点击序列中若有付费行为，则将这个item
强制纳入该序列每个item的上下文窗口

### 冷启动策略
- airbnb并没有做end2end的学习属性的embedding，而是直接把new item按主要属性检索到最相似的top3个已知的item，取3个item向量的平均值初始化new item embedding

---

## File: _drafts/进行中/学习中/搜索推荐/推荐算法.md

## Graph Model

推荐中对graph model的研究主要有两个方面，一个是如何构图，另一个是如何在图上做ranking。

关于构图问题，取决于数据，首先考虑如果我们只有user item的数据，那么最简单的方法就是构造二分图，两类节点，user节点和item节点，如果user喜欢item，就在他们中间连一条边。

如果我们有了用户的profile信息，和item的content信息，这个时候又有了很多构图的方法。一种方法是用这些信息计算出user-user相似度和item-item相似度，然后把这些相似度作为权重，来给user节点之间，和item节点之间加边，这个称为two-layer graph model。相关的可以参考下面两篇论文：
1. A graph-based recommender system for digital library
2. A graph model for E-commerce recommender systems

当然，如果这些额外信息比较单一，比如我们有tag信息，我们可以构造一个3分图，加入tag节点，如果一个item有某个tag，那么他们之间有边，如果一个user用过某个tag，那么他们之间也有边。 如果是社会网络信息，我们可以直接将社会网络关系加入到user-user之间。如果我们有user参加某些group的信息，我们可以加入一类group节点，如果一个user参加过一个group，在中间就会有一条边。

基本的构图思想就是上面这些，下面讨论图的rank问题。

图上的rank，分为三大类：

一类是基于图上的随机游走，一般用迭代法，速度很快，相关的论文有：

1.Topic-Sensitive PageRank
2.TrustWalker: a random walk model for combining trust-based and item-based recommendation

还有周涛发表的一些论文，二分图上的扩散等

另一类是把推荐的问题看做一个半监督学习的问题，从而用传播的算法，最经典的是下面这篇博士论文
Semi-Supervised Learning with Graphs
这篇文章的作者是用图做半监督学习的权威

最好一类是用图的Laplacian矩阵来度量图中顶点的相似度，最经典的工作是下面这篇论文：
Random-Walk Computation of Similarities between Nodes of a Graph with Application to Collaborative Recommendation


https://blog.csdn.net/AnUnverse/article/details/104516493

## 冷启动问题
例如，一个新物品，还没产生浏览数据，模型很难输出推荐这个物品。一个新用户也是一样。  

解决方法
1. 得到新物品/新用户的标签。例如，给物品手动打标，然后找到最近的TOP15物品，使用他们对应向量的平均值作为新物品的向量。新用户是通过什么渠道介绍来的，与用户所在群体有关。
2. 实验。分出一定的流量去给用户去试。这会降低线上推荐算法的效果，所以需要人去 trade off


## 参考资料
https://blog.csdn.net/u011748319/article/details/90269818

https://www.zhihu.com/question/20326697/answer/58148605

推荐中的GRAPH MODEL：https://www.cnblogs.com/startover/p/3169603.html


## 讲座

### 1
http://v.qq.com/vplus/de9f3237bfc440568cd6e6189ae90664

wide&deep 模型，google 在2016年提出来的，在推荐排序获得早期成功的模型

DeepFM 模型，效果略好于 wide&deep，但耗时增加


排序算法的特征分为几类：
- 用户画像特征。
  - 自身的属性，性别年龄等
  - 用户行为，浏览等
  - 基于行为衍生的特征，例如标签偏好等
- item特征
  - item 自身的属性
  - item 挖掘出的特征，例如内容分类、关键词、情感等
  - item 被用户赋予的特征，例如pv，uv
- 交互特征
  - item与用户的匹配度


### 2
讲的召回算法，挺好

https://v.qq.com/x/page/w3030aybnyh.html

采样策略：
1. 借鉴 airbnb，对与被dislike的，采样窗口无限大，并且作为负例
2. 有些负例是没被曝光过的，这不合理。作为改进，采用曝光过的，但未被用户点击的作为负例。


GCNs:一种比较新的 embedding  
(其实没太懂)

召回（看原视频）
- 全局召回
  - 热榜召回
  - 热搜召回
  - 热词召回
- 个性化召回
- 属性召回
- 相关召回

召回的基础模型：YouTubeNet，先把user和item都做成item，然后用近邻算法。

个性化召回：把用户聚类，分为不同的组，不同的组给不同的榜单

---

## File: _drafts/进行中/学习中/搜索推荐/知识图谱.md

[Binary file]

---

## File: _drafts/进行中/学习中/搜索推荐/评估.md

## 在线广告预估ctr的AUC计算方法

CTR
:    （Click-Through-Rate）即点击通过率。计算公式为CTR=实际点击次数/展示量，即 Click / Show content


## AUC
ROC曲线是这样的：  
横轴是FPR，纵轴是TPR  

对每次点击，ground truth 是0/1 分类数据，也就是点击/不点击。  
模型预测值：这次展示，用户点击的概率

这是一个标准的分类模型+概率输出场景，因此可以画 ROC 曲线，并计算 AUC

## 计算

https://blog.csdn.net/cserchen/article/details/7535182

https://blog.csdn.net/zcc_0015/article/details/77246407


```python
def scoreClickAUC(num_clicks, num_impressions, predicted_ctr):
    """
    Calculates the area under the ROC curve (AUC) for click rates

    Parameters
    ----------
    num_clicks : a list containing the number of clicks
    num_impressions : a list containing the number of impressions
    predicted_ctr : a list containing the predicted click-through rates
    Returns
    -------
    auc : the area under the ROC curve (AUC) for click rates
    """
    i_sorted = sorted(range(len(predicted_ctr)),key=lambda i: predicted_ctr[i],
                      reverse=True)
    auc_temp = 0.0
    click_sum = 0.0
    old_click_sum = 0.0
    no_click = 0.0
    no_click_sum = 0.0

    # treat all instances with the same predicted_ctr as coming from the
    # same bucket
    last_ctr = predicted_ctr[i_sorted[0]] + 1.0

    for i in range(len(predicted_ctr)):
        if last_ctr != predicted_ctr[i_sorted[i]]:
            auc_temp += (click_sum+old_click_sum) * no_click / 2.0
            old_click_sum = click_sum
            no_click = 0.0
            last_ctr = predicted_ctr[i_sorted[i]]
        no_click += num_impressions[i_sorted[i]] - num_clicks[i_sorted[i]]
        no_click_sum += num_impressions[i_sorted[i]] - num_clicks[i_sorted[i]]
        click_sum += num_clicks[i_sorted[i]]
    auc_temp += (click_sum+old_click_sum) * no_click / 2.0
    auc = auc_temp / (click_sum * no_click_sum)
    return auc
```
当点击是0-1型数据时，与 `sklearn.metrics.roc_auc_score` 结果完全一致，但这个自定义函数还可以处理多次点击的数据

---

## File: _os/1_sko/sko_en.md

---
layout: open_source
title: 【en】scikit-opt
categories: 开源
tag: scikit-opt
keywords:
order: 101
repo_name: scikit-opt
---

---

## File: _os/1_sko/sko_zh.md

---
layout: open_source
title: scikit-opt
categories: 开源
tag: scikit-opt
order: 102
repo_name: scikit-opt
---

---

## File: _os/2_wm/bw_en.md

---
layout: open_source
title: 【en】blind_watermark
categories: 开源
tag: Watermark
order: 201
repo_name: blind_watermark
---

---

## File: _os/2_wm/bw_zh.md

---
layout: open_source
title: blind_watermark
categories: 开源
tag: Watermark
order: 202
repo_name: blind_watermark
---

---

## File: _os/2_wm/hide_info.md

---
layout: open_source
title: HideInfo
categories: 开源
tag: Watermark
order: 210
repo_name: HideInfo
---

## HideInfo

[](https://github.com/guofei9987/HideInfo)


一些小而美的信息隐藏方法  



[](https://pypi.org/project/HideInfo/)
[](https://github.com/guofei9987/HideInfo/blob/main/LICENSE)


[](https://github.com/guofei9987/HideInfo/)
[](https://github.com/guofei9987/HideInfo/fork)
[](https://pepy.tech/project/HideInfo)




| 算法                                                                                         | 说明                |
|--------------------------------------------------------------------------------------------|-------------------|
| [幻影坦克](https://github.com/guofei9987/HideInfo/blob/main/example/example_mirage_tank.py)    | 使图片在不同的背景下显示不同的图片 |
| [化物为图](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_as_img.py)    | 把数据以图片形式存放        |
| [藏物于图](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_in_img.py)    | 把数据藏在一个图片中        |
| [图片隐水印](https://github.com/guofei9987/HideInfo/blob/main/example/example_img_watermark.py) | 图片空域上的隐水印         |
| [图种](https://github.com/guofei9987/HideInfo/blob/main/example/example_img_seed.py)         | 把图片和文件黏在一起，并存为图片  |
| [EXIF](https://github.com/guofei9987/HideInfo/blob/main/example/example_img_exif.py)       | 把一段信息放到图片的EXIF中   |
| [化物为音](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_as_music.py)  | 把数据以音频的形式存放       |
| [藏物于音](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_in_music.py)  | 把数据隐藏在一个音频中       |
| [回声水印](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_in_music.py)  | 以回声的形式，把二进制嵌入到音频中 |
| [化物为文](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_as_txt.py)    | 把数据以文本文件的形式存放     |
| [藏物于文](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_in_txt.py)    | 把数据隐藏在一段文本中       |




安装
```
pip install HideInfo
```


## 幻影坦克

功能：把两个图片合并，使其在黑色背景下显示图片A，在白色背景下显示图片B

说明
- 已支持彩色图片
- 一般情况下，手机/浏览器的预览和点击大图分别使黑色背景和白色背景，因此有"预览和点击是两张不通的图"的效果
- 视频展示：[B站](https://www.bilibili.com/video/BV1DF41117c7/)
- 代码：[example/example_mirage_tank.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_mirage_tank.py)


```python
from hide_info import mirage_tank

mirage_tank.mirage_tank('图片.png', 'img2.jpeg', '幻影坦克.png')
```

## hide_as_img:化物为图

功能：把文件/文本/bytes 类数据，转换为图片  
原理：图片 1 个像素的 1 个通道可以存放 0-255 的数字，也就是一个字节。因此可以用来存放数据。
使用场景：
- 信息隐藏、隐蔽传输
- 在只能发送图片的场景下（例如社交软件），发送任意信息

说明
- RGB 3个通道都用来存放数据，但不使用透明通道
- 使用前4个字节记录数据的大小，因此要求总的数据量小于 4G
- 可以存放文件、文本、字节等类型的数据，把它转化为一张图片
- 代码：[example_hide_as_img.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_as_img.py)

```python
from hide_info import hide_as_img

# 文件转为图片并存下来
hide_as_img.file_encode(filename='要隐藏的文件.zip', img_filename='化物为图.png')
# 把图片再转回文件
hide_as_img.file_decode(filename='化物为图-解出来的文件.zip', img_filename='化物为图.png')
```

## hide_in_img：藏物于图

功能：把文件/文本/字节 类数据，藏进一个预先准备好的 PNG 图片中，使其用肉眼无法看出区别  
原理：（LSB算法）根据信息的二进制，改变像素数据的最低位，肉眼是无法察觉这种改变  
使用场景：
- 信息隐藏、隐蔽传输
- 在只能发送图片的场景下（例如某社交软件），发送任意信息
- 盲水印、图片溯源、版权保护


说明
- 解原始数据时，无需原图参与
- 使用前4个字节存放数据的大小
- 使用位运算，提高一定的性能
- LSB算法对压缩、转格式等攻击脆弱
- 例子：[example_hide_in_img.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_in_img.py)

```python
from hide_info import hide_in_img

# 把文件隐藏到图片中
hide_in_img.file_encode(filename='要隐藏的文件.zip', img_filename='图片.png', img_filename_new='藏物于图.png')
# 从图片中提取文件
text_encode = hide_in_img.file_decode('藏物于图-解出的文件.zip', img_filename='藏物于图.png')
```

## img_watermark: 图片空域上的隐水印

说明：
- 同样使用 LSB 算法。 
- 水印是一个 **二值图**。
- 可对抗裁剪攻击
- 如果图片有大片纯色区域，对这些攻击有一定的鲁棒性：缩放、转格式、截图、裁剪。如果没有大片纯色区域，则不能对抗这些攻击。
- 例子：[example/example_img_watermark.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_img_watermark.py)

代码 
```python
from hide_info import img_watermark

# 嵌入隐式水印
img_watermark.file_encode(img_filename="图片.png", watermark_filename="watermark.png", img_filename_new="图片_打入水印.png")

# 提取隐式水印
img_watermark.file_decode(img_filename="图片_打入水印.png", wm_extract="解出的水印.png")
```

## img_seed:图种

功能：把图片和文件连接起来，以图片的形式存下来（目前还不完善）

- 例子：[example/example_img_seed.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_img_seed.py)

原理
- jpg 的内容结束标志为 FF D9，它不关心之后的内容
- rar 的内容开始标志为 52 61 71 21，它不关心前面的内容

## img_exif:把信息隐藏在图片的EXIF中

功能：把信息隐藏在图片的 EXIF 中，从而获得隐蔽信息、传输隐蔽信息的能力

- 例子：[example/example_img_exif.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_img_exif.py)

## hide_in_music: 藏物于音

功能：把一段信息（文件/文本/bytes），藏进一个音乐文件中

例子：
- [example_hide_in_music.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_in_music.py)

```python
from hide_info import hide_in_music

# 把文件隐藏到某个音乐中
hide_in_music.file_encode(filename='要隐藏的文件.zip', music_filename="音乐.wav", music_filename_new="藏物于音.wav")
# 从音乐中提取文件
hide_in_music.file_decode(filename="藏物于音-解出的文件.zip", music_filename="藏物于音.wav")
```

## hide_as_music：化物为音

功能：把一段信息（文件/文本/bytes），转为声音
原理：用 16 种音可以表示一个四进制。如果每个音持续 0.05 秒，那么每秒声音可以存放 10 字节
使用场景：
    - 信息隐藏、隐蔽传输
    - 在只能发送图片的场景下（例如某社交软件），发送任意信息
    

说明
- 例子：[hide_as_music.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_as_music.py)

```python
from hide_info import hide_as_music

# 文件转为声音并存下来
hide_as_music.file_encode(filename='要隐藏的文件2.zip', wav_filename='化物为音.wav')
# 把声音再转回文件
hide_as_music.file_decode(filename='化物为音-解出来的文件.zip', wav_filename='化物为音.wav')

```

## echo_watermark: 回声水印

人类听觉系统（HAS）极为灵敏，音频感知冗余小，音频水印同时满足隐蔽性和鲁棒性有一定难度。同时音频压缩算法如 MP3 有损压缩有出色的压缩率和音质，对音频水印带来很大的挑战。

掩蔽效应是 HAS 的一个特点：短时间内高能量部分会掩蔽低能量部分，从而让人耳只能听见高能量部分，掩蔽分为超前掩蔽、同时掩蔽、滞后掩蔽。因此可以将信息隐藏在音频信号的回声中而不影响听感。

回声水印（Echo Watermarking）是一种音频水印技术，通过在原始音频信号中添加回声来嵌入信息。

回声水印的实现通常有两个重要参数：回声延迟和回声幅度。延迟时间决定了回声在原始信号之后多久发生，而幅度则影响回声的强度。通过巧妙地调节这两个参数，可以将数字信息（如比特流）编码到音频信号中。

例如，可以用短的延迟时间表示比特'0'，用长的延迟时间表示比特'1'，或者通过调整回声的幅度来表示不同的数据位。

回声水印技术对于音质的影响相对较小，同时具有较好的鲁棒性，能够在一定程度上抵抗压缩、转换等处理过程。这使得它适用于版权保护、内容认证、隐秘通讯等领域。

```python
from hide_info.echo_watermark import EchoWatermark
from hide_info import utils, evaluate
from scipy.io import wavfile

ori_file = "./ori_file/sounds.wav"  # 载体
embedded_file = "./output/sounds_with_watermark.wav"  # 嵌入水印后的文件名
wm_str = "回声水印算法，欢迎 star!"  # 水印

wm_bits = utils.bytes2bin(wm_str.encode('utf-8'))
len_wm_bits = len(wm_bits)

# embed:
echo_wm = EchoWatermark(pwd=111001)
echo_wm.embed(origin_filename=ori_file, wm_bits=wm_bits, embed_filename=embedded_file)

# extract：
echo_wm = EchoWatermark(pwd=111001)
wm_extract = echo_wm.extract(embed_filename=embedded_file, len_wm_bits=len_wm_bits)

wm_str_extract = utils.bin2bytes(wm_extract).decode('utf-8', errors='replace')
print("extract watermark: ", wm_str_extract)
# error rate：
evaluate.get_error_rate(wm_extract, wm_bits)
```


## hide_in_text：藏物于文

功能：把一段信息（文件/文本/bytes），藏进一段文本中

说明
- 实测在苹果设备 Macbook、IOS 上，隐藏前后的文本看不出区别。但是 Windows 和某些安卓系统上，会有空格
- 例子：[hide_in_txt.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_in_txt.py)

```python
from hide_info import hide_in_txt

# 把一个文件隐藏在一段已有的文本中
hide_in_txt.file_encode(filename='要隐藏的文件2.zip', text_filename='一段文本.txt', text_filename_new='藏物于文.txt')
# 从文本中提取文件
hide_in_txt.file_decode(filename='藏物于文-解出的文件.zip', text_filename='藏物于文.txt')
```

## hide_as_txt: 化物为文

功能：把一段信息（文件/文本/bytes），以文本的形式存放下来

说明
- 使用的是 base85 算法
- 例子：[hide_as_txt.py](https://github.com/guofei9987/HideInfo/blob/main/example/example_hide_as_txt.py)

```python
from hide_info import hide_as_txt

# 把一个文件转化为一段文本，并存下走
hide_as_txt.file_encode(filename='要隐藏的文件.zip', txt_filename='化物为文.txt')
# 从文本中提取文件
hide_as_txt.file_decode(filename='化物为文-解出的文件.zip', txt_filename='化物为文.txt')
```

## 其他算法

缩放藏图：提前计算用近邻法缩放时使用的时哪些像素点，然后把这些像素点变成另一个图。

---

## File: _os/2_wm/text_wm.md

---
layout: open_source
title: 文本隐水印
categories: 开源
tag: Watermark
order: 205
repo_name: blind_watermark
---

<style>
    textarea {
        width: 98%;
        height: 200px;
    }
    .middle {
        text-align: center;
    }
    th,td{
        text-align: center;
    }
</style>



<h4 class="middle">0. 设置密码</h4>

    **密码*：**
    


<hr>

<h4 class="middle">1. 把隐水印嵌入到明文</h4>



| 密文和载体 | embed=&gt; | 嵌入后的载体 |
| --- | --- | --- |
| **密文：** |  |  |
|  |  |  |





<hr>

<h4 class="middle">2. 提取隐水印</h4>



| 嵌入密文后的载体 | extract=&gt; | 解出的密文 |
| --- | --- | --- |
|  |  |  |



<hr>




<script type="module">
    import init, { Watermarker } from "/a/app/hidden_watermark/pkg/wasm_text_watermark.js";

    async function run() {
        await init();

        let watermarker = null; // Watermarker 实例

        // 获取 DOM 元素
        const passwordInput = document.getElementById("password");
        const embedBtn = document.getElementById("embedBtn");
        const extractBtn = document.getElementById("extractBtn");

        // 初始化 Watermarker 实例
        function createWatermarker(password) {
            try {
                return new Watermarker(password);
            } catch (e) {
                console.error("初始化 Watermarker 失败:", e);
                alert("密码无效，请重新输入！");
                return null;
            }
        }

        passwordInput.addEventListener("change", () => {
            const password = passwordInput.value;
            if (password) {
                watermarker = createWatermarker(password);
            } else {
                alert("密码不能为空！");
            }
        });

        embedBtn.addEventListener("click", () => {
            if (!watermarker) {
                alert("请先设置密码！");
                return;
            }

            const wm = document.getElementById("wm").value;
            const baseText = document.getElementById("baseText").value;

            if (!wm) {
                alert("请输入需要隐藏的密文！");
                return;
            }

            if (!baseText) {
                alert("请输入作为掩护的明文！");
                return;
            }

            try {
                const textWithWm = watermarker.embed(baseText, wm);
                document.getElementById("newText").value = textWithWm;
            } catch (e) {
                console.error(e);
                alert("嵌入水印时出错！");
            }
        });

        extractBtn.addEventListener("click", () => {
            if (!watermarker) {
                alert("请先设置密码！");
                return;
            }

            const textWithWm = document.getElementById("text_embed2").value;

            if (!textWithWm) {
                alert("请输入嵌入水印后的明文！");
                return;
            }

            try {
                const extractedWm = watermarker.extract(textWithWm);
                document.getElementById("wm_extract").value = extractedWm;
            } catch (e) {
                console.error(e);
                alert("提取水印时出错！");
            }
        });
    }

    run();
</script>


## Source Code

|Rust|Python|Javascript|
|--|--|--|
|[](https://github.com/guofei9987/hidden_watermark)|[](https://github.com/guofei9987/text_blind_watermark) | [javascript](https://www.guofei.site/pictures_for_blog/app/text_watermark/v1.html)


## How to use

[https://www.bilibili.com/video/BV1m3411s7kT](https://www.bilibili.com/video/BV1m3411s7kT)

---

## File: _os/5_备忘与构想/about_sec.md

---
layout: open_source
title: 关于工具的说明
categories: 开源
tag: DevNotes
order: 209
---


本站采用 **静态网站** 架构，所有工具均为纯前端实现，没有后端服务。  
所有处理均在用户本地浏览器完成，不会上传文件或数据，源码也全部公开。

## 安全检测说明

有人关心：公司安全系统能否检测到你在使用本工具？这里做一个简短说明。



### 一、公司安全系统能看到什么？

通常能看到：访问了本网站，包括
- 访问了 `guofei.site`
- 打开了 `/os/hide_as_img.html`
- 页面停留时间


### 二、通常看不到什么？

本网站的工具均不具备“上传文件到服务器”的功能。  
因此，在普通网络监控环境下，公司网络层通常无法看到你实际选择了哪些本地文件，也无法看到文件内容。


## 重度监控环境下可能的情况



在军工/金融/涉密等极高敏感的场景下，你的电脑会被做非常重的监控，那么可能被监控到这些：

1. 如果浏览器被深度注入。例如，安装了特供浏览器、浏览器插件、EDR，Hook 浏览器 API 等。
    - 能看到：你选了什么文件、文件的 hash、文件名
    - 看不到：文件内容（大概率）
2. 如果安装了高级 EDR/DLP。可以监控内存、浏览器进程等。
    - 能看到的：浏览器读取了本地文件。因为浏览器是掉用 OS 文件 API，`浏览器 file input`
    - 但是，企业安全一般认为这是低风险的，这是因为浏览器每天都在打开 PDF、读取图片、选择文件等，你的操作被淹没在海量相似的监控日志里（如果有这个日志的话）
3. 截屏审计。这个相当于你背后站着个人，神仙来了也没办法。


## 关于离线使用

如果将网页保存到本地、离线运行：
1. 网络层监控失明。
2. 但是浏览器的本地行为仍可能被 EDR 看见。


## 最后说明

不存在“绝对隐蔽”的方式。  
本网站仅用于技术研究与学习交流，请勿用于商业或者非法用途。



## 其它相关脑洞

ScreenDrop 是通过屏幕 => 摄像头传输信息的。借助了当前生态完整的 QR 为中介。  

梳理需求，还是有其它潜在（脑洞）方案的

需要额外硬件的
- HDMI：播放视频，并通过 HDMI 传输数字信号，理论上可以达到极高的传输率
- 音频线

只需要手机的
- 音频
- 二维码
- base64（文本）+OCR


更大的脑洞
- 风扇的转速
- 机箱上的 RGB 灯
- 主板上的声音
- 电磁特性


显示器
- 除了 QR 之外，还可以有：条纹、彩色块、其它二维码、彩色二维码之类的。

---

## File: _os/5_备忘与构想/bwm_enhance.md

---
layout: open_source
title: 【改进】blind_watermark
categories: 开源
tag: DevNotes
order: 209
repo_name: blind_watermark
---


## 1. 性能方面
### svd性能

使用 `profile` 发现，程序运行过程中 `np.svd` 占用80% 的耗时，因此需要改进。



SVD 数学描述：$A_{m\times n}=U_{m\times m}S_{m\times n}V_{n\times n}^T$
- 其中,U,V是正交矩阵，$UU^T=E, VV^T=E$
- S是对角矩阵

### 第一次提升性能

blind_watermark 的一些特点，使得这个步骤有一定的性能提升空间
- A是确定的 4x4 的矩阵
- 最终需要的不是 svd 分解后的 3 个矩阵，而是改变 最大特征值之后的乘积

$AA^T=(USV)(USV)^T=USVV^TS^TU^T=US^2U^T$  
$A^TA=VS^2V^T$  

要的最终结果是
$$A_2=U(S+
[\begin{array}{c}
    x&0&0&0\\ 0&0&0&0 \\0&0&0&0 \\ 0&0&0&0 \\
    \end{array}]
    )V=A+U
[\begin{array}{c}
    x&0&0&0\\ 0&0&0&0 \\0&0&0&0 \\ 0&0&0&0 \\
    \end{array}]
    V$$
$$=A+[u_1u_2u_3u_4][\begin{array}{c}
    x&0&0&0\\ 0&0&0&0 \\0&0&0&0 \\ 0&0&0&0 \\
    \end{array}][\begin{array}{c}
    v_1^T\\ v_2^T \\ v_3^T \\ v_4^T \\
    \end{array}]
=A+u_1xv_1^T
$$

因此只需要求解最大特征值，以及最大特征值对应的特征向量

另一篇博客，写了如何用迭代法求解最大特征值，以及最大特征值对应的特征向量。

【代码】

结果：
- 平均需要5次迭代，每次迭代计算1次矩阵积
- 实际性能：（试验1万次），单次耗时为 `np.svd` 的 30%
- 但是为了替代 svd，需要调用2次求特征值，算上计算 $AA^T,A^TA$的消耗，耗时并没有降低。尽管绝对的计算量低很多。
- 这是因为 python 脚本比不上深度调优的 `np.svd`
- 下面进一步优化，只需要计算1次特征值，另一个特征向量用一个矩阵积得到

### 进一步优化

注意到 $AA^T,A^TA$ 都是实对称矩阵，而且特征值一定一模一样。以此为入手点，继续优化。

假设
- $AA^T$对应的最大特征值 $\lambda$，特征向量 $u_1$
- $A^TA$对应的最大特征值一定也是 $\lambda$，特征向量 $v_1$

推导：
- 特征值的定义：$A^TAv_1=\lambda v1$
- 左乘 A：$AA^TAv_1=\lambda A v_1$
- 也就是 $AA^T(Av_1) =\lambda (A v_1)$
- 得到 $Av_1=u_1$（然后还要对 $u_1$ 做个单位化）

上面的算式有一项 $u_1xv_1^T$ 实际上就是 $x u_1 v_1^T = x A v_1 v_1^T$ （还要乘以单位化的系数）  
颠倒过来推导，也可以得到 $u_1u_1^T A$


代码
```

'''
待替换：

def block_add_wm_slow(self, arg):
        block, shuffler, i = arg
        # dct->(flatten->加密->逆flatten)->svd->打水印->逆svd->(flatten->解密->逆flatten)->逆dct
        wm_1 = self.wm_bit[i % self.wm_size]
        block_dct = dct(block)

        # 加密（打乱顺序）
        block_dct_shuffled = block_dct.flatten()[shuffler].reshape(self.block_shape)
        u, s, v = svd(block_dct_shuffled)
        s[0] = (s[0] // self.d1 + 1 / 4 + 1 / 2 * wm_1) * self.d1
        if self.d2:
            s[1] = (s[1] // self.d2 + 1 / 4 + 1 / 2 * wm_1) * self.d2

        block_dct_flatten = np.dot(u, np.dot(np.diag(s), v)).flatten()
        block_dct_flatten[shuffler] = block_dct_flatten.copy()
        return idct(block_dct_flatten.reshape(self.block_shape))
'''

import numpy as np
from numpy.linalg import svd

d1 = 36


def algo_old(block_dct_shuffled, wm_1):
    u, s, v = svd(block_dct_shuffled)

    s[0] = (s[0] // d1 + 1 / 4 + 1 / 2 * wm_1) * d1
    return np.dot(u, np.dot(np.diag(s), v))


# %%


from numba import jit

# 精度
precision = 1e-8


@jit(nopython=True)
def get_eig(A):
    # 精度
    x = np.random.rand(4, 1)
    y_norm_old = 0

    for i in range(20):
        y = A @ x
        y_norm = np.linalg.norm(y)
        x = y / y_norm

        if -precision < y_norm - y_norm_old < precision:
            # 特征值，特征向量
            return (x.T @ A @ x)[0, 0], x

        y_norm_old = y_norm

    return (x.T @ A @ x)[0, 0], x


@jit(nopython=True)
def block_add_wm3(A, wm_1):
    lam, u1 = get_eig(A @ A.T)
    lam = np.sqrt(lam)

    v1 = A.T @ u1
    v1 = v1 / np.linalg.norm(v1)

    add = (lam // d1 + 1 / 4 + 1 / 2 * wm_1) * d1 - lam
    return A + (u1 @ v1.T) * add


block_dct_shuffled = np.random.rand(4, 4) * 255

wm_1 = 0
res1 = block_add_wm3(block_dct_shuffled, wm_1)
res2 = algo_old(block_dct_shuffled, wm_1)

assert (np.abs(res1 - res2)).max() < 1e-6

import datetime

num = 10000
A_ = np.random.rand(4, 4) * 255
A = np.sqrt(A_ @ A_.T)

start_time = datetime.datetime.now()
for i in range(num):
    block_add_wm3(block_dct_shuffled, wm_1)
print(datetime.datetime.now() - start_time)

start_time = datetime.datetime.now()
for i in range(num):
    algo_old(block_dct_shuffled, wm_1)
print(datetime.datetime.now() - start_time)

```


## 2. 对截图的优化

（牵涉较多）

截图（裁剪+缩放）后，现在需要原图来计算其原本的位置和大小。希望改进算法后，不需要原图。
1. 推导公式发现， dct+svd，可以简化为 svd（如果不考虑shuffle的话）
2. svd 性能太低，如果用解析解 4x4 对应的是 4次方程，也不简单。可以考虑用 3x3
3. 可以不用 svd，因为 dct 本身倾向于就把低频部分放到左上角。而 4x4 这么小的分快一般就是低频为主。经过实验室可行的。试了一下，相当于原像素点加上 `k * ones`，本质上就是一种 LSB


如果只考虑裁剪，这些算法可以。但是对缩放、旋转，无法有效定位。
1. 同步码
2. 二维模版定位

Fourier-Mellin 
- log-polar 域
- 但其复杂度高、某些场景下更脆弱

特征点对其
- SIFT/SURF/ORB 等




## 3. 加入水印清晰度指标

1. 水印清晰度。指的是所有方块清晰度的平均值
2. 水印一致性。指的是重复的水印（以及纠错码）的一致性



## 4. 加入 ECC

待加入，比较方便

---

## File: _os/5_备忘与构想/constrained_regression.md

---
layout: open_source
title: 【轮子】带约束的岭回归
categories: 开源
tag: DevNotes
order: 710
---





## 前言
### 1. 为何是岭回归
实战中，有可能碰见这种情况，几个数据特征是相关的。如果不使用二阶惩罚项，小属性趋势容易“叠加”到大属性上，从而小属性完全失效。  
例如，要做一个手机的价格的预测模型，CPU和内存很可能是高度相关的。普通的线性回归容易把价格“归类”到某一个属性上。  

### 2. 为何带约束

实战中，往往碰到这种情况，数据中的长尾属性很多。例如，某些属性是稀有属性，涉及到的记录数比较少。  
尽管总的数据量很大，但稀有属性的数据量却可能不大。  
因此需要人为给定一些排序（所谓的先验专家知识）

### 3. 与其他模型的对比
- 线性模型：训练集上优秀，测试集上极差，因为过拟合现象。
- Lasso：训练集测试集均好于此模型，但一方面对稀有属性过拟合，另一方面不符合业务认知。

## 造轮子

带约束的岭回归

$C=\lVert Xw-y\rVert_2^2+\alpha \lVert w\rVert_2^2$  
s.t.$w\in \Sigma$  


下面把这个最优化问题转化为二次规划问题
### 1. 损失函数部分
损失函数是 $J=(\hat Y-Y)^T(\hat Y-Y)+\alpha w^Tw$

先看第一项：
$(\hat Y-Y)^T(\hat Y-Y)$
$=\hat Y^T \hat Y-\hat Y^TY-Y^T\hat Y+Y^TY$（矩阵乘积结合律）
$=\hat Y^T \hat Y-\hat Y^TY-\hat Y^T Y+Y^TY$（因为是1*1矩阵，所以可以随意转置）
$=\hat Y^T \hat Y-2 Y^T \hat Y+Y^TY$

再看第二项：
$\alpha w^Tw=\alpha w^T I w$（其中$I$表示单位矩阵：对角线全为1的对角阵）

两项相加，并且考虑到 $Y^TY$ 是常数，在最优化中不考虑。  
$J=\hat Y^T \hat Y-2 Y^T \hat Y+\alpha w^T I w$
$=w^TX^TXw-2Y^TXw+\alpha w^T Iw$
$=w^T(X^TX+\alpha I)w -2 (Y^TX)w$
$=2[0.5w^T(X^TX+\alpha I)w -(Y^TX)w]$（这就化为了二次规划的标准形式）


令$p=X^TX+\alpha I,q^T=-Y^Tx$,
得到二次型的标准形式：
$\min\limits_w (1/2)w^T p w+q^Tw$

### 2. 约束部分
约束部分就按照标准形式写就行了，不需要公式转化。

### 3. 代码
```py
alpha=0.1 # l2范数前面的系数。
from cvxopt import matrix, solvers
X, y = matrix(X), matrix(y)

# 最优化目标部分：
I = matrix(np.eye(num_features))
P = X.T * X + alpha * I
q = (-1.0 * y.T * X).T # 因为标准型输入的是q.T，所以还需要一次转置

# 约束部分：(Gw<h)
G = matrix(g).T # 注意一下，这里的g是list，需要转置。如果g是np.array，就不需要。
h = matrix([-0.01] * G.size[0])  # 这里按照类似“小于即可”，“小0.01”等实际需求去自定义
# A,b 等号约束同理

sv = solvers.qp(p, q, G, h)
sv['x'] # 解出系数
```

---

## File: _os/5_备忘与构想/hide_info_more.md

[Binary file]

---

## File: _os/5_备忘与构想/text_watermark_more.md

---
layout: open_source
title: 【改进】文本盲水印
categories: 开源
tag: DevNotes
order: 720
repo_name: text_blind_watermark
---

提供了网页版本、Python版本、Rust版本


在线试用：[https://www.guofei.site/pictures_for_blog/app/text_watermark/v1.html](https://www.guofei.site/pictures_for_blog/app/text_watermark/v1.html)




## 零宽字符选择


字符测试地址（网页）：https://www.guofei.site/pictures_for_blog/app/text_watermark/find_chr.html


测试范围：

|| macbook| windows | iso | 安卓系统 | linux
|--|--|--|--|--|--|
| Chrome | 
| 系统预装的浏览器 | 
| 系统预装的编辑器 | 
| 微信 | 
| office | 
| 其它主流APP ||QQ、抖音、知乎、小红书、B站|
| wps |
| Github readme、代码预览页 |  |






 windows-excel
 - ❌：7F，00AD
 - ✔️：1d，200B，200C，200D，FEFF，2060，202A

 windows-word
 - ❌：1d，7F，00AD，
 - ✔️：200B，200C，200D，FEFF，2060，202A

windows-ppt
- ❌：None
- 正确：1d，7F，200B，200C，200D，FEFF，2060，00AD，202A


windows-chrome
- ❌：1d，7F
- ✔️：其它

windows-edge
- 同 windows-chrome

IE
- 全通过


windows-写字板
- 同 Windows- Chrome

windows-txt编辑器
- 全通过

Windows-钉钉
- 同 Chrome

Windows-微信

Windows-wps

Windows-ppt

Windows-excel



命令行
- macbook-pycharm 命令行
    - ✔️： 1d，202A，FEFE，200E，200F
- macbook-zsh
    - ❌：200B，200C，00AD
    - ✔️： 1d，7F，200D，FEFF，2060，202A，FEFE、2060，200E，200F



字符说明

1. 零宽度空格（Zero Width Space）
代码点: U+200B
名称: ZERO WIDTH SPACE
功能: 允许在文本中插入一个可能的换行点，但不会显示任何可见的空格。常用于需要控制换行但不希望显示空格的位置。
2. 零宽度非连接符（Zero Width Non-Joiner）
代码点: U+200C
名称: ZERO WIDTH NON-JOINER (ZWNJ)
功能: 防止前后字符连接或形成连字，常用于书写需要区分连接性语言（如阿拉伯语、希伯来语）中的字母。
不可用：MacBook 的 Excel
3. 零宽度连接符（Zero Width Joiner）
代码点: U+200D
名称: ZERO WIDTH JOINER (ZWJ)
功能: 指示前后的字符应连接或形成连字，常用于组合字母或生成特定的连字形式。
不可用：Macbook 的 Excel
4. 零宽度无断行空格（Zero Width No-Break Space）
代码点: U+FEFF
名称: ZERO WIDTH NO-BREAK SPACE (ZWNBSP)
功能: 原本用作字节顺序标记（BOM），但也可作为不可见的无需断行的空格使用。注意：在现代 Unicode 中，推荐使用 WORD JOINER (U+2060) 来替代。
5. 左右文本方向控制字符
左至右标记（Left-to-Right Mark, LRM）
代码点: U+200E
名称: LEFT-TO-RIGHT MARK
功能: 指示文本方向为从左到右，常用于混合方向的文本中。
右至左标记（Right-to-Left Mark, RLM）
不可用：Macbook-Excel
6. 方向
代码点: U+200F
名称: RIGHT-TO-LEFT MARK
功能: 指示文本方向为从右到左，常用于混合方向的文本中。
不可用：Macbook-Excel
6. 字符连接格式符（Character Joiner）
代码点: U+2063
名称: INVISIBLE SEPARATOR
功能: 用作不可见的分隔符，通常用于分隔两个字符但不显示任何分隔符。
7. 数学格式字符
线性占位符（Invisible Times）
代码点: U+2062
名称: INVISIBLE TIMES
功能: 用于数学表达式中，作为隐形的乘号。
线性占位符（Invisible Separator）
不可用：Macbook-Excel、MacBook-word
8. 代码点: U+2063
名称: INVISIBLE SEPARATOR
功能: 在数学表达式中用作隐形的分隔符。
不可用：Macbook-Excel、MacBook-word



综合来说，使用 2060、FEFF 是比较好的

---

## File: _os/7_app/github_star_counter.md

---
layout: app
title: github star数量统计
categories: 开源
tag: tools
order: 710
repo_name: star_counter
---


一个统计某个账号下 github 的 star 数量的在线小应用。  

## 试试吧：
输入账号，然后点击`Calculate` 按钮  


<style>
  .blinking {
    animation: blinker 1s linear infinite;
  }

  @keyframes blinker {
    50% { opacity: 0.3; }
  }
</style>

<script src="https://www.guofei.site/star_counter/star_counter.js"></script>


<script>
    function func_1() {
        const output = document.getElementById("star_counter");
        output.classList.add("blinking");
        output.innerHTML = '🌀 Loading...';

        github_id = document.getElementById("user").value;

        setTimeout(() => {
            const result = cal_github_star(github_id);
            output.classList.remove("blinking");
            document.getElementById("star_counter").innerHTML = result;
        }, 100);

    }
</script>


Input github id: 







## Source Code

| language | description | links |
|----------|-------------|-------|
| Javascript | [](https://github.com/guofei9987/star_counter/) | [star_counter](https://github.com/guofei9987/star_counter/) |
| Python | [](https://github.com/guofei9987/github_star_counter/) | [github_star_counter](https://github.com/guofei9987/github_star_counter/) |

---

## File: _os/7_app/life.md

---
layout: app
title: 焦虑放大器
categories: 开源
tag: tools
order: 799
---


<style>
    #myTable {
        border-collapse: collapse;
    }

    #myTable td {
        width: 20px;
        height: 20px;
        border: 1px solid #fff;
        position: relative;
    }

    #myTable td.past {
        background-color:#D2B48C;
    }

    #myTable td.future {
        background-color:#4CAF50;
    }

    #myTable td.old {
        background-color:#C0C0C0;
    }

    #myTable td.now {
        animation: smooth-blink 500ms linear infinite;
    }

    #myTable td.event::after {
        content: attr(data-label);
        position: absolute;
        top: -25px;
        left: 50%;
        transform: translateX(-50%);
        background: rgba(0, 0, 0, 0.7);
        color: #fff;
        font-size: 10px;
        padding: 2px 5px;
        border-radius: 3px;
        white-space: nowrap;
    }

    @keyframes smooth-blink {
        0%, 100% { background-color: #D2B48C; }
        50% { background-color: #4CAF50; }
    }

    #explain td{
        border: 1px solid #fff;
    }

    .progress-bar {
        width: 400px;
        background-color: #f5f5f5;
        border: 1px solid #ccc;
        border-radius: 10px;
        overflow: hidden;
        background-color: #4CAF50;
        position: relative;
    }

    .progress-bar-inner {
        height: 100%;
        background-color: #D2B48C;
    }

    .bar1{
        height: 25px;
    }

    .bar2{
        height: 75px;
    }

    #life-bar {
        position: relative;
        display: flex;
        align-items: center;
    }

    .time-stats {
        position: absolute;
        width: 200px;
        padding: 0 10px;
        font-size: 12px;
        line-height: 1.3;
    }

    .left-stats {
        text-align: left;
        left: 0;
    }

    .right-stats {
        text-align: right;
        right: 0;
    }

</style>





    






    
    
    






|  | 已经过了的时间 |
| --- | --- |
|  | 65岁之前的余生 |
|  | 65岁之后的余生 |



<script>
const birthDay = new Date("1988-02-16");
const life_span = 80;
const endDay = new Date(birthDay.getFullYear() + life_span, birthDay.getMonth(), birthDay.getDate());
const num_cols = 20;
const num_rows = 20;
const table = document.getElementById("myTable");
const currentDate = new Date();
const pastSeconds = (currentDate.getTime() - birthDay.getTime()) / 1000;
const currentCellIdx = Math.floor(pastSeconds / 3600 / 24 / 365 / (life_span / num_cols / num_rows));

// 人生关键节点（按0.2年一个格子）
const events = {
    [Math.floor((18 / 80) * 400)]: "🎓18岁",
    [Math.floor((27 / 80) * 400)]: "👶工作-中体彩",
    [Math.floor((30 / 80) * 400)]: "💼工作-京东",
    [Math.floor((32.2 / 80) * 400)]: "🔥工作-蚂蚁"
};

for (let i = 0; i < num_rows; i++) {
    const newRow = table.insertRow();
    for (let j = 0; j < num_cols; j++) {
        const newCell = newRow.insertCell();
        const newCellIdx = i * num_cols + j;

        if (newCellIdx < currentCellIdx) {
            newCell.classList.add("past");
        } else if (newCellIdx === currentCellIdx) {
            newCell.classList.add("now");
        } else if (newCellIdx <= 65 * 5) {
            newCell.classList.add("future");
        } else {
            newCell.classList.add("old");
        }

        if (events[newCellIdx]) {
            newCell.classList.add("event");
            newCell.setAttribute("data-label", events[newCellIdx]);
        }
    }
}

function tickDay(){
    const now = new Date();
    const startOfDay = new Date(now);
    startOfDay.setHours(0, 0, 0, 0);
    const percentLeft = (now - startOfDay) / (24 * 60 * 60 * 1000) * 100;
    const progressBar = document.getElementById("today-bar-inner");
    progressBar.style.width = percentLeft + "%";
    progressBar.innerText = "今日已用" + percentLeft.toFixed(4) + '%';
}

function tickLife() {
    const leftStats = document.querySelector('.left-stats');
    const rightStats = document.querySelector('.right-stats');
    const currentDate = new Date();
    const daysPassed = (currentDate - birthDay) / (1000 * 3600 * 24);
    const daysRemaining = (endDay - currentDate) / (1000 * 3600 * 24);

    leftStats.innerHTML = `时光已去：${(daysPassed / 365).toFixed(8)} 年${(daysPassed / 12).toFixed(8)} 月${daysPassed.toFixed(8)} 天`;
    rightStats.innerHTML = `余生还剩：${(daysRemaining / 365).toFixed(8)} 年${(daysRemaining / 12).toFixed(8)} 月${daysRemaining.toFixed(8)} 天`;

    const percentLeft = daysPassed / (daysPassed + daysRemaining) * 100;
    const progressBar = document.getElementById("life-bar-inner");
    progressBar.style.width = percentLeft + "%";
}

setInterval(tickLife, 50);
setInterval(tickDay, 50);
</script>

---

## File: _os/7_app/screen_drop.md

---
layout: app
title: 二维码传文件
categories: 开源
tag: tools
order: 709
---

---

## File: _os/开源文档/amazing_title.md

---
layout: open_source
title: 震惊体标题生成器
categories: 开源
tag: tools
order: 821
repo_name: vulgar_language_generator
---

## demo

<script src="https://www.guofei.site/vulgar_language_generator/amazing_title/amazing_title.js"></script>
<script>
function myFunction1() {
    document.getElementById("amazing_tile").innerHTML += amazing_title_1();
}

function myFunction2() {
    document.getElementById("amazing_tile").innerHTML += amazing_title_2();
}
</script>
带主语的震惊体
不带主语的震惊体




## 如何部署到你的网站上

```html
<script src="http://www.guofei.site/vulgar_language_generator/amazing_title/amazing_title.js"></script>
<script>
function myFunction1() {
    document.getElementById("amazing_tile").innerHTML += amazing_title_1();
}

function myFunction2() {
    document.getElementById("amazing_tile").innerHTML += amazing_title_2();
}
</script>
<button type="button" onclick="myFunction1()">带主语的震惊体</button>
<button type="button" onclick="myFunction2()">不带主语的震惊体</button>
<p id="amazing_tile"></p>
```


## 源码和原理

[源码](https://github.com/guofei9987/vulgar_language_generator)  
[](https://github.com/guofei9987/vulgar_language_generator/stargazers)
[](https://github.com/guofei9987/vulgar_language_generator/network/members)

原理其实就是三段短语随机拼接而成，分两种罗列如下：
### 1. 带主语的震惊体
part1：
```
震惊！, 禽兽！, 太不是人了！, 重大揭秘！, 大惊失色！, 惊天内幕！, 居然是这样！, 数万人围观！, 你不得不信，, 速度进！, 有本事你别看！
```

part2：
```
竟深夜推倒六个少女，, 久吃不胖的三个秘诀，, 隐藏多年的男友终于出现了！, 二十年单身的终极原因，, 第一次做这种事就被发现了，, 不会告诉你的择偶标准，, 账户余额竟高达亿余！, 竟喊话十亿国人，, 最想删除的照片原来是这张！, 居然有女朋友了！不是充气的！, 的真实身份可能是..., 竟在小树林干不可描述的事…, 曾与多名衣衫不整的少女共处一室！
```

part3：
```
有图有真相！, 你一定要看！, 韩红听了都想打人 ..., 不转不是地大人！, 之前都被骗了！, 不能再瞒着大家了！, 看完我崩溃了..., 男人看完都沉默了..., 赶紧分享！, 简直不敢相信！, 不轻易分享出来！
```

公式就是 part1+张三+part2+part3，随机选取


### 2. 不带主语的震惊体
#### part1:
```
"全世界80万人疯传", "你不可不知的", "立刻分享，", "天啊！这居然是", "我看了3遍都不相信", "38个", "21个", "看完眼眶湿湿的", "我怎么没早点发现这", "让你大惊失色", "15个",
"12个你一定得知道", "不看后悔", "超过6万人已经发现", "你一定没看过的", "这太神了！", "史上最", "整整流传两世纪", "45个", "10个影响你一生", "让专家跌破眼镜", "17个",
"每个人都忽略这", "25个你一定会爱上", "这是我听过最奇怪的", "14个让人笑翻", "胆小的人别看", "3分钟看完这", "20岁以前必看", "全中国都在看，", "杜拉克教我的", "前所未闻", "深度揭秘", "史上最强"
```


#### part2：

```
"不可思议的事实，", "致富秘诀，", "劲爆的惊险画面，", "看到赚到的不传秘方，", "绝无仅有的超自然现象，", "值得收藏一辈子的秘密，", "影响你全家的健康行为，", "残酷的人生领悟，",
"首次解禁，", "轰动全球的照片，", "不可不看的影片，", "不可告人的秘密", "改变全人类的超酷行为，", "家庭必备的神圣之物，", "骇人听闻的灵异现象，", "不轻易透露的超强技巧，", "超搞笑的视频，", "立刻就必须做的事，", "从未被揭发的新闻，",
"啧啧称奇的绝妙发明，", "让人傻眼的画面，", "可爱到爆的小动物，", "珍贵的历史宝物，", "让全球男性陷入疯狂的影片，", "诡异的视觉陷阱，", "全人类的存亡关键，", "操纵人心的秘密，",
"星座小秘密，", "致癌的日常食品，", "哈佛大学最受欢迎的课程，", "全球禁播的MV，", "医师养生法，", "最难以置信的骗术，"
​```


#### part3:
```
"看完后我惊呆了！", "真的把我吓傻了！", "全世界都崩溃！", "我的下巴都掉了！", "看完对人生对然开悟了！", "全场的观众都崩溃了！", "尤其是第7个！", "特别是最后一个！", "我不敢相信第3个！", "你一定要看第5个！", "完全颠覆你的想象！", "不敢相信！", "第4个太夸张了！", "第6个不是真的吧？", "第8个太疯狂了！", "他是怎么做到的？", "不分享还是人吗？", "第2个太惊人了！", "这真的让我看不下去了…", "你一定要看到最后！", "我的心融化了…", "把所有人都吓坏了！", "第9个真的很神奇！", "真是太天才了！", "我从椅子上跳了起来！", "第5秒我就流泪了…", "是女人一定要看！", "我忍不住一直看下去…", "请看完！", "其他简直弱爆了！", "强烈推荐！", "有图有真相！"
```

公式就是 part1 + part2 + part3，随机选取

---

## File: _os/开源文档/fourier_artist.md

[Binary file]

---

## File: _os/开源文档/pylshash.md

[Binary file]

---

## File: _os/开源文档/vulgar_poet.md

[Binary file]

---

## File: _posts/0_合集/2013-01-05-log.md

---
layout: post_pure
title: 【归档】建站日志(6篇)
categories: 合集
tags:
keywords:
name: 建站日志
permalink: /:title:output_ext
order: 19001
---

{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2015-09-30-interesting.md

---
layout: post_pure
title: 【归档】趣文(17篇)
categories: 合集
tags:
keywords:
name: 趣文
permalink: /:title:output_ext
order: 19003
---


{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2016-04-23-frontend.md

---
layout: post_pure
title: 【合集】前端开发(6篇)
categories: 合集
tags: 0x10_计算机基础
keywords:
name: 前端
permalink: /:title:output_ext
order: 19008
---


{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2016-04-23-python.md

---
layout: post_pure
title: 【合集】Python(18篇)
categories: 合集
tags: 0x10_计算机基础
keywords:
name: python
permalink: /:title:output_ext
order: 19008
---


{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2016-08-21-pandas.md

---
layout: post_pure
title: 【合集】pandas(9篇)
categories: 合集
tags:
keywords:
name: pandas
permalink: /:title:output_ext
order: 19001
---

{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2020-10-01-matlab.md

---
layout: post_pure
title: 【合集】Matlab(18篇)
categories: 合集
tags: 0x10_计算机基础
keywords:
name: Matlab
permalink: /:title:output_ext
order: 19005
---

{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2021-09-12-hybrid.md

---
layout: post
title: Java、Python、C混合编程
categories: 合集
tags:
keywords:
order: 173
---

## 编译后的文件

window：
- `.dll` 动态
- `.lib` 静态

Linux
- `.o` 对应 Windows上的 `.obj`
- `.a` 多个 `.o` 的合并
- `.so` 对应 Windows上的 `.dll`

MacOS
- 动态 `.dylib`
- 静态 `.a`

## 【ctypes】python 调 C 编译后的动态库

优缺点：
- 优点：无需处理 Python 版本
- 缺点：不能多线程


步骤
1. 写 c 文件， 保存为 `file.c`
```c
#include<stdio.h>
void add()
{
int sum=0;
for(int i=0;i<1000;i++)
sum+=i;
printf("sum:%d\n",sum);
}
```
2. 把 `file.c` 文件编译为 `file.so`：`gcc file.c -shared -o file.so`
3. 在Python中导入和使用 `.so`
```python
from ctypes import cdll
clib = cdll.LoadLibrary("./file.so")
clib.add()
```


如何同时支持 windows/Linux : https://www.bilibili.com/video/BV17y4y1W7BY?p=3


### 数据类型


| ctypes 类型  | C 类型                                 | Python 数据类型   |
|--------------|----------------------------------------|-------------------|
| c_bool       | _Bool                                  | bool (1)          |
| c_char       | char                                   | 单字符字节串对象  |
| c_wchar      | wchar_t                                | 单字符字符串      |
| c_byte       | char                                   | int               |
| c_ubyte      | unsigned char                          | int               |
| c_short      | short                                  | int               |
| c_ushort     | unsigned short                         | int               |
| c_int        | int                                    | int               |
| c_uint       | unsigned int                           | int               |
| c_long       | long                                   | int               |
| c_ulong      | unsigned long                          | int               |
| c_longlong   | __int64 或 long long                   | int               |
| c_ulonglong  | unsigned __int64 或 unsigned long long | int               |
| c_size_t     | size_t                                 | int               |
| c_ssize_t    | ssize_t 或 Py_ssize_t                  | int               |
| c_float      | float                                  | float             |
| c_double     | double                                 | float             |
| c_longdouble | long double                            | float             |
| c_char_p     | char * (NUL terminated)                | 字节串对象或 None |
| c_wchar_p    | wchar_t * (NUL terminated)             | 字符串或 None     |
| c_void_p     | void *                                 | int 或 None       |


例子：

```c
// c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int my_c_fun(int x1, float x2, char *x3 // 指向字符串的指针
        , int *x4 // 指向 array 的指针
        , char **x5 //指向 array of string 的指针
        , int *x6 // 指向一个 int 类型的指针，在函数中修改它指向的值
        , char *x7 // 指向一个 string 类型的指针，在函数中修改它指向的值
) {
    printf("Get input :\n");
    printf("x1 = %d\n", x1);
    printf("x2 = %f\n", x2);
    printf("x3 = %s\n", x3);

    printf("x4 = ");
    for (int i = 0; i < 5; i++) {
        printf(" %d", x4[i]);
    }
    printf("\n");

    printf("x5 = ");
    for (int i = 0; i < 3; i++) {
        printf(" %s", x5[i]);
    }
    printf("\n");

    // 修改指针指向的值
    *x6 = 8;
    printf("%s\n", x7);
    strcpy(x7, "你好");

    return x1 + (int) x2 + (int) strlen(x3) + x4[0];
}


// python

from ctypes import cdll

clib = cdll.LoadLibrary("./file.so")
import ctypes

clib.my_c_fun.argtypes = [
    ctypes.c_int,
    ctypes.c_float,
    ctypes.c_char_p,
    ctypes.POINTER(ctypes.c_int),
    ctypes.POINTER(ctypes.c_char_p),
    ctypes.POINTER(ctypes.c_int),
    ctypes.c_char_p,
]

clib.my_c_fun.restype = ctypes.c_int

int_lst = [1, 2, 3, 4, 5]
x4 = (ctypes.c_int * len(int_lst))()
x4[:] = int_lst

# Pass a list of string
str_lst = ["hello", "world", "!", "\0"]
x5 = (ctypes.c_char_p * len(str_lst))()
x5[:] = [i.encode("utf-8") for i in str_lst]

x6 = ctypes.c_int()
x7 = ctypes.create_string_buffer(100)
x7.value = "nihao".encode('utf-8')  # 也先可以赋予一个值

res = clib.my_c_fun(
    1  # 默认 int 类型，无需转化
    , 1.2  # 传入 float
    , "hello".encode('utf-8')  # 传入字符串 char *
    , x4
    , x5
    , ctypes.byref(x6)
    , x7
)

print('res:', res)
print("x6:", x6.value)
print("x7:", x7.value.decode('utf-8'))
```







```c
int my_c_fun(int x1, float x2, char *x3, int *x4, char **x5) {
    printf("Get input :\n");
    printf("x1 = %d\n", x1);
    printf("x2 = %f\n", x2);
    printf("x3 = %s\n", x3);

    printf("x4 = ");
    for (int i = 0; i < 5; i++) {
        printf(" %d", x4[i]);
    }
    printf("\n");

    printf("x5 = ");
    for (int i = 0; i < 3; i++) {
        printf(" %s", x5[i]);
    }
    printf("\n");


    return x1 + (int) x2 + (int) strlen(x3) + x4[0];
}

char *my_c_fun2() {
    char *p = malloc(20);
    strcpy(p, "hello");
    return p;
}


int *my_c_fun3() {
    int *p = malloc(20 * sizeof(int));
    for (int i = 0; i < 20; i++) {
        p[i] = 30 - i;
    }
    return p;
}

// my_c_fun3 对应的内存应当及时 free。如果这里 free 了，python脚本里面的返回值也就free了
void my_c_fun3_free(int *p) {
    free(p);
}


char **my_c_fun4() {
    char **p = malloc(5 * sizeof(char *));
    p[0] = "hello";
    p[1] = "world";
    return p;
}
```

用 python 去调用上面那个 C

```python
import ctypes

clib = ctypes.cdll.LoadLibrary("/Users/guofei/c_algorithm/main.o")

# Pass a list of int
int_lst = [1, 2, 3, 4, 5]
int_arr = (ctypes.c_int * len(int_lst))()
int_arr[:] = int_lst

# Pass a list of string
str_lst = ["hello", "world", "!", "\0"]
str_arr = (ctypes.c_char_p * len(str_lst))()
str_arr[:] = [i.encode("utf-8") for i in str_lst]

x = clib.my_c_fun(1  # 默认 int 类型，无需转化
                  , ctypes.c_float(1.2)  # 传入 float
                  , ctypes.c_char_p("hello".encode('utf-8'))  # 传入字符串 char *
                  , int_arr # 传入 int *
                  , str_arr # 传入 char **
                  )
print('res:', x)

# 返回一个字符串
clib.my_c_fun2.restype = ctypes.c_char_p
x = clib.my_c_fun2()
print('res:', x)

# 返回 list of int
clib.my_c_fun3.restype = ctypes.POINTER(ctypes.c_int * 20)
x = clib.my_c_fun3()
print('res:', list(x.contents))

# 注意：用完记得 free，free之后，x 的内容也变了（内存被释放了）
clib.my_c_fun3_free(x)

# 返回 list of string
clib.my_c_fun4.restype = ctypes.POINTER(ctypes.c_char_p * 2)
x = clib.my_c_fun4()
print('res:', list(x.contents))

# 这个不知道什么用
# clib.my_c_fun2.argtypes = (ctypes.c_char_p,)
```

## Python 调 Rust

[Rust混合编程](https://www.guofei.site/2022/08/28/rust2.html#混合编程)


https://www.guofei.site/2022/08/28/rust2.html#混合编程

## 【JPype1】Python 调 Java

安装
```bash
pip install JPype1
```

示例java脚本


```java
package com.guofei9987.learn_java;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class JavaClass {

    public static String tstStatic(String a) {
        return "调用了静态方法，入参：" + a;
    }

    public List<String> my_java_fun(int x1, String x2, List<Integer> x3, List<String> x4) {
        System.out.println("x1 = " + x1);
        System.out.println("x2 = " + x2);
        System.out.println("x3 = " + x3);
        System.out.println("x4 = " + x4);

        ArrayList<String> res = new ArrayList<String>(Arrays.asList("" + x1, x2)) {
        };
        res.addAll(x4);
        return res;
    }

    public String my_java_fun(int a) {
        return "调用了重载的方法，入参：" + a;
    }
}
```


Python 调用 Java
```python
import jpype
import os

jarpath = os.path.join(os.path.abspath("."), "/Users/guofei9987/learn_java/target/learn_java-1.0-SNAPSHOT.jar")
jvmPath = jpype.getDefaultJVMPath()
jpype.startJVM(jvmPath, "-ea", "-Djava.class.path=%s" % (jarpath))

# step1：加载类
javaClass = jpype.JClass("com.guofei9987.learn_java.JavaClass")

# step2：实例化java对象
javaInstance = javaClass()

# step3：调用java方法
javaClass.tstStatic("Hello")
# >>>'调用了静态方法，入参：Hello'


output = javaInstance.my_java_fun(
    1  # 传入 int
    , "hello"  # 传入 String
    , jpype.java.util.ArrayList([1, 2, 3])  # 传入 ArrayList<int>
    , jpype.java.util.ArrayList(["hello", "world"]))  # 传入 ArrayList<String>
print(list(output))

output2 = javaInstance.my_java_fun(1)
print(output2)

# step4：关闭jvm
jpype.shutdownJVM()
```


关于变量类型
- java.lang.String
    - 把 java.lang.String 转为 Python 的 str 类型：`str(java_string)`
    - 把 Python 的 str 转为 java.lang.String：`jpype.JClass("java.lang.String")("Hello, World!")`




## 【PMML】Java调 sklearn 算法模型
### 描述

Python 训练算法模型，保存为 PMML 文件。然后 Java 调用 PMML 文件做预测，这样线上就变成纯 JAVA 项目了。


相关项目
- Python 端的项目：https://github.com/jpmml/sklearn2pmml
- Java端 项目：https://github.com/jpmml/jpmml-model  
- 对应的库：https://repo1.maven.org/maven2/org/jpmml/


安装
- Python
```sh
pip install scikit-learn==0.24.2
pip install sklearn2pmml==0.74.4
```
- JAVA `pom.xml` 文件


```xml
<dependency>
    <groupId>org.jpmml</groupId>
    <artifactId>pmml-evaluator</artifactId>
    <version>1.5.9</version>
</dependency>
```







### 使用



python 训练模型
```python
from sklearn import tree
from sklearn.datasets import load_iris
from sklearn2pmml.pipeline import PMMLPipeline
from sklearn2pmml import sklearn2pmml

iris = load_iris()
X, y = iris.data, iris.target
pipeline = PMMLPipeline([("classifier", tree.DecisionTreeClassifier())])  # 用决策树分类
pipeline.fit(X, y)
sklearn2pmml(pipeline, "iris.pmml", with_repr=True)
```


java 调用模型做预测
```java
package com.alipay.tianqian;

import org.dmg.pmml.FieldName;
import org.jpmml.evaluator.*;
import org.xml.sax.SAXException;

import javax.xml.bind.JAXBException;
import java.io.*;
import java.util.*;


public class TestPmml {

    public static void main(String[] args) throws JAXBException, SAXException, IOException {
        TestPmml obj = new TestPmml();

        Evaluator model = new LoadingModelEvaluatorBuilder()
                .load(new File("src/iris.pmml"))
                .build();

        List<Map<String, Object>> inputs = new ArrayList<>();
        inputs.add(obj.getRawMap(5.1, 3.5, 1.4, 0.2));
        inputs.add(obj.getRawMap(4.9, 3, 1.5, 4));
        for (Map<String, Object> input : inputs) {
            Map<String, Object> output = obj.predict(model, input);
            System.out.println("X=" + input + " -> y=" + output.get("y"));
        }
    }



    private Map<String, Object> getRawMap(Object a, Object b, Object c, Object d) {
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("x1", a);
        data.put("x2", b);
        data.put("x3", c);
        data.put("x4", d);
        return data;
    }

    /**
     * 运行模型得到结果。
     */
    private Map<String, Object> predict(Evaluator evaluator, Map<String, Object> data) {
        Map<FieldName, FieldValue> input = getFieldMap(evaluator, data);
        Map<String, Object> output = evaluate(evaluator, input);
        return output;
    }

    /**
     * 把原始输入转换成PMML格式的输入。
     */
    private Map<FieldName, FieldValue> getFieldMap(Evaluator evaluator, Map<String, Object> input) {
        List<InputField> inputFields = evaluator.getInputFields();
        Map<FieldName, FieldValue> map = new LinkedHashMap<FieldName, FieldValue>();
        for (InputField field : inputFields) {
            FieldName fieldName = field.getName();
            Object rawValue = input.get(fieldName.getValue());
            FieldValue value = field.prepare(rawValue);
            map.put(fieldName, value);
        }
        return map;
    }

    /**
     * 运行模型得到结果。
     */
    private Map<String, Object> evaluate(Evaluator evaluator, Map<FieldName, FieldValue> input) {
        Map<FieldName, ?> results = evaluator.evaluate(input);
        List<TargetField> targetFields = evaluator.getTargetFields();
        Map<String, Object> output = new LinkedHashMap<String, Object>();
        for (TargetField field : targetFields) {
            FieldName fieldName = field.getName();
            Object value = results.get(fieldName);
            if (value instanceof Computable) {
                Computable computable = (Computable) value;
                value = computable.getResult();
            }
            output.put(fieldName.getValue(), value);
        }
        return output;
    }
}
```

---

## File: _posts/0_合集/2022-01-11-old_ann.md

---
layout: post_pure
title: 【归档】上世纪神经网络(10篇)
categories: 合集
tags: 
keywords:
name: old_ann
permalink: /:title:output_ext
order: 19008
---


{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2022-03-05-tensorflow.md

---
layout: post_pure
title: 【归档】TensorFlow(14篇)
categories: 合集
tags: 0x11_算法平台
keywords:
name: TensorFlow
permalink: /:title:output_ext
order: 19007
---

{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2022-06-10-c.md

---
layout: post_pure
title: 【合集】C/C++(9篇)
categories: 合集
tags: 0x10_计算机基础
keywords:
name: C
permalink: /:title:output_ext
order: 19007
---

{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2022-12-10-rust.md

---
layout: post_pure
title: 【合集】Rust(8篇)
categories: 合集
tags: 0x10_计算机基础
keywords:
name: rust
permalink: /:title:output_ext
order: 19008
---


{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2023-09-09-java.md

---
layout: post_pure
title: 【合集】Java(4篇)
categories: 合集
tags: 0x10_计算机基础
keywords:
name: Java
permalink: /:title:output_ext
order: 19007
---


{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2024-04-28-torch.md

---
layout: post_pure
title: 【合集】Pytorch(11篇)
categories: 合集
tags: 0x11_算法平台
keywords:
name: torch
permalink: /:title:output_ext
order: 19008
---


{% assign category_name = page.name %}

共 {{site.categories[category_name].size}} 篇

{% for post in site.categories[category_name] %}
  <li>
    {{ post.date | date: "%Y年-%m月-%d日" }} &raquo;
    [{{post.title}}]({{ post.url }})
  </li>
{% endfor %}

---

## File: _posts/0_合集/2_6_pytorch/2019-12-07-torch.md

---
layout: post
title: 🔥【pytorch】基本语法
categories: torch
tags: 
keywords:
order: 261
---

可以参考 [【pytorch】建立模型](https://www.guofei.site/2019/12/14/torch_model.html)，提供了一个完整的最小神经网络构建过程，本文会对每个步骤做拆解和详细描述：

1. 安装与配置。介绍安装、使用GPU等知识
2. Tensor 的各种用法示例，包括各种函数、矩阵、统计运算
3. 建立模型，包括
    - 网络层、激活函数、卷积层 等
    - 模型的 save/load
    - 正则化
4. 定义损失函数
5. 定义优化器
6. 训练



## 安装与配置

看CUDA版本
```
nvidia-smi
```

[官网上的安装教程](https://pytorch.org/get-started/locally/)


2.x的重大更新
```python
# 编译，极大提升性能
model = torch.compile(model)

# torch.distributed、FSDP、DTensor 等能力持续改进

# Transformer 常用算子（如 attention 相关）和算子实现上持续优化
```

**GPU**
```python
import torch
from torch import nn

torch.cuda.is_available() # 返回 True/False 表示GPU是否可用
torch.cuda.device_count() # 可用的GPU数量
```

**使用GPU**
```python
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 'cuda' 等同于 'cuda:X',其中X是torch.cuda.current_device()
mytensor = my_tensor.to(device) # tensor
model = model.to(device) # 返回的 model 和输入的 model 是同一个对象，这个行为与下面的 tensor 不同

print(mytensor.device)
# 看模型在哪个设备上：(原理是看第一个参数所在的位置)
print(next(model.parameters()).device)
```

### 并行

```python
# torch 默认不会做多显卡计算，用这个
model = nn.DataParallel(model)
# 目前替换：nn.parallel.DistributedDataParallel

# 设定这个之后，CPU占用会极大提高
torch.set_num_threads(num_physical_cores/num_workers)

# 加载并行
DataLoader(..., num_workers=args.nThreads)
```

- [性能相关的其它资料] https://zhuanlan.zhihu.com/p/69250939



## Tensor

**新建**
```python
torch.empty(5, 3) 
torch.ones(3, 3)
torch.ones_like(...)
torch.zeros(5, 3, dtype=torch.long)
torch.eye(5)

torch.arange(start=0, end=8, step=2) # 含头不含尾
torch.linspace(start=0, end=9, steps=5) # 均匀的取5个值，含头含尾


# 随机生成
torch.manual_seed(2)         # 设置种子
print(torch.initial_seed())  # 查看种子
torch.rand(5, 3)             # 均匀分布 0～1
torch.randn(5, 3)            # 标准正态分布
torch.randn_like(x, dtype=torch.float)


# 从其它数据新建
torch.tensor([[5.5, 3],[2,3]], dtype=torch.float32)
torch.from_numpy(np.ones((5,5))) 

# 说明：
# 1. 全部可以有入参 device=device，或者 device='cuda:0'
# 2. 全部可以用 dtype=torch.float32 指定数据类型，数据类型如下
# 3. 要在同一个 device 上才可以运行
```

**device**

```python
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# device 还可以是字符串: device = 'cpu' # device = 'cuda'

# 在 CPU 上生成，然后转到 GPU
x = torch.randn(4, 4).to(device)
# 在 GPU 生成，然后转到 CPU
x = torch.randn(4, 4, device=device).cpu()
# 也可以用 to(device) 转 CPU

# 说明：转换设备时发生数据复制
```



**数据类型转换**
```python
x.int()
x.long()
x.float()
x.bool()
x.char() # int8 类型
x.double()

# 有这些类型（还有很多）
torch.bool
torch.int
torch.short
torch.uint8 # 这个是 ByteTensor
torch.int
torch.int8
torch.int16
torch.int32
torch.long
torch.float
torch.float16
torch.float32
torch.float64
torch.double
torch.complex32
torch.complex64
```


### 基本运算
```python
# 四舍五入
a.round()
a.fix()
a.floor()


a + b
a * b    # 矩阵元素积
a @ b    # 矩阵积
a += 1

# 可以指定输出到哪个变量
result = torch.empty(5, 3)
torch.add(a, b, out=result)


# 大多数运算符后面可以加个下划线，表示替换运算
# 替换加
y.add_(x) # 这个会把加法的结果赋值给y
# 如 x.copy_(y), x.t_()

# 这些运算也可以不用符号，而是用函数表示:
a.matmul(b)
```



取数
```python
a.size() # torch.Size([5, 3])
a.numel() # 共多少个元素

# index 和 Numpy 一样
a[:, 1]

# 获取某一行
a.select(dim=1,index=2) # 获取按照 dim 计算的 第 index 组。
# 例子的 dim=1 表示获取的是列，index=2 表示获取第 2 列


# tensor 转其它格式
a.numpy() # 转 np.array
a.tolist() # 转 list

# 转 Python 数字，只有单个元素的时候可以用
a[0][0].item()

# 注意一个特性: 共享内存
x = torch.ones(2)
y = x.numpy()
x += 1
print(x, y)
# 打印：tensor([2., 2.]) [2. 2.]

# 值得一提，反过来也是这个特性
a = np.ones(5)
b = torch.from_numpy(a)
a += 1
print(a, b)
# [2. 2.] tensor([2., 2.])
```

reshape
```python
# reshape 也可以做下面这些事，但不能reshape到1维（？不知道为什么要这么设计）

a = torch.randn(4, 4)
a.reshape(2, -1)
a.reshape(-1)
```



### 数学运算

```python
a.sqrt()
a.square()
a.exp()

# 指数运算
a.pow(-1.0)
a.pow(2.0)

a.cos()
a.cosh()
a.acos()
a.acosh()
a.arccos()
a.arccosh()
```


**linalg**
```python
from torch import linalg

a = torch.rand(5, 5)


U, S, Vh = linalg.svd(a)
# full_matrices=False，可以提高性能

# 只返回特征值：
linalg.svdvals(a)

e_val, e_vec = linalg.eig(a)
linalg.eigvals(a)


# linalg 还有很多方法，例如：
linalg.norm
linalg.qr
```



矩阵操作
```py
d = a.diagonal()           # 取出对角线
a1 = torch.diag_embed(d)   # 还原为对角矩阵

a.flip(dims=(0,)) # 按照 dims 确定的维度翻转

a.t() # 转秩


a.tril(k=0) # 下三角矩阵
a.triu(k=0) # 上三角矩阵

# cat
a = torch.rand(3, 2)
b = torch.rand(3, 2)

torch.cat([a, b], dim=0)

# 分割
a = torch.arange(0,12,step=1).reshape(2,6)
a.chunk(chunks=3, dim=1) # 尽量均匀分为三份
# 分为3份，大小分别是 1，3，2
torch.split(x, split_size_or_sections=(1, 3, 2), dim=1)
# 按 dim=1 分为3份，其大小分别为 1, 3, 2
```

where

```python
torch.where(x1 > 0.5, x1, x2)
torch.clip(x1, min=0.4, max=0.6)
```



**按位运算**
```python
# dtype 必须是 int 类型，最好是 uint8
x1 = torch.tensor([1, 2, 3], dtype=torch.uint8)
x2 = torch.tensor([1, 1, 1], dtype=torch.uint8)


x1 & x2  # 按位与
x1 | x2  # 按位或
~x1  # 按位非
x1 ^ x2  # 按位异或
# 以上对应的运算符为：x1.bitwise_or(x2) 等类似的东西

x1 << 1  # 移位运算
# x1.bitwise_left_shift(1)
```

**逻辑运算**
```python
# 0 转为 False，别的数字都转为 True
x1 = torch.tensor([-0.9, 0, True, False], dtype=torch.bool)

# >、<、==、 >=、 <= 都可以
x2 = torch.rand(size=(4,)) < 0.5

# 逻辑与、或、异或、非
x1 & x2
x1 | x2
x1 ^ x2
~x1

# 其它方式：
# x1.logical_and(x2)
# x1.logical_or(x2)
# x1.logical_xor(x2)
# x1.logical_xor_(x2)
# x1.logical_not()
# x1.logical_not_()
```



### 统计类运算

```py
a.mean()
a.mean(dim=1,keepdim=True)

a.sum()
a.sum(dim=1)

a.max()
values, indices = a.max(dim=1, keepdim=True)

a.min()
a.mode()

values, indices = a.sort(dim=1, descending=False)

a.argmin()
a.argsort()
a.argmax(dim=1, keepdim=True)

a.histc
a.histogram

a.std()

```




## 网络层

```
nn.Linear(16 * 5 * 5, 120)
```


### 激活函数

```python
import torch.nn as nn
import torch.nn.functional as F
# 很多激活函数，在上面两个模块中是等价的，使用上的区别：
# nn 提供的是模块形式，适合放进 nn.Sequential
# F 提供的是函数形式，更灵活，适合条件调用、灵活的场景


# Module 方式
act = nn.ReLU(inplace=False)
y = act(x)

# Functional 方式
y = F.relu(x, inplace=False)
```


主要的激活函数：
- `nn.ReLU` ReLU(Rectifier Linear Unit), $\max(0,x)$ 
- `nn.ReLU6` 是 hard-sigmoid 的变种 $\min(\max(0,x),6)$，移动端/量化友好
- `nn.Sigmoid`  $1/(1+\exp(-x))$，优点是不容易出现极端只，但因为梯度消失问题，已经很少用了
- `nn.Tanh` $\dfrac{e^{2x}-1}{e^{2x}+1}$
- `nn.Softsign` 是符号函数的连续估计$x/(abs(x)+1)$
- `nn.Softplus` 是ReLU的平滑版 $\log(\exp(x)+1)$
- `nn.ELU` ELU(Exponential Linear Unit)  $$\begin{cases} x, & x>0 \\ \alpha\left(e^{x}-1\right), & x\le 0 \end{cases}$$





```python
nn.Softmax(dim=dim)
torch.softmax(x, dim=1)    # 用于图片，对 channel 做 softmax
nn.LogSoftmax()  # 对 softmax 取对数，对应的损失函数是 NLLLoss

# 更现代的写法
nn.CrossEntropyLoss
# 等价于 nn.LogSoftmax + nn.NLLLoss
```






2019年5月22日更新（来自吴恩达的 DeepLearning.ai 课程）：  
- sigmoid: never use, except output layer  
- tanh: pretty much strictly superior then sigmoid  
- ReLU: if you do not know which to choose, always choose ReLU  
- Leaky ReLU： you may try this $max(0.01z,z)$

**激活函数的微分** 
- sigmoid:$g(x)=\dfrac{1}{1+e^{-z}},g'(z)=g(z)(1-g(z))$  
- tanh:$g(x)=\dfrac{e^z-e^{-z}}{e^z+e^{-z}},g'(z)=1-(g(z))^2$  
- ReLU/Leaky RelU： 分段函数，注意0点的情况（但0点不是很重要）


### 卷积相关

```py
import numpy as np
import torch
from torch import nn

conv_1 = nn.Conv2d(
    in_channels=1
    , out_channels=16
    , kernel_size=(5, 5)
    , stride=(1, 1)
    , padding='same'  # 或者 padding=2
)

# 显示卷积核的值
conv_1.weight

# 可以给它赋值
filter_1 = torch.from_numpy(np.ones((16, 1, 5, 5)))
conv_1.weight = torch.nn.Parameter(filter_1)

```

Pool

```python
nn.MaxPool2d(kernel_size=2)


# 还有：
# nn.Conv1d, nn.Conv2d, nn.Conv3d
# nn.MaxPool, nn.MaxPool2d, nn.MaxPool3d
```










## 建立模型

```python
import torch
import torch.nn as nn
import torch.nn.functional as F
from collections import OrderedDict


class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()

        # 方法1：最常用
        self.fc1 = nn.Linear(10, 10)
        # 方法2：动态命名，尽量别用
        self.add_module("fc2", nn.Linear(10, 10))
        # 方法3：
        self.block3 = nn.Sequential(OrderedDict([
            ("conv1", torch.nn.Conv2d(in_channels=1, out_channels=16, kernel_size=(5, 5))),
            ("relu1", nn.ReLU())
        ]))
        # 方法4：
        self.add_module("block4", nn.Sequential(OrderedDict([
            ("conv1", torch.nn.Conv2d(in_channels=1, out_channels=16, kernel_size=(5, 5))),
            ("relu1", nn.ReLU())
        ])))

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        # forward 中不加入就不起作用
        # x = self.block3(x)
        # x = self.block4(x)
        return x


my_net = MyNet()
print(my_net)
```

如何使用模型
```python
x = torch.randn(8, 10)

y = my_net(x)
```


### 保存和载入模型

```python
# 存
torch.save(my_net.state_dict(),'./model.pkh')

my_net1 = MyNet().to(device)
# 读
my_net1.load_state_dict(torch.load('./model.pkh', weights_only=True))
# weights_only 只加载权重，更安全

# 关于 device 的说明：
# 1. state_dict 时，会连同所在设备号一起保存；在 load 时，会 load 到对应的设备上
# 2. 使用 map_location 可以指定 load 到哪个设备上
# 3. my_net1.load_state_dict(xxx) 时，会加载到 my_net1 所在的设备上。无论 load 时这些 tensor 在哪个设备上

# 指定参数 load 到哪个设备上：
device3 = torch.device("cuda:3")
torch.load('model.pkh', map_location=device3, weights_only=True)

# 或者
troch.load('model.pkh', map_location={"cuda:1":"cuda:0"})
```

连同训练状态一起保存，以便断点续训

```python
# 保存
ckpt = {
    "epoch": epoch,
    "model_state": model.state_dict(),
    "optim_state": optimizer.state_dict(),
    # 可选：
    # "sched_state": scheduler.state_dict(),
    # "scaler_state": scaler.state_dict(),   # AMP 用
}
torch.save(ckpt, "ckpt.pth")

# 加载
model = MyNet().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

ckpt = torch.load("ckpt.pth", map_location=device)
model.load_state_dict(ckpt["model_state"])
optimizer.load_state_dict(ckpt["optim_state"])

start_epoch = ckpt["epoch"] + 1
model.train()
for epoch in range(start_epoch, num_epochs):
    ...
```


safetensors: 更快、更安全、更标准的 tensor 保存格式

```python
# pip install safetensors

# 保存
from safetensors.torch import save_file

state = my_net.state_dict()
save_file(state, "model.safetensors")

# 读取
from safetensors.torch import load_file

state = load_file("model.safetensors", device='cuda:1')  # 默认在 CPU，可以指定设备
my_net1 = MyNet()
my_net1.load_state_dict(state)
```



### 训练配置的开启和控制

```python
# 切换到训练模式：开启 Dropout、BatchNorm 等
model.train()

# 切换到评估/推理模式：关闭 Dropout，BatchNorm 用训练时记录的
model.eval()

# 不记录计算图、不计算梯度，用于评估/推理
with torch.no_grad():
    ...
```



关于 `with torch.no_grad():`
```python
x = torch.randn(3, requires_grad=True)
y = x * x
print(y.requires_grad) # True
with torch.no_grad():
    print(y.requires_grad) # True
    y2 = x * x
    print(y2.requires_grad) # False

print(y.requires_grad) # True
print(y2.requires_grad) # False
```
或者使用 `y = x.detach()` 生成的是数据共享内存，但指定不微分的新 Tensor


### AUTOGRAD

**requires_grad** 用来控制其是否产生梯度
```python
# 方法1
x = torch.ones(2, 2, requires_grad=True)
# requires_grad 默认为 False

# 方法2
x = torch.ones(2, 2)
x.requires_grad = True
```


```python
y = x + 2
# y.requires_grad 为 True
# y.grad_fn 非空
```


案例：

```py
y = x + 2
# 只要 x.requires_grad == True，那么对 x 的大多数运算都符合：
# y.requires_grad 为 True
# y.grad_fn 非空
z = y * y * 3
k = z.mean()
# 同上，z.requires_grad 和 k.requires_grad 都是 True
```

- `x.requires_grad` 如果设定为 Ture，后面用到y的变量都会计算梯度
- `y.grad_fn` 是与梯度计算有关的函数


```python
# 求导数
k.backward() # 开始计算梯度
print(x.grad) # 返回梯度值
# 1. 返回 dk/dx_ij，形式是矩阵
# 2. 只会给出叶子的导数。所以 z.grad 没有值。因为计算这个值往往意义不大
# 3. 如果确实需要 z.grad，提前声明 z.retain_grad()

x.is_leaf, y.is_leaf # (True, False)
```

要点：
- `k.backward()` 只能运行一次
- `k.backward(retain_graph=True)` 可以运行多次，但结果为上一次的累加，（会导致内存占用较多？）

开关梯度计算

```python
x = torch.ones(2, 2, requires_grad=True)

# 方法1. 使用 with
with torch.no_grad():
    y = x + 2

print(y.requires_grad)  # False

# 方法2. 使用装饰器
@torch.no_grad()
def func(x):
    return x + 2


y = func(x)
print(y.requires_grad)  # False

# 相反的运算是 torch.enable_grad()，可以嵌入到 no_grad() 代码块里面
# 如果 x 本身没有设置 requires_grad=True，那么即使 enable_grad()，它也不生效

# 方法3. 全局打开/关闭
torch.set_grad_enabled(True)
torch.set_grad_enabled(False)
```


```python
# ???
# 如果 out 是一个 tensor 数据类型的矢量，那么这样
v = torch.tensor([1.0, 2, 3])
y.backward(v)
# ？？？但我没搞清楚这个对应哪个数学公式
```



### 正则化


**l2正则化**

```python
# l2 正则化适合用 AdamW，并且 weight_decay 就是 l2 正则化的参数
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)


# 第二种写法（如果想要更精细控制）：
# l2 正则化建议作用于 bias，因此分两组
weight_p, bias_p = [], []
for name, p in my_net.named_parameters():
    if 'bias' in name:
        bias_p += [p]
    else:
        weight_p += [p]

optimizer = torch.optim.SGD([{'params': weight_p, 'weight_decay': 1e-5},
                             {'params': bias_p, 'weight_decay': 0}],
                            lr=1e-2,
                            momentum=0.9)

# l1 正则化也需要手动写
```



**Dropout** 用来减轻 overfitting
```py
nn.Dropout(p=0.5) # p 是丢弃概率


# 以下会按 channel 丢弃整条 channel：

# 输入 (N, C, L) ，随机把某些 整条通道 C 全部置 0 （该通道上的所有 L 位置为0）
nn.Dropout1d

# 输入(N, C, H, W)，随机把某些 整条通道 C 全部置 0 （该通道的 H×W 全部为 0）。典型用在：2D CNN（图像）
nn.Dropout2d

# 输入 (N, C, D, H, W)：随机把某些 整块通道 C 置 0（该通道的 D×H×W 全为 0）。典型用在：3D CNN（视频、医学影像体数据）
nn.Dropout3d
```




**Batch Normalization**

```py
nn.BatchNorm1d # 针对 2 维或者 3 维，输入是 (N, C), 或者 (N, C, L)
nn.BatchNorm2d # 针对 2 维，输入 (N, C, H, W)
nn.BatchNorm3d # 针对 3 维，输入 (N, C, D, H, W)
# 其中，N 是 batch size


torch.nn.BatchNorm1d(num_features=5, eps=1e-5
                     , momentum=0.1, affine=True, track_running_stats=True, device=None, dtype=None)
# num_features：二维(N, D) 中的 D，BatchNorm2d 中的 C
# eps：防治除0错误
# momentum 动态均值和动态方差所用的动量
# affine 自适应调整 gamma/beta 值，若为 False 则不用它们
# track_running_stats=True 不但追踪当期的均值和方差，还根据之前批次做调整

```

$y = \dfrac{x - \mathrm{E}[x]}{\sqrt{\mathrm{Var}[x] + \epsilon}} * \gamma + \beta$

BN不能紧跟着dropout，否则会抖动严重


## 损失函数


1. 交叉熵，适用于分类，$H(p,q)=-\sum p(x)\log q(x)$
```py
criterion = nn.CrossEntropyLoss()
nn.CrossEntropyLoss(weight)  # 加权交叉熵，针对类别数量不均衡的情况
```
2. MSE，适用于回归，$MSE(y,\hat y)=1/n \sum (y-\hat y)^2$
```py
criterion = nn.MSELoss()
criterion = torch.nn.L1Loss() # 这个对应的是 MAE，平均绝对误差
```
3. 自定义。例如，预测销量时，多预测一个损失1元，少预测1个损失10元。  
$Loss(y,y')=\sum f(y_i,y_i')$,  
其中，$$f(x,y)=\left\{\begin{array}{ccc}a(x-y)&x>y\\
b(y-x)&x\leq y\end{array}\right.$$
```py
def asym_l1_loss(y_pred, y_true, a=1.0, b=10.0):
    # over: y_pred > y_true
    over = (y_pred - y_true).clamp_min(0.0)
    under = (y_true - y_pred).clamp_min(0.0)
    return (a * over + b * under).mean()
```
4. 多标签二分类任务中的损失函数，每个预测值有 n 个 0/1
```python
nn.BCELoss
nn.BCEWithLogitsLoss
```



## 优化器







### torch中的优化器
```python
optimizer = torch.optim.SGD(my_model.parameters(), lr=learning_rate)
optimizer = torch.optim.Adam(my_model.parameters(),weight_decay =1e-3) # weight_decay 是 L2 penalty
```

适用性
- SGD 对尺度很敏感，因此必须做标准化



### 学习率

学习率衰减
```python
# 等间隔调整
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
# 按步调整
torch.optim.lr_scheduler.MultiStepLR

# 指数衰减 lr * (gamma ** step)
torch.optim.lr_scheduler.ExponentialLR

# 余弦退火，学习率按余弦衰减
torch.optim.lr_scheduler.CosineAnnealingLR

# 指标在近几次没有变化时，调整学习率，最常用
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau \
    (optimizer=optimizer
     , mode='min'
     , factor=0.5  # gamma
     , patience=5  # 监控不再减少/增加的次数
     , verbose=True  # 触发规则后打印
     , threshold=1e-4  # 触发规则的阈值
     , threshold_mode='abs'  # 触发规则的计算方法
     , cooldown=0  # 触发规则后停止监控这么多次
     , min_lr=0  # lr最小是这么多
     , eps=1e-8
     )

# 自定义 学习率衰减
torch.optim.lr_scheduler.LambdaLR
```

如何使用？
```python
# 训练阶段，前面一堆代码
optimizer.step()
scheduler.step()
# 后面一堆代码
```

画一个学习率衰减图

```python
optimizer = torch.optim.Adam(my_net.parameters(), lr=0.1)
# scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.5)
scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.96)

lr_history = []
for i in range(100):
    scheduler.step()
    lr_history.append(optimizer.state_dict()['param_groups'][0]['lr'])
```









## 其它常见问题

```python

torch.get_default_dtype()
torch.set_default_dtype(torch.float16)


torch.ByteTensor([1.1, 2, 3]) # 对于小数，会取整。对于溢出的数（大于255或负的），会舍弃溢出位数
# 但是，如果输入的是Tensor，会卡死，这么解决：
torch.tensor([1, 2, 3]).type(torch.int8)
```



**hook**

```python
# 正向时会触发的hook
def func1(model,input,output):pass
my_net.register_forward_hook(func1)
# 反向时会触发的hook
def func2(model,grad_input,grad_output):pass
my_net.register_backward_hook(func2)
```

### 显存不够

如果模型太大，一个batch未必能放进去显存。解决：把一个 batch 分割运行，把梯度累积起来，n次后更新一次

```python
accumulation_steps = 5  # 累积5次，然后更新一次权重

for i in range(1000):
    loss = loss_func(pred, y)
    loss = loss / accumulation_steps
    loss.backward() # 计算 loss
    if (i + 1) % accumulation_steps == 0:
        optimizer.step()  # 参数更新
        optimizer.zero_grad()  # 清空梯度
```

另一种情况，如果有两个独立的子任务，尽量独自前向传播
```py
# 不要这样：
loss = loss1 + loss2
loss.backward()

# 而是这样：
loss = loss1 + loss2
loss1.backward()
loss2.backward()
```

---

## File: _posts/0_合集/2_6_pytorch/2019-12-08-torch_operators.md

---
layout: post
title: 【pytorch】优化算法介绍
categories: torch
tags: 
keywords:
order: 262
---





## 优化算法理论篇
### 1. SGD类
#### 1.1 BGD
batch gradient descent, 就是输入全部数据求得平均误差，然后以此为依据，进行一次迭代更新

$\theta=\theta-\alpha \nabla_\theta J(\theta)$  

优点:
- cost fuction若为凸函数，能够保证收敛到全局最优值；若为非凸函数，能够收敛到局部最优值

缺点:
- 每轮迭代都需要在整个数据集上计算一次，速度慢
- 需要较大内存
- 批量梯度下降不允许在线更新模型，例如新增实例。


#### 1.2 SGD
stochastic gradient descent, 每次读入一个数据进行计算。  

$\theta=\theta-\alpha \nabla_\theta J(\theta,x^{(i)},y^{(i)})$  

优点:
- 算法收敛速度快(在Batch Gradient Descent算法中, 每轮会计算很多相似样本的梯度, 这部分是冗余的)
- 可以在线更新
- 有几率跳出一个比较差的局部最优而收敛到一个更好的局部最优甚至是全局最优


缺点：
1. 由于是随机抽取，梯度不可避免会有误差，因此需要调整学习率。
2. 容易局部最优，容易陷入马鞍点

#### 1.3 Mini-batch Gradient Descent
Mini-batch Gradient Descent, 将数据分为很多batch，每次随机抽取一个batch进行迭代运算。  

$\theta=\theta-\alpha \nabla_\theta J(\theta,x^{(i:i+n)},y^{(i:i+n)})$


以上方法的共同缺点是：
1. 学习率$\alpha$难以选择
2. 往往陷入局部最优


### 2. Momentum

#### 2.1 Momentum
模拟物理中的动量概念，优点是前期能够加速震荡，后期再局部最小值附近震荡时，能够抑制震荡，加快收敛。

$v_t=\gamma v_{t-1}+\nabla_\theta J(\theta)$  
$\theta \leftarrow \theta-v_t$  
特点：
- 下降初期，能够加速下降
- 下降中后期，康震荡

#### 2.2 Nesterov Momentum法

在小球向下滚动的过程中，我们希望小球能够提前知道在哪些地方坡面会上升，这样在遇到上升坡面之前，小球就开始减速。这方法就是Nesterov Momentum，其在凸优化中有较强的理论保证收敛。并且，在实践中Nesterov Momentum也比单纯的 Momentum 的效果好：  

$v_t=\gamma v_{t-1}+\nabla_\theta J(\theta-\gamma v_{t-1})$  
$\theta \leftarrow \theta-v_t$  

这样理解：$\theta-\gamma v_{t-1}$是小球对下一个位置的“展望”  


### 3. AdaGrad法
自适应地为各个参数分配不同的学习率，能够控制每个维度的梯度方向。  


AdaGrad 算法的一次迭代时这样的：
- 取一个batch
- 计算梯度，这一步与SGD一样 $g\leftarrow \dfrac{1}{m}\nabla_\theta \sum_i L(f(x^{(i)};\theta),y^{(i)})$  
- 累积平方梯度 $r\leftarrow r+g\bigodot g$  
- 计算更新$\Delta \theta \leftarrow \dfrac{\epsilon}{\delta+\sqrt r}\bigodot g$
- 应用迭代$\theta\leftarrow \theta+\Delta \theta$


用语言描述就是：梯度越小的分量（从图上看越平缓）下降越快，反之下降越慢。




这个图里的划线部分是传统的 mini-batch ，如果用 AdaGrad 可以小勺一些震荡。


### Adalelta
Adagrad法存在的问题：学习率单调递减，需要手动设置全局初始学习率。  
Adadelta法用一阶方法，近似模拟二阶牛顿法，解决了以上问题
### RMSProp法
与Momentum类似地方法，通过引入衰减系数，使每回合都衰减一定的比例。  
适用于RNN  
Adagrad会累加之前所有的梯度平方，而RMSprop仅仅是计算对应的平均值，因此可缓解Adagrad算法学习率下降较快的问题。  
- 取一个batch
- 计算梯度，这一步与SGD一样 $g\leftarrow \dfrac{1}{m}\nabla_\theta \sum_i L(f(x^{(i)};\theta),y^{(i)})$  
- $r\leftarrow \rho r+(1-\rho)g\bigodot g$  
- 计算更新$\Delta \theta \leftarrow \dfrac{\epsilon}{\delta+\sqrt r}\bigodot g$
- 应用迭代$\theta\leftarrow \theta+\Delta \theta$


### Adam
名称来源于 adaptive moment estimation. 根据损失函数对每个参数的梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。  
本质上是 Momentum + RMSProp  

（tf的默认参数: $\alpha=0.001,\beta_1=0.9, \beta_2=0.999, \epsilon=10^{-8}$）  
$g_t$ 是梯度  
$m_t=\beta_1 m_{t-1}+(1-\beta_1) g_t$  
$v_t=\beta_2 v_{t-1}+(1-\beta_2)g_t^2$  
$\hat m_t=\dfrac{m_t}{1-\beta_1^t}$  
$\hat v_t=\dfrac{v_t}{1-\beta_2^t}$  
$\theta_{t+1}=\theta_t-\dfrac{\alpha}{\sqrt {\hat v_t}+\epsilon} \hat m_t$  






## 关于局部最优

做梯度下降时，往往会收敛到各维度一阶导数为0的点。  
我们往往觉得这是一个局部最优点，但实际上有可能是鞍点。下面是鞍点的图示：  







**判断鞍点的一个充分条件是：函数在一阶导数为零处（驻点）的 Hessian matrix 为不定矩阵。**

这让我们想到，如果算法收敛到一个点（各维度的一阶导数一定为0），那么这个点是不定矩阵的概率是 $1-0.5^n$，n较大时，这个数接近1.  
也就是说，**高维空间中的鞍点数量远远大于最优点**  
**看起来，模型几乎收敛到鞍点** （错误的结论，因为还有更差的情况，下面解释）  

在鞍点，一个随机的扰动，就会滑出鞍点。这是 mini-batch 的优势。**大部分时候收敛到的并不是鞍点**  
（另外，还有些鞍点是难以逃离的）

高维空间里（深度学习问题上）真正可怕的不是局部最优也不是鞍点问题，而是一些特殊地形。比如大面积的平坦区域。

---

## File: _posts/0_合集/2_6_pytorch/2019-12-14-torch_model.md

---
layout: post
title: 【pytorch】建立模型
categories: torch
tags: 
keywords:
order: 264
---




## 最小实践：分类模型

step1:编数据
```python
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn import model_selection, datasets


X, y = datasets. \
    make_classification(n_samples=100_000,
                        n_features=10,
                        n_informative=5,
                        n_redundant=2,  # 用 n_informative 线性组合出这么多个特征
                        n_classes=3,
                        n_clusters_per_class=1,
                        flip_y=0.05  # 随机交换这么多比例的y，以制造噪声
                        )

from sklearn import model_selection

X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.2)

# NN基本上都要做标准化。图像类是归一化到 0~1，文本类是 embedding
# 只在训练集上 fit，避免数据穿越
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
```

step2:构建神经网络

```python
import torch
import torch.nn as nn
import torch.nn.functional as F


class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.fc1 = nn.Linear(10, 20)
        self.fc2 = nn.Linear(20, 3)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x


my_net = MyNet()
```

step3: 定义参数和损失函数
```python
epochs = 101

# batch_size 大训练更快，但更容易泛化变差
batch_size = 1024

print_every = 5

criterion = nn.CrossEntropyLoss()
# 用的是是最后一层输出 logits（未 softmax）

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)

optimizer = torch.optim.Adam(my_net.parameters(), lr=1e-3)
```

step4：训练
```python
from torch.utils.data import TensorDataset, DataLoader
from sklearn import metrics
import numpy as np

my_net.to(device)

# dataset / dataloader
X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train, dtype=torch.long)
train_loader = DataLoader(
    TensorDataset(X_train_tensor, y_train_tensor),
    batch_size=batch_size,
    shuffle=True
)

X_test_tensor  = torch.tensor(X_test, dtype=torch.float32, device=device)
y_test_tensor  = torch.tensor(y_test, dtype=torch.long, device=device)


for epoch in range(epochs):
    my_net.train()
    running_loss = 0.0
    n = 0

    for xb, yb in train_loader:
        # 训练数据放入 device
        xb = xb.to(device)
        yb = yb.to(device)
        
        # 每次迭代都要清空梯度
        optimizer.zero_grad()

        # 前向传播
        logits = my_net(xb)

        # 计算损失
        loss = criterion(logits, yb)

        # 反向传播
        loss.backward()

        # 更新权重参数值
        optimizer.step()

        running_loss += loss.item() * xb.size(0)
        n += xb.size(0)

    train_loss = running_loss / n

    if epoch % print_every == 0:
        my_net.eval()
        with torch.no_grad():
            test_logits = my_net(X_test_tensor)
            test_loss = criterion(test_logits, y_test_tensor).item()
            y_pred = test_logits.argmax(dim=1).cpu().numpy()

        y_true = y_test_tensor.cpu().numpy()
        precision = metrics.precision_score(y_true, y_pred, average="macro", zero_division=0)
        recall = metrics.recall_score(y_true, y_pred, average="macro", zero_division=0)

        print(f"epoch={epoch:3d} train_loss={train_loss:.5f} "
              f"test_loss={test_loss:.5f} precision={precision:.4f} recall={recall:.4f}")

```

step5:模型的保存和读取
```python
torch.save(my_net.state_dict(), 'my_model.pkl')

my_net.load_state_dict(torch.load('my_model.pkl'))
```

step6:使用模型
```python
_, y_predicted = torch.max(my_net(X_test_tensor), 1)

from sklearn import metrics

print('confusion_matrix = \n', metrics.confusion_matrix(y_predicted, y_test))
```



## 最小实践：回归模型

```python
# 编数据

from sklearn import datasets
from sklearn import model_selection
from sklearn import preprocessing
import numpy as np
import torch
from torch import nn
from torch.utils.data import TensorDataset, DataLoader

X, y, coef = \
    datasets.make_regression(n_samples=1000,
                             n_features=5,
                             n_informative=3,  # 其中，3个feature是有信息的
                             n_targets=1,  # 多少个 target
                             bias=1,  # 就是 intercept
                             coef=True,  # 为True时，会返回真实的coef值
                             noise=1,  # 噪声的标准差
                             )

X_train, X_test, y_train, y_test = model_selection.train_test_split(
    X.astype(np.float32), y.reshape(-1, 1).astype(np.float32), test_size=0.2)

# 要标准化
X_scaler, y_scaler = preprocessing.StandardScaler(), preprocessing.StandardScaler()
X_train = X_scaler.fit_transform(X_train).astype(np.float32)
X_test = X_scaler.transform(X_test).astype(np.float32)
y_train = y_scaler.fit_transform(y_train).astype(np.float32)
y_test = y_scaler.transform(y_test).astype(np.float32)


# %% 建模型
class MyModel(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(MyModel, self).__init__()
        self.linear = nn.Linear(input_dim, output_dim, bias=True)

    def forward(self, x):
        out = self.linear(x)
        return out


my_model = MyModel(input_dim=5, output_dim=1)

# %% 超参数和损失函数
epochs = 401
learning_rate = 0.01
batch_size = 512

criterion = nn.MSELoss()
optimizer = torch.optim.SGD(my_model.parameters(), lr=learning_rate)

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)

# %% 构建数据

# 使用 DataLoader 做 batch
X_train_t = torch.tensor(X_train, dtype=torch.float32)
y_train_t = torch.tensor(y_train, dtype=torch.float32)
X_test_t = torch.tensor(X_test, dtype=torch.float32, device=device)
y_test_t = torch.tensor(y_test, dtype=torch.float32, device=device)

dataloader_train = DataLoader(
    TensorDataset(X_train_t, y_train_t),
    batch_size=batch_size,
    shuffle=True,
    num_workers=0,
    pin_memory=torch.cuda.is_available()
)

# %% 定义测评指标
import numpy as np
from sklearn import metrics


def eval_1(model, X, y, y_scaler):
    model.eval()
    with torch.no_grad():
        X = X.to(device)
        y_hat_np = model(X).cpu().numpy()
    y_np = y.cpu().numpy()

    # 返回到原来的尺度
    y_hat_np = y_scaler.inverse_transform(y_hat_np)
    y_np = y_scaler.inverse_transform(y_np)

    # 计算 MAE、MSE、R2
    mae = metrics.mean_absolute_error(y_np, y_hat_np)
    rmse = np.sqrt(metrics.mean_squared_error(y_np, y_hat_np))
    r2 = metrics.r2_score(y_np, y_hat_np)
    return mae, rmse, r2


# %% 训练

my_model = my_model.to(device)

for epoch in range(epochs):
    my_model.train()
    for xb, yb in dataloader_train:
        xb = xb.to(device, non_blocking=True)  # 允许异步拷贝，从而节省时间
        yb = yb.to(device, non_blocking=True)

        optimizer.zero_grad()
        pred = my_model(xb)
        loss = criterion(pred, yb)
        loss.backward()
        optimizer.step()

    if epoch % 50 == 0:
        mae_tr, rmse_tr, r2_tr = eval_1(model=my_model, X=X_train_t, y=y_train_t, y_scaler=y_scaler)
        mae_te, rmse_te, r2_te = eval_1(model=my_model, X=X_test_t, y=y_test_t, y_scaler=y_scaler)

        print(f"epoch {epoch:3d} | "
              f"train MAE={mae_tr:.4f} RMSE={rmse_tr:.4f} R2={r2_tr:.4f} | "
              f"test  MAE={mae_te:.4f} RMSE={rmse_te:.4f} R2={r2_te:.4f}")

# %% 预测（输出回到原 y 尺度）
my_model.eval()
with torch.no_grad():
    y_hat_scaled = my_model(X_test_t.to(device)).cpu().numpy()

y_hat = y_scaler.inverse_transform(y_hat_scaled)
```


测评指标怎么看？
1. R2 不多说，越接近1越好，例如 0.81 说明模型能解释 81% 的方差
2. MAE 和 RMSE 都是带单位的。MAE 是平均的预测误差
3. RMSE 由于加了平方，它如果与 MAE 的差距很大，说明有个别样例的误差很大。

## DDP

如果有多个 GPU，可以并行训练，其原理很简单，各 GPU 上独立计算梯度，然后做 All-Reduce 求平均，再各自更新参数


```
from torch.nn.parallel import DistributedDataParallel as DDP
```




这里分3步：
1. 生成数据并保存
2. 并行训练
3. 推理


step1: 编造数据，并保存。以及把标准化的模型一起保存
```python
# make_data.py
import os
import numpy as np
from sklearn import datasets, model_selection
from sklearn.preprocessing import StandardScaler
import joblib


def main(seed=42, out_dir="data"):
    os.makedirs(out_dir, exist_ok=True)

    X, y = datasets.make_classification(
        n_samples=100_000,
        n_features=10,
        n_informative=5,
        n_redundant=2,
        n_classes=3,
        n_clusters_per_class=1,
        flip_y=0.05,
        random_state=seed
    )

    X_train, X_test, y_train, y_test = model_selection.train_test_split(
        X, y, test_size=0.2, random_state=seed, stratify=y
    )

    # 只在训练集上 fit，避免数据穿越
    scaler = StandardScaler()
    X_train = scaler.fit_transform(X_train)
    X_test = scaler.transform(X_test)

    np.savez_compressed(
        os.path.join(out_dir, "cls_data.npz"),
        X_train=X_train.astype(np.float32),
        y_train=y_train.astype(np.int64),
        X_test=X_test.astype(np.float32),
        y_test=y_test.astype(np.int64),
    )
    joblib.dump(scaler, os.path.join(out_dir, "scaler.joblib"))

    print(f"Saved: {out_dir}/cls_data.npz, {out_dir}/scaler.joblib")


if __name__ == "__main__":
    main()
```


step2: 训练

```python
# 4个 GPU 并行训练，执行以下脚本：
# torchrun --standalone --nproc_per_node=4 train_ddp.py
# train_ddp.py
import os
import numpy as np
from dataclasses import dataclass

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.distributed as dist

from torch.utils.data import TensorDataset, DataLoader
from torch.utils.data.distributed import DistributedSampler
from torch.nn.parallel import DistributedDataParallel as DDP

from sklearn import metrics


@dataclass
class Config:
    data_path: str = "data/cls_data.npz"
    ckpt_dir: str = "ckpt"
    ckpt_name: str = "model.pt"

    epochs: int = 101
    batch_size: int = 1024
    lr: float = 1e-3
    print_every: int = 5
    num_workers: int = 2
    seed: int = 42


class MyNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 20)
        self.relu1 = nn.ReLU()
        self.fc2 = nn.Linear(20, 3)

    def forward(self, x):
        x = self.relu(self.fc1(x))
        return self.fc2(x)  # logits


def is_main() -> bool:
    return dist.get_rank() == 0


def ddp_setup():
    """
    torchrun 会注入环境变量：RANK, WORLD_SIZE, LOCAL_RANK
    RANK 是全局 rank，每个进程有唯一的编号，范围 [0, WORLD_SIZE-1]
    LOCAL_RANK 是本机 rank，范围 [0, nproc_per_node-1]
    """
    if not torch.cuda.is_available():
        raise RuntimeError("未检测到 CUDA/GPU")

    if "RANK" not in os.environ or "WORLD_SIZE" not in os.environ:
        raise RuntimeError("启动方式：torchrun --standalone --nproc_per_node=4 train_ddp.py ")

    dist.init_process_group(backend="nccl")

    if not (dist.is_available() and dist.is_initialized()):
        raise RuntimeError("初始化失败")

    local_rank = int(os.environ["LOCAL_RANK"])
    # 设置默认的 CUDA，不然的话，其它代码如果未指定GPU号则会都集中在 CUDA:0 上
    torch.cuda.set_device(local_rank)

    # 一些相关配置：
    # dist.get_world_size()
    return local_rank


def ddp_cleanup():
    dist.destroy_process_group()


def set_seed(seed: int):
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    np.random.seed(seed)


@torch.no_grad()
def evaluate(model, device, X_test, y_test, criterion):
    model.eval()
    logits = model(X_test)
    loss = criterion(logits, y_test).item()
    y_pred = logits.argmax(dim=1).cpu().numpy()
    y_true = y_test.cpu().numpy()
    precision = metrics.precision_score(y_true, y_pred, average="macro", zero_division=0)
    recall = metrics.recall_score(y_true, y_pred, average="macro", zero_division=0)
    return loss, precision, recall


def main():
    cfg = Config()
    os.makedirs(cfg.ckpt_dir, exist_ok=True)

    local_rank = ddp_setup()
    set_seed(cfg.seed + dist.get_rank())

    device = torch.device("cuda", local_rank)
    print("启动设备：", device)

    # load data
    d = np.load(cfg.data_path)
    X_train = torch.from_numpy(d["X_train"])
    y_train = torch.from_numpy(d["y_train"])
    # 评估只在主进程做
    X_test = torch.from_numpy(d["X_test"]).to(device) if is_main() else None
    y_test = torch.from_numpy(d["y_test"]).to(device) if is_main() else None

    train_ds = TensorDataset(X_train, y_train)

    # DDP sampler
    sampler = DistributedSampler(train_ds, shuffle=True)

    train_loader = DataLoader(
        train_ds,
        batch_size=cfg.batch_size,
        sampler=sampler,
        num_workers=cfg.num_workers,
        pin_memory=True,  # 锁定内存页，提高 CPU -> GPU 的搬运效率
        drop_last=False
    )

    # model / loss / optim
    model = MyNet().to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=cfg.lr)

    # wrap DDP
    model = DDP(model, device_ids=[device.index])

    for epoch in range(cfg.epochs):
        sampler.set_epoch(epoch)

        model.train()
        running_loss = 0.0
        n = 0

        for xb, yb in train_loader:
            xb = xb.to(device, non_blocking=True)
            yb = yb.to(device, non_blocking=True)

            optimizer.zero_grad(set_to_none=True)
            logits = model(xb)
            loss = criterion(logits, yb)

            # 这一步 DDP 会对所有 GPU 上的梯度做 reduce
            # 发生阻塞，DDP 做了优化，“边算边通信”
            loss.backward()
            optimizer.step()  # 每个进程用相同的梯度更新自己的模型副本

            running_loss += loss.item() * xb.size(0)
            n += xb.size(0)

        train_loss_local = running_loss / max(n, 1)

        # 汇总各进程的 train loss（加权平均）
        t = torch.tensor([running_loss, n], dtype=torch.float64, device=device)
        # 对所有进程的 t 求和，并广播回各自进程的 t
        dist.all_reduce(t, op=dist.ReduceOp.SUM)
        train_loss = (t[0] / t[1]).item()

        if (epoch % cfg.print_every == 0) and is_main():
            # 注意：DDP 下 model 是 wrapper，真实模型是 model.module
            eval_model = model.module
            test_loss, precision, recall = evaluate(eval_model, device, X_test, y_test, criterion)

            print(
                f"epoch={epoch:3d} "
                f"train_loss={train_loss:.5f} "
                f"test_loss={test_loss:.5f} "
                f"precision={precision:.4f} recall={recall:.4f}"
            )

    # save checkpoint（只在主进程保存）
    if is_main():
        raw_model = model.module
        ckpt_path = os.path.join(cfg.ckpt_dir, cfg.ckpt_name)
        torch.save(
            {
                "model_state_dict": raw_model.state_dict(),
                "config": cfg.__dict__,
            },
            ckpt_path
        )
        print(f"Saved checkpoint to: {ckpt_path}")

    ddp_cleanup()


if __name__ == "__main__":
    main()
```


原理说明：
1. 会在 CPU 上启动4个进程，每个进程绑定一个 GPU
2. 每个 GPU 上计算梯度，然后 reduce，然后用相同的梯度更新各自的模型副本


加载模型，并做推理

```python
# infer.py
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn import metrics


class MyNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 20)
        self.fc2 = nn.Linear(20, 3)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        return self.fc2(x)


def main(data_path="data/cls_data.npz", ckpt_path="ckpt/model.pt"):
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    d = np.load(data_path)
    X_test = torch.from_numpy(d["X_test"]).to(device)
    y_test = d["y_test"]  # numpy

    model = MyNet().to(device)
    ckpt = torch.load(ckpt_path, map_location=device)
    model.load_state_dict(ckpt["model_state_dict"])
    model.eval()

    with torch.no_grad():
        logits = model(X_test)
        y_pred = logits.argmax(dim=1).cpu().numpy()

    print("confusion_matrix=\n", metrics.confusion_matrix(y_test, y_pred))


if __name__ == "__main__":
    main()
```





## 一些研究




可以手动去做 SGD
```python
learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate)
```



### 从raw建立神经网络

```python
import numpy as np
from sklearn import datasets

X, y, coef = \
    datasets.make_regression(n_samples=1000,
                             n_features=5,
                             n_informative=5,  # 其中，3个feature是有信息的
                             n_targets=1,  # 多少个 target
                             bias=0,  # 就是 intercept
                             coef=True,  # 为True时，会返回真实的coef值
                             noise=0.001,  # 噪声的标准差
                             )

# 必须标准化

from sklearn import preprocessing

X_transform=preprocessing.StandardScaler().fit_transform(X)
y_transform=preprocessing.StandardScaler().fit_transform(y.reshape(-1,1))

# 构建参数

import torch

x_tensor = torch.tensor(X_transform,dtype=float)
y_tensor=torch.tensor(y_transform,dtype=float)

input_size, hidden_size, output_size, batch_size = x_tensor.shape[1], 128, 1, 116
```

方法1:从raw建立

```python
# 权重
weights1 = torch.randn((input_size, hidden_size), dtype=float, requires_grad=True)
biases1 = torch.randn(hidden_size, dtype=float, requires_grad=True)
weights2 = torch.randn((hidden_size, output_size), dtype=float, requires_grad=True)
biases2 = torch.randn(output_size, dtype=float, requires_grad=True)

# 训练

learning_rate = 0.01
losses = []

for i in range(10000):
    hidden = x_tensor.mm(weights1) + biases1
    hidden = torch.relu(hidden)
    y_hat = hidden.mm(weights2) + biases2
    # 可以用 my_nn = torch.nn.Sequential，简化

    # 可以用 cost = torch.nn.MSELoss，以及 loss = cost(y_hat, y) ，简化
    loss = torch.mean((y_hat - y_tensor) ** 2)
    losses.append(loss.data.numpy())

    if i % 1000 == 0:
        print('loss:', loss)

    loss.backward()

    # 更新参数，可以用 optimizer.step() 更新
    weights1.data.add_(-learning_rate * weights1.grad.data)
    biases1.data.add_(-learning_rate * biases1.grad.data)
    weights2.data.add_(-learning_rate * weights2.grad.data)
    biases2.data.add_(-learning_rate * biases2.grad.data)

    # 清空
    weights1.grad.data.zero_()
    biases1.grad.data.zero_()
    weights2.grad.data.zero_()
    biases2.grad.data.zero_()
```    


方法2:使用torch的内置函数，可以有更简洁的写法

```python
my_nn = torch.nn.Sequential(
    torch.nn.Linear(input_size, hidden_size),
    torch.nn.Sigmoid(),
    torch.nn.Linear(hidden_size, output_size)
)

cost = torch.nn.MSELoss(reduction='mean')
optimizer = torch.optim.Adam(my_nn.parameters(), lr=0.001)

# 训练
losses = []
for i in range(1000):
    batch_loss = []

    for start in range(0, len(x_tensor), batch_size):
        end = min(start + batch_size, len(x_tensor))
        xx = torch.tensor(x_tensor[start:end], dtype=torch.float, requires_grad=True)
        yy = torch.tensor(y_tensor[start:end], dtype=torch.float, requires_grad=True)

        y_hat = my_nn(xx)
        loss = cost(y_hat, yy)
        optimizer.zero_grad()
        loss.backward(retain_graph=True)
        optimizer.step()
        batch_loss.append(loss.data.numpy())

    if i % 100 == 0:
        losses.append(np.mean(batch_loss))
    print(i, np.mean(batch_loss))
```