mingyun / mingyun.github.io

github主页
157 stars 92 forks source link

python 学习 #110

Open mingyun opened 6 years ago

mingyun commented 6 years ago
https://www.shiyanlou.com/courses/983/labs/3952/document
2.2.1 创建密钥

首先在终端敲入,如果一路一直按回车下去,会把密钥文件放置再默认路径,也就是 ~/.ssh/ 路径下,并且会创建一套空密码验证的密钥文件,反之则每一次匹对公私钥都需要再手动输入一次密码,所以这里为了方便使用,建议一路回车下去就行

$ ssh-keygen
输入密钥文件保存路径,建议默认路径,按回车跳过
要求输入密码,建议回车使用空密码方便以后的每次连接
到选择存放密钥文件的路径下查看,我这里使用的使默认路径,所以使 ~/.ssh/ 路径下,可以看到生成了两个密钥文件,后缀为 .pub 的就是公钥文件,另一个没有后缀的就是私钥文件,可以看到密钥文件创建完毕

2.2.2 关联公钥到 Github 账号下

首先复制公钥文件中的内容,也就是 ssh-rsa 开头到 用户名@主机名 这段字符串
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDStxnH4GgUnoKDVUtz5+ASquLsXA8D+bKPiAe0Ts+tOhpHac2jsCVBn7gGRi232GGJVl9QfwH4Qo0QrXm+h9+kSDe+PZM7UbpxBxrhq61DDy63NhTot4K46jNEo/DC0r7nKZ0WZQiGex/FPNetuacsuIwZ06J7f83TT3MM8x4X4DG3N3pDK1YySUUr8mKPFQbhu8y2SPeHnpG5b6+4NKG92cYeKCqtohZ1+iIL7iH8kUcJKu3sA9w6IrN+yWy07IH1tAUswzuLmDtk8QWdJQ9av3I1i6KcpfuFFcdw5jcbZZpOG1xC3/z/9XHrBV/br2MwoIiQi1pI shiyanlou@0a663168c0bb
然后回到 Github, 点击右上角头像的下拉按钮,选择 Settings
然后在 Settings 页面中选择左边菜单里的 SSH and GPG keys,然后点击右上角的 New SSH key 按钮,填写 Title 和 Key,然后点击 Add SSH key 按钮提交

通过返回的页面可以看到公钥与 Github 已经关联完毕
因为我们是 HTTPS 协议方式来克隆的仓库,所以每一次同步操作都需要输入用户名和密码
git clone https://github.com/shiyanlou-001/shiyanlou-001.git

#!/usr/bin/env python3 其中第一行的前两个字符 #! 称为 Shebang ,目的是告诉 shell 使用 Python 3 解释器执行其下面的代码。 如果有这行代码,并且给脚本通过 Linux 的 chmod a+x XXX.py 命令增加了执行权限,则可以使用 ./XXX.py 这种方式直接执行脚本,否则需要用 python3 XXX.py 这种方式执行。

来源: 实验楼 
链接: https://www.shiyanlou.com/courses/983
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播
str1.strip('ab') 则只会删除 str1 字符串中头尾部的 a 和 b 字符
异常类: NameError 访问一个未定义的变量 SyntaxError 语法错误,这个严格讲算是程序的错误 IndexError 对于一个序列,访问的索引超过了序列的范围(序列的概念会在后续实验中讲到),可以理解为我的序列里只有三个元素,但要访问第4个 KeyError 访问一个不存在的字典 Key,字典也会在下一节实验中详细讲到,Key 如果不存在字典就会抛出这个异常 ValueError 传入无效的参数 AttributeError 访问类对象中不存在的属性
 filename = '/etc/protocols' f = open(filename) try: f.write('shiyanlou') except: print("File write error") finally: print("finally") f.close()
raise ValueError() 外部的代码就可以使用 except ValueError 进行捕获和处理了。

每个 XXX.py 文件都是一个 Python 模块,文件的内容会在 import XXX 的时候直接执行。对于文件夹,Python 中可以识别成一个包,前提是这个文件夹中有一个 __init__.py 文件,文件中可以不用写任何内容。例如我们创建一个目录 shiyanlou,在这个目录下有 __init__.py 和 louplus.py 两个代码文件,我们想要引入 louplus.py 文件就可以用 import shiyanlou.louplus 这种代码来引入,前提是 shiyanlou 目录已经放到了 Python 模块搜索的默认路径下了sys.path

当通过 import argtest 作为模块导入到其他代码文件时不会执行if __name__ == '__main__':中的内容。
https://github.com/shiyanlou/louplus-python/blob/master/01-income-tax-calculator/challenge1-good.py 
format(1.2345, ".2f") 

 >>> courses.insert(0, 'Java') >>> courses ['Java', 'Linux', 'Python', 'Vim', 'C++', 'PHP']
>>> courses.remove('Java') 
>>> courses ['Ruby', 'Linux', 'Python', 'Vim', 'C++', 'PHP']
>>> courses ['BigData', 'C++', 'Cloud', 'Linux', 'PHP'] 
>>> courses.pop(0) 'BigData' >>> courses ['C++', 'Cloud', 'Linux', 'PHP']
需要注意空的集合不能够使用 {} 创建,只能使用 set 函数,因为{} 创建的是一个空的字典 : 
>>> courses = set() >>> type(courses)
 >>> courses = {'Linux', 'C++', 'Vim', 'Linux'} 
>>> courses {'Linux', 'Vim', 'C++'}
集合还可以直接由字符串与 set 函数进行创建,会将字符串拆散为不同的字符,并去除重复的字符: >>> nameset = set('shiyanlou.com') >>> nameset {'c', 'o', '.', 'm', 'u', 'h', 's', 'a', 'n', 'i', 'y', 'l'}

>>> dict_from_tuple = dict(((1,'Linux'), (2,'Vim'))) 
>>> >>> dict_from_tuple {1: 'Linux', 2: 'Vim'}
 字典中也存在 pop(key) 函数,可以返回 key 对应的 value,并将该 key:value 键值对删除: >>> coursesdict {2: 'Vim', 5: 'Bash', 6: 'Python'} >>> coursesdict.pop(2) 'Vim' >>> coursesdict {5: 'Bash', 6: 'Python'}

列表:可修改有序的数据集合 元组:不可修改的有序的数据集合 集合:无序的不重复的数据集合 字典:无序的存储 key:value 键值对的数据集合

def change(): global a a = 90 print(a) a = 9 print("Before the function call ", a) print("inside change function", end=' ') change() print("After the function call ", a)

 >>> connect(port=22, ipaddress='192.168.1.1')

我们也能将函数的参数标记为只允许使用参数名传递参数。用户调用函数时将只能对每一个参数使用相应的参数名,如果不使用则会抛出 TypeError:
 >>> def hello(*, name='User'):
         ... print("Hello", name) ... 
>>> hello('shiyanlou') Traceback (most recent call last): File "", line 1, in TypeError: hello() takes 0 positional arguments but 1 was given 
>>> hello(name='shiyanlou') Hello shiyanlou

第一个是具有默认值的参数后面不能再有普通参数,比如 f(a,b=90,c) 就是错误的。
 第二个是默认值只被赋值一次,因此如果默认值是任何可变对象时会有所不同,比如列表、字典或大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数: 
>>> def f(a, data=[]): ... data.append(a) ... return data ... >>> print(f(1)) [1] >>> print(f(2)) [1, 2] >>> print(f(3)) [1, 2, 3]
 要避免这个问题,你可以像下面这样: 
>>> def f(a, data=None): ... if data is None: ... data = [] ... data.append(a) ... return data ... >>> print(f(1)) [1] >>> print(f(2)) [2]
 可变参数的使用方法是在参数列表前加上 *

Python 中的对象有不可变对象,指的是数值、字符串、元组等,和可变对象,指的是列表、字典等。如果是不可变对象作为参数,相当于是值的传递,函数中对该参数的修改不会保留。如果是可变对象,则相当于传引用,函数中的修改会保留。
 面向对象的 4 个核心概念: 抽象 封装 继承 多态
 object 是 Python 中所有对象的祖先,它是所有类的基类。类需要一个初始化方法,__init__ 是 Python 的初始化方法,注意前后各有两个下划线 _,self指代当前的对象。 类是一个抽象的概念,而实例是一个具体的对象。比如说狗是一个抽象的概念,因为狗有很多种,而那个正在 wang wang 叫的叫旺财的狗是一个实例。

多态就是使用同一方法对不同对象可以产生不同的结果。

静态变量和类方法是可以直接从类访问,不需要实例化对象就能访问。假设上面例子中的动物它们都是 Jack 养的,那么就可以在 Animal 类中用一个静态变量表示,一般声明在 __init__ 前面: class Animal(object): owner = 'jack' def __init__(self, name): self._name = name

类方法和静态变量类似,它也可以通过类名直接访问,类方法用 @classmethod 装饰,类方法中可以访问类的静态变量,下面添加了一个类方法 get_owner: 
class Animal(object): owner = 'jack' def __init__(self, name): self._name = name @classmethod def get_owner(cls): return cls.owner 注意类方法的第一个参数传入的是类对象,而不是实例对象,所以是 cls。 通过类方法获取 owner: print(Animal.get_owner()) # 'jack' print(Cat.get_owner()) # 'jack'
 静态方法用 @staticmethod 装饰,和 classmethod 有点类似。staticmethod 在运行时不需要实例的参与,它被放在类下面只是因为它和类有一点关系,但并不像类方法那样需要传递一个 cls 参数。
 使用了两次 readline() 再次使用 readlines() 将不会有任何输出,所以我们需要再次重新打开文件

for 循环遍历文件对象来读取文件中的每一行:
 >>> file = open(filename) >>> for x in file: ... print(x, end = '')

>>> import pickle >>> courses = { 1:'Linux', 2:'Vim', 3:'Git'} >>> with open('./courses.data', 'wb') as file: ... pickle.dump(courses, file) ... >>> with open('./courses.data', 'rb') as file: ... new_courses = pickle.load(file) ... >>> new_courses {1: 'Linux', 2: 'Vim', 3: 'Git'}

能被 for 循环访问的都是可迭代的对象,能被 next() 函数获取下一个值的是迭代器。

生成器只能被迭代一次,因为每次迭代的元素不是像列表元素一样,已经在内存中,而是你每迭代一次,它生成一个元素。 创建一个生成器并迭代:
 >>> g = (x**x for x in range(1, 4)) >>> g at 0x10d1a5af0> >>> for x in g: ... print(x)
 *arg 和 **kwargs 都是 Python 中函数的可变参数。 *args 表示任何多个无名参数,是一个元组,**kwargs 表示关键字参数,是一个字典。这两个组合表示了函数的所有参数。如果同时使用时,*args 参数列要在 **kwargs 前。
datetime.now().strftime('%Y')
OrderedDict 是一个特殊的字典。字典本质上是一个哈希表,其实现一般是无序的,OrderedDict 能保持元素插入的顺序: >>> from collections import OrderedDict >>> d = OrderedDict() >>> d['apple'] = 1 >>> d['google'] = 2

 >>> from collections import Counter >>> c = Counter('https://www.shiyanlou.com')
 >>> c.most_common(3) [('w', 3), ('h', 2), ('t', 2)]

 if sys.argv[1] == 2 :
    exit()
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()
Flask 提供了一个管理 Flask 应用的命令行工具,首先要设置应用的环境变量:

export FLASK_APP=app.py
export FLASK_DEBUG=1
环境变量 FLASK_APP 是用来指向 flask run 执行的 Flask 应用代码的路径,这里是 app.py 的路径。FLASK_DEBUG=1 表示打开 DEBUG 信息,可以输出访问和出错信息,帮助我们解决代码中出现的问题,建议后续只要执行 flask run 都要打开 FLASK_DEBUG。

然后就可以这样运行 Flask 应用了:

flask run
默认地,应用运行在 localhost:5000 上。打开浏览器,访问这个地址就能看到返回的 Hello World! 了。
@app.route('/user/<username>')
def user_index(username):
    # 在函数中指名变量名称,这样就能获取到通过路由传入的变量值
    return 'Hello {}'.format(username)
也可以指定路由变量的类型,比如说,一个博客应用的每个博文页面可以用这篇博文的 ID 作为路由变量,ID 应该是个 int 类型的值:

@app.route('/post/<int:post_id>')
def show_post(post_id):
    return 'Post {}'.format(post_id)
注册的路由 return 的内容会包含在返回给用户的 HTTP response 中,这两个实例都返回字符串,所以用户使用浏览器访问这两个链接地址的时候看到的就是两个字符串显示在浏览器页面上。

模板渲染

在上面的例子中,处理函数返回的都是字符串,但是在真正的项目中,需要使用 HTML 编写页面,不可能把所有的内容都写到字符串中。模板引擎的作用就是你用模板引擎规定的语法编写 HTML 页面,在处理函数中指定模板,传入相应的模板变量,Flask 就能调用模板引擎自动渲染出一个完整的 HTML 页面。

Flask 默认的模板引擎是 jinja2,理论上你是可以更换其它模板引擎的,但是 jinja2 已经足够好用。

Flask 使用 render_template 函数渲染模板,指定了一个模板名称后,Flask 会到 templates 目录下去找这个模板,然后使用传入的变量渲染模板。

如果我们用模板来改写用户主页的例子,那么处理函数可以这样写:

from flask import render_template

@app.route('/user/<username>')
def user_index(username):
    return render_template('user_index.html', username=username)
然后创建 templates 目录,目录结构变成这样:

/flask-test-app
    app.py
    /templates
        user_index.html
在 user_index.html 中:

<h1>Hello, {{ username }}!</h1>
在 jinja2 中,用 {{ }} 来渲染一个字符串变量。这里的 username 就是在 render_template 的时候传入的关键字参数 username。现在访问一个用户主页,比如说:

localhost:5000/user/shiyanlou
就能看到一个用 h1 标签包裹的 Hello, shiyanlou! 了。

另外,flask 中提供了 url_for 来根据路由的函数名称构建 URL 链接地址,提供了 redirect 来跳转到其他路由,见下面的例子:

from flask import render_template, redirect, url_for

@app.route('/')
def index():
    return redirect(url_for('user_index', username='default'))

@app.route('/user/<username>')
def user_index(username):
    return render_template('user_index.html', username=username)
这个例子中,访问 / index 页面的时候,会自动跳转到 /user/default 页面,跳转的目标页面 URL 地址是由 url_for 产生的,而跳转过程是由 redirect 函数进行的操作。
request 对象

Flask 通过 request 对象获取请求相关的数据,要使用它,要从 flask 导入:

from flask import request
从 request.headers 获取请求头的数据,可以把它当作字典来使用,比如要获取用户的 user-agent:

request.headers.get('User-Agent')
从 request.args 获取请求的参数,假设我们的应用是个博客应用,主页有分页功能,用 这个 URL 访问主页:

localhost:5000?page=2&per_page=10
获取 ? 后面的参数就可以这样做:

page = request.args.get('page')
per_page = request.args.get('per_page')
处理之外,可以通过 request.form 获取表单数据,通过 request.method 获取当前请求的方法。

session

HTTP 协议是无状态的,每一次请求它们的关系都是相互独立的。但是在实际的应用是,我们确实有很多数据服务器需要记住,但又不适合存放在数据库中。

比如说,一个登录页面需要在用户密码输入错误 3 次后要求输入验证码,服务器就需要一个计数器纪录错误次数,但把它放到数据库也不太合适。session 就是用来为每个用户独立存放一些数据的地方。存放在 session 里的数据可以在特定用户的多个请求之间共享。

cookies

cookies与 session 类似,只不过 cookies 是存在客户端加密信息。在 Flask 中,cookie 使用配置的 SECRET_KEY 作为签名进行加密。

比如在上面的访问用户主页的路由中,将用户名设置为一个 cookies,这样用户在此访问时,我们就能知道他是谁了:

from flask import make_response

@app.route('/user/<username>')
def user_index(username):
    resp = make_response(render_template('user_index.html', username=username))
    resp.set_cookie('username', username)
    return resp
设置 cookies后,用户访问其他页面可以从 request.cookies 获取到我们设置的 username:

from flask import request

@app.route('/')
def index():
    username = request.cookies.get('username')
    return 'Hello {}'.format(username)
错误处理

使用 app.errorhandler 装饰器可以注册错误处理函数,比如对于最常见的 404 错误,我们返回一个特定的 404.html 页面。

@app.errorhandler(404)
def not_found(error):
    return render_template('404.html'), 404
例子中也展示了使用 render_template 的一个小知识点,就是可以在它后面指定本次返回的状态码。

在 flask 中还有一个经常用来处理错误的方法 abort(),使用 abort(404) 则能够直接进入到页面无法找到(HTTP 状态码404)的处理逻辑中。例子如下:

from flask import render_template, abort

@app.route('/user/<username>')
def user_index(username):
    if username == 'invalid':
        abort(404)
    return render_template('user_index.html', username=username)
当 username 为 invalid 字符串的时候,即访问 /user/invalid 地址的时候,直接返回页面无法找到。

Numpy 支持比 Python 本身更为丰富的数值类型,细分如下:

bool:布尔类型,1 个字节,值为 True 或 False。
int:整数类型,通常为 int64 或 int32 。
intc:与 C 里的 int 相同,通常为 int32 或 int64。
intp:用于索引,通常为 int32 或 int64。
int8:字节(从 -128 到 127)
int16:整数(从 -32768 到 32767)
int32:整数(从 -2147483648 到 2147483647)
int64:整数(从 -9223372036854775808 到 9223372036854775807)
uint8:无符号整数(从 0 到 255)
uint16:无符号整数(从 0 到 65535)
uint32:无符号整数(从 0 到 4294967295)
uint64:无符号整数(从 0 到 18446744073709551615)
float:float64 的简写。
float16:半精度浮点,5 位指数,10 位尾数
float32:单精度浮点,8 位指数,23 位尾数
float64:双精度浮点,11 位指数,52 位尾数
complex:complex128 的简写。
complex64:复数,由两个 32 位浮点表示。
complex128:复数,由两个 64 位浮点表示。
在 Numpy 中,上面提到的这些数值类型都被归于 dtype(data-type) 对象的实例。

我们可以用 numpy.dtype(object, align, copy) 来指定数值类型。而在数组里面,可以用 dtype= 参数。

import numpy as np

a = np.array([1.1, 2.2, 3.3], dtype=np.float64) # 指定 1 维数组的数值类型为 float64
此处输入图片的描述

另外,你可以使用 .astype() 方法在不同的数值类型之间相互转换。

a.astype(int) # 将 a 的数值类型从 float64 转换为 int
此处输入图片的描述

最后,你可以使用 .dtype 来查看 dtype 属性。

a.dtype # 查看 a 的数值类型
http://pillow-zh-cn.readthedocs.io/zh_CN/latest/installation.html
>>> from PIL import Image
>>> im = Image.open("nyan.png")
>>> print(im.format, im.size, im.mode)
>>> gray = im.convert('L')
>>> img = im.getdata()
>>> list(img)
$ wget http://labfile.oss.aliyuncs.com/courses/673/images.zip
$ unzip images.zip #解压文件
$ wget http://labfile.oss.aliyuncs.com/courses/673/Image_2_ASCII.zip
wget http://labfile.oss.aliyuncs.com/courses/694/category.zip  
create database category default charset utf8;
use category;
 CREATE TABLE `category` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自动增长id',
  `pid` int(11) NOT NULL COMMENT '父id',
  `category` varchar(255) NOT NULL COMMENT '分类名称',
  `orderid` int(11) NOT NULL DEFAULT '0' COMMENT '排序id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
$ wget http://labfile.oss.aliyuncs.com/courses/756/simple.py
$ wget http://labfile.oss.aliyuncs.com/courses/756/my_word_cloud.py
$ wget http://labfile.oss.aliyuncs.com/courses/756/santi.txt
$ wget http://labfile.oss.aliyuncs.com/courses/756/santi2.txt
$ wget http://labfile.oss.aliyuncs.com/courses/756/santi3.txt

$ wget http://labfile.oss.aliyuncs.com/courses/756/stormtrooper_mask.png
$ wget http://labfile.oss.aliyuncs.com/courses/756/constitution.txt
$ wget http://labfile.oss.aliyuncs.com/courses/791/finally.py
$ wget http://labfile.oss.aliyuncs.com/courses/791/my_data.xlsx
$ wget http://labfile.oss.aliyuncs.com/courses/791/phase_detector.xlsx
$ wget http://labfile.oss.aliyuncs.com/courses/791/phase_detector2.xlsx
mingyun commented 6 years ago
"""
    ###     ####         ######
          ###  ###      #    ###
    ###         ###       ######
    ###      ####       ###   ##
    ###    ####        ###    ##
    ###   ##########    ##### ###

i2a creates ASCII art from images right on your terminal.

Usage: i2a [options] [FILE]

Options:
  -h --help            Show this on screen.
  -v --version         Show version.
  -c --colors          Show colored output.
  -b --bold            Output bold characters
  --contrast=<factor>  Manually set contrast [default: 1.5].
  --alt-chars          Use an alternate set of characters. 
"""

import subprocess
from colors import *
from PIL import Image, ImageEnhance
from docopt import docopt

__version__ = '1.0'

_ASCII = "@80GCLft1i;:,. "
_ASCII_2 = "Q0RMNWBDHK@$U8&AOkYbZGPXgE4dVhgSqm6pF523yfwCJ#TnuLjz7oeat1[]!?I}*{srlcxvi)><\\)|\"/+=^;,:'_-`. "

def rgb(red, green, blue):
    return 16 + (red * 36) + (green * 6) + blue

def set_style(fg=None, bg=None, bold=None):
    print(_set_style(fg, bg, bold), end='')

def _set_style(fg=None, bg=None, bold=''):
    result = ''
    if fg:
        result += '\x1b[38;5;%dm' % fg
    if bg:
        result += '\x1b[48;5;%dm' % bg
    if bold:
        result += '\x1b[1m'
    return result

def reset_color():
    print(_reset_color(), end='')

def _reset_color():
    return '\x1b[0m'

def print_color(*args, **kwargs):
    fg = kwargs.pop('fg', None)
    bg = kwargs.pop('bg', None)
    bold = kwargs.pop('bold', None)
    set_style(fg, bg, bold)
    print(*args, **kwargs)
    reset_color()

def display_output(arguments):
    global _ASCII
    if arguments['--alt-chars']:
        _ASCII = _ASCII_2
    try:
        im = Image.open(arguments['FILE'])
    except:
        raise IOError('Unable to open the file.') 
    im = im.convert("RGBA")
    try:
        _HEIGHT, _WIDTH = map(int, subprocess.check_output(['stty', 'size']).split())
    except:
        _HEIGHT, _WIDTH = 50, 50

    aspect_ratio    = im.size[0] / im.size[1]
    scaled_height   = _WIDTH / aspect_ratio
    scaled_width    = _HEIGHT * aspect_ratio * 2

    width = scaled_width
    height = scaled_height
    if scaled_width > _WIDTH:
        width = int(_WIDTH)
        height = int(scaled_height / 2)

    elif scaled_height > _HEIGHT:
        width = int(scaled_width)
        height = int(_HEIGHT)

    im = im.resize((width,height), resample=Image.ANTIALIAS)

    enhancer = ImageEnhance.Contrast(im)
    im = enhancer.enhance(float(arguments['--contrast']))
    img = im.getdata()

    im = im.convert('L')

    bg = rgb(0, 0, 0)
    fg = rgb(5, 5, 5)

    bold = None
    if arguments['--bold']:
        bold = True
    else:
        bold = False

    row_len = 0
    for (count, i) in enumerate(im.getdata()):
        ascii_char = _ASCII[int((i / 255.0) * (len(_ASCII) - 1))]

        if arguments['--colors']:
            color = rgb(int((img[count][0] / 255.0) * 5), int((img[count][1] / 255.0) * 5),int((img[count][2] / 255.0) * 5))
            bg = color
            fg = rgb(0, 0, 0)
        print_color(ascii_char, end='', fg=fg, bg=bg, bold=bold)

        row_len += 1
        if row_len == width:
            row_len = 0
            print('')

def main():
    arguments = docopt(__doc__, version=__version__)
    if arguments['FILE']:
        display_output(arguments)
    else:
        print(__doc__)

if __name__ == '__main__':
    main()

from os import path
from wordcloud import WordCloud
import os
d = path.dirname(__file__)

font=os.path.join(os.path.dirname(__file__), "DroidSansFallbackFull.ttf")
font='simhei.ttf'
# Read the whole text.
#text = open(path.join(d, 'constitution.txt')).read()
text = open(u"video.html").read().decode('gbk')

# Generate a word cloud image
wordcloud = WordCloud(font_path=font).generate(text)

# Display the generated image:
# the matplotlib way:
import matplotlib.pyplot as plt
plt.imshow(wordcloud)
plt.axis("off")

# lower max_font_size
wordcloud = WordCloud(font_path=font,max_font_size=40).generate(text)
plt.figure()
plt.imshow(wordcloud)
plt.axis("off")
plt.show()
mingyun commented 6 years ago

https://getman.cn/4e7Pn PHP7内核剖析https://github.com/pangudashu/php7-internal https://github.com/kz26/gohls gohls -l=true "m3u8地址" "保存的文件名.mp4" https://github.com/nilaoda/The-New-M3U8-Downloader/ https://github.com/xuyuanfang/m3u8_downloader_4_yingke 将ts转成m3u8 ffmpeg -i 12生肖.ts -c copy -map 0 -f segment -segment_list playlist.m3u8 -segment_time 10 output%03d.ts 将MP4转成m3u8

ffmpeg -i test.mp4 -codec copy -bsf h264_mp4toannexb test.ts https://www.zhihu.com/question/48914419?sort=created M3U8 Downloader

>>> sprintf("%15s",'1.2.3')
=> "          1.2.3"
public static  function get_client_ip($type = 0)
    {
        $type       =  $type ? 1 : 0;
        static $ip  =   NULL;
        if ($ip !== NULL) return $ip[$type];
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $pos    =   array_search('unknown',$arr);
            if(false !== $pos) unset($arr[$pos]);
            $ip     =   trim($arr[0]);
        }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ip     =   $_SERVER['HTTP_CLIENT_IP'];
        }elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip     =   $_SERVER['REMOTE_ADDR'];
        }
        // IP地址合法验证
        $long = sprintf("%u",ip2long($ip));
        $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
        return $ip[$type];
    }

    /**
     * 计算集群节点
     * @param $room     房间号
     * @param array $node 节点数组
     */
    public static function calculateNode($room,$num){
        if(!empty($room) && !empty($num)){
            return crc32(hash('md5',$room)) % $num;
        }
        return false;
    }
/**
     * curl多线程请求
     * @param $channel
     * @param $array
     * @param $data
     * @param int $timeout
     * @return array
     */
    public static function multipleThreadsRequest($channel,$array,$data,$timeout = 10){
        $res = [];
        $mh = curl_multi_init();//创建多个curl语柄
        foreach($array as $k=>$url){
            $conn[$k]=curl_init($url.'?id='.$channel);
            curl_setopt($conn[$k], CURLOPT_TIMEOUT, $timeout);//设置超时时间
            curl_setopt($conn[$k], CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
            curl_setopt($conn[$k], CURLOPT_HEADER, 0);//这里不要header,加块效率
            curl_setopt($conn[$k],CURLOPT_RETURNTRANSFER,1);
            curl_setopt($conn[$k], CURLOPT_POSTFIELDS, $data);
            curl_multi_add_handle ($mh,$conn[$k]);
        }
        $running = NULL;
        do {
            usleep(10000);
            curl_multi_exec($mh,$running);
        } while($running > 0);

        foreach ($array as $k => $url) {
            $errors = curl_error($conn[$k]);
            $res[$k]=curl_multi_getcontent($conn[$k]);//获得返回信息
            $header[$k]=curl_getinfo($conn[$k]);//返回头信息
            //抛入异常日志记录
            if(!empty($errors)){
                $header[$k]['errors'] = $errors;
            }
            curl_close($conn[$k]);//关闭语柄
            curl_multi_remove_handle($mh  , $conn[$k]);   //释放资源
        }
        curl_multi_close($mh);
        return [
            'return'=>$res,
            'header'=>$header
        ];
    }
mingyun commented 6 years ago
use Illuminate\Http\Request;
public function postLogin($q Request){

        // 先校验验证码
        $this->validate($q, [
            'captcha' => 'required|captchadun',
        ]);
return response()->json(['code' => '200', 'msg' => 'success'])
}

App\Providers\CaptchaDunServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Services\CaptchaVerifier;

class CaptchaDunServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     */
    public function boot()
    {
        $this->app['validator']->extend('captchadun', function($attribute, $value, $parameters)
        {
            return (new CaptchaVerifier(config('services.captcha.CAPTCHA_ID'),config('services.captcha.SECRET_ID'),config('services.captcha.SECRET_KEY')))->verify($value);
        });
    }

    /**
     * Register any application services.
     *
     * This service provider is a great spot to register your various container
     * bindings with the application. As you can see, we are registering our
     * "Registrar" implementation here. You can add your own bindings too!
     */
    public function register()
    {

    }

}

config/app.php
'providers' => [
 'App\Providers\CaptchaDunServiceProvider',
]
App\Services\CaptchaVerifier .php
<?php
namespace App\Services;
/**
 * 易盾验证码二次校验SDK http://support.dun.163.com/captcha/api/ http://support.dun.163.com/captcha/demo/#_1
 * @author yangweiqiang
 */
class CaptchaVerifier {
    const VERSION = 'v2';
    const API_TIMEOUT = 5;
    const API_URL = 'http://c.dun.163yun.com/api/v2/verify';
    /**
     * 构造函数
     * @param $captcha_id 验证码id
     * @param $secret_id 密钥对
     * @param $secret_key 密钥对
     */
    public function __construct($captcha_id, $secret_id, $secret_key) {
        $this->captcha_id  = $captcha_id;
        $this->secret_id = $secret_id;
        $this->secret_key = $secret_key;
    }

    /**
     * 发起二次校验请求
     * @param $validate 二次校验数据
     * @param $user 用户信息
     */
    public function verify($validate, $user = '') {
        $params = array();
        $params["captchaId"] = $this->captcha_id;
        $params["validate"] = $validate;
        $params["user"] = $user;
        // 公共参数
        $params["secretId"] = $this->secret_id;
        $params["version"] = self::VERSION;
        $params["timestamp"] = sprintf("%d", round(microtime(true)*1000));// time in milliseconds
        $params["nonce"] = sprintf("%d", rand()); // random int
        $params["signature"] = $this->sign($this->secret_key, $params);

        $result = $this->send_http_request($params);\Log::info('captcha',['captcha'=>$result]);
        return array_key_exists('result', $result) ? $result['result'] : false;
    }

    /**
     * 计算参数签名
     * @param $secret_key 密钥对key
     * @param $params 请求参数
     */
    private function sign($secret_key, $params){
        ksort($params); // 参数排序
        $buff="";
        foreach($params as $key=>$value){
            $buff .=$key;
            $buff .=$value;
        }
        $buff .= $secret_key;
        return md5($buff);
    }

    /**
     * 发送http请求
     * @param $params 请求参数
     */
    private function send_http_request($params){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, self::API_URL);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::API_TIMEOUT);
        curl_setopt($ch, CURLOPT_TIMEOUT, self::API_TIMEOUT);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));

        /*
         * Returns TRUE on success or FALSE on failure. 
         * However, if the CURLOPT_RETURNTRANSFER option is set, it will return the result on success, FALSE on failure.
         */
        $result = curl_exec($ch);
        // var_dump($result);

        if(curl_errno($ch)){
            $msg = curl_error($ch);
            curl_close($ch);
            return array("error"=>500, "msg"=>$msg, "result"=>false);
        }else{
            curl_close($ch);
            return json_decode($result, true);  
        }
    }
}

<meta charset="utf-8"/>

 <div id="captcha"></div>
 <div class="error-code"></div>
<div class="login">登录</div>                           
<script src="//code.jquery.com/jquery.js"></script>
<script src="//cstaticdun.126.net/load.min.js"></script>                        
<script type="text/javascript">
        var captchaInstance,captcha;
        initCaptcha();
        function initCaptcha() {
            initNECaptcha({
                captchaId: "b7982ef659d64141b7120a6af27e19a0",
                element: "#captcha",
                //mode: "float",
                width: 270,
                onReady: function(instance) {
                    console.log("captchaready");
                },
                onVerify: function(err, data) {
                    if (data) {
                        captcha = data.validate;
                    }
                }
            }, function onload(instance) {
                captchaInstance = instance;
            }, function onerror(err) {

            });
        }
        $('.login').click(function(){
            $.ajax({
                url: "/login",
                type: "POST",
                data: {
                    captcha: captcha
                },
                success: function(res) {
                    switch (parseInt(res.code)) {
                      case 200:
                        captchaInstance.refresh();
                        break;
                      default:
                        $(".error-code").html("图形码失败");
                        break;
                    }
                },
                error: function(res) {
                    try {
                        var resp = $.parseJSON(res.responseText);
                        if (resp.captcha) {
                            $(".error-code").html("图形码失败");
                            return false;
                        }
                    } catch (e) {
                        $(".error-code").html("图形码失败");
                    }
                }
            });
        });

</script>                        
mingyun commented 6 years ago

https://blog.lerzen.com/ 书童机器人--果冻陪你聊 Python 3 中,包括以下几种基本数据类型:

整数:例如 100,-200,0 等 布尔数:True 或 False 浮点数:小数,例如 1.5,2.5 None:空值,注意与0是不同的,可以理解为未定义的值。 除了这四种之外,还有一些其他不常用的类型,例如复数 两个列表,想合并到一起,一种方法是将其中一个列表合并到另外一个列表的末尾位置,可以使用 extend(): pop() 函数返回最后的一个元素,pop() 在返回元素的同时也会删除这个元素,传入一个参数 i 即 pop(i) 会将第 i 个元素弹出

需要注意空的集合不能够使用 {} 创建,只能使用 set 函数,因为{} 创建的是一个空的字典 :

dict_from_tuple = dict(((1,'Linux'), (2,'Vim')))

coursesdict[5] = 'Bash' del coursesdict[1]

for key,value in coursesdict.items(): print(key,value)

字典中也存在 pop(key) 函数,可以返回 key 对应的 value,并将该 key:value 键值对删除

coursesdict.pop(2) 第一个是具有默认值的参数后面不能再有普通参数,比如 f(a,b=90,c) 就是错误的。

第二个是默认值只被赋值一次,因此如果默认值是任何可变对象时会有所不同,比如列表、字典或大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数 def f(a, data=[]): def connect(ipaddress, *ports):

connect('192.168.1.1', 22, 23, 24) Python 中的对象有不可变对象,指的是数值、字符串、元组等,和可变对象,指的是列表、字典等。如果是不可变对象作为参数,相当于是值的传递,函数中对该参数的修改不会保留。如果是可变对象,则相当于传引用,函数中的修改会保留。 面向对象的 4 个核心概念:

抽象 封装 继承 多态

抽象就是对特定实例抽取共同的特征及行为形成一种抽象类型的过程。 特征和行为在程序语言中通常被称为属性(Attribute)和方法(Method) 封装就是用类将数据和基于数据的操作封装在一起,隐藏内部数据,对外提供公共的访问接口。 object 是 Python 中所有对象的祖先,它是所有类的基类。类需要一个初始化方法,init 是 Python 的初始化方法,注意前后各有两个下划线 _,self指代当前的对象。

类是一个抽象的概念,而实例是一个具体的对象。比如说狗是一个抽象的概念,因为狗有很多种,而那个正在 wang wang 叫的叫旺财的狗是一个实例。 隐藏数据访问有什么好处呢?最大的好处就是提供访问控制。比如在 Cat 类中,用户输入名的可能有小写,有大写,而我们希望对外提供的名词都是首字母大写,其余字母小写,那么我们就可以在 get_name 方法中做访问控制

def get_name(self): return self._name.lower().capitalize()

Dog 和 Cat 继承了父类 Animal 的初始化方法,get_name 和 set_name 方法,并重写了父类的 make_sound 方法。 多态就是使用同一方法对不同对象可以产生不同的结果。 因为 Python 中不是绝对的私有,还是通过 obj._Classname__privateAttributeOrMethod 来访问

class Animal(object):
    owner = 'jack'
    def __init__(self, name):
        self._name = name
    @classmethod
    def get_owner(cls):
        return cls.owner
class Animal(object):
    def __init__(self, name):
        self._name = name
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self, value):
        self._name = value
    def make_sound(self):
        pass
  @staticmethod
    def order_animal_food():
        print('ording...')
        print('ok')
Animal.order_animal_food()
我们需要谨慎使用 read() 读取整个文件,因为有可能你的系统内存并不足够存储整个文件的内容。当 read() 执行后,再次执行将不会有任何内容的输出。
>>> file = open(filename)
>>> for x in file:
...     print(x, end = '')
 with open(filename) as file:
    count = 0
    for line in file:
        count += 1
        print(line)
    print('Lines:', count)
for i, x  in enumerate(sys.argv):
    if (i == 0):
        continue
    print(i, x)

 d = {'a': 1, 'b': 2, 'c': 3}
{k:v*v for k, v in d.items()}
能被 for 循环访问的都是可迭代的对象,能被 next() 函数获取下一个值的是迭代器。
生成器首先它是一个迭代器,不同的是,生成器只能被迭代一次,因为每次迭代的元素不是像列表元素一样,已经在内存中,而是你每迭代一次,它生成一个元素。

>>> g = (x**x for x in range(1, 4))
>>> g
<generator object <genexpr> at 0x10d1a5af0>
>>> for x in g:
...     print(x)
...
1
4
27

和列表解析有点像,只不过使用的是圆括号。不同于列表可以反复迭代,迭代完一次之后再迭代这个生成器,它不会打印元素,也不回报错。

使用生成器有什么好处呢?因为生成器不是把所有元素存在内存,而是动态生成的,所以当你要迭代的对象有非常多的元素时,使用生成器能为你节约很多内存,这是一个内存友好的特性。

 >>> def fib(n):
...     current = 0
...     a, b = 1, 1
...     while current < n:
...         yield a
...         a, b = b, a + b
...         current += 1

装饰器本质上是一个函数,它接受一个函数作为参数。

>>> from datetime import datetime
>>> def log(func):
...     def decorator(*args, **kwargs):
...         print('Function ' + func.__name__ + ' has been called at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
...         return func(*args, **kwargs)
...     return decorator
...
>>> @log
... def add(x, y):
...     return x + y
...
>>> add(1, 2)
Function add has been called at 2017-08-29 13:11:48
3
>>> def add(x, y):
...     return x + y
...
>>> add = log(add)
>>> add(1, 2)
Function add has been called at 2017-08-29 13:16:02
3
add 其实已经不再是原来的 add 函数了,它已经变成了log 函数返回的 decorator 函数:

>>> add.__name__
'decorator'

多进程

import os
from multiprocessing import Process

def hello(name):
    print('child process: {}'.format(os.getpid()))
    print('Hello ' + name)

def main():
     # 注意:args 参数要以 tuple 方式传入
    p = Process(target=hello, args=('shiyanlou', ))
    p.start()
    p.join()
    print('parent process: {}'.format(os.getpid()))

if __name__ == '__main__':
    main()

用 Process 类定义了一个子进程,这个子进程要执行的函数是 hello,传入的参数是 shiyanlou,然后调用 start() 方法,启动子进程,这时候子进程会调用 hello 函数,将 shiyanlou 作为参数传入,打印当前进程 id 和 hello shiyanlou 后返回。 join() 方法表示等待子进程运行结束后继续执行,所以在子进程返回后会继续打印父进程的 id

from multiprocessing import Process, Queue

queue = Queue()

def f1():
    queue.put('Hello shiyanlou')

def f2():
    data = queue.get()
    print(data)

def main():
    Process(target=f1).start()
    Process(target=f2).start()

if __name__ == '__main__':
    main()

import time
from multiprocessing import Process, Value, Lock

def func(val, lock):
    for i in range(50):
        time.sleep(0.01)
        # with lock 语句是对下面语句的简写:
        # 使用 acquire() 方法获取锁,release() 方法释放锁
     # 多进程无法使用全局变量,multiprocessing 提供的 Value 是一个代理器,
     # 可以实现在多进程的共享这个变量
        # lock.acquire()
        # val.value += 1
        # lock.release()
        #
        with lock:
            val.value += 1

if __name__ == '__main__':

    v = Value('i', 0)
    # 初始化锁
    lock = Lock()
    procs = [Process(target=func, args=(v, lock)) for i in range(10)]

    for p in procs:
        p.start()
    for p in procs:
        p.join()

    print(v.value)
用一个进程池打印输出30次范围在0~29之间的数字:

from multiprocessing import Pool

def f(i):
    print(i, end=' ')

def main():
      # 初始化一个 3 个进程的进程池
    pool = Pool(processes=3)
    for i in range(30):
           # 调用 apply 方法开始处理任务,传入任务处理函数 f,和参数 i
        pool.apply(f, (i,))

if __name__ == '__main__':
    main()
import threading

def hello(name):
      # get_ident() 函数获取当前线程 id 
    print('child thread: {}'.format(threading.get_ident()))
    print('Hello ' + name)

def main():
    # 初始化一个线程,参数传递和使用 Process 一样
    t = threading.Thread(target=hello, args=('shiyanlou',))
    # 启动线程和等待线程结束,和 Process 的接口一样
    t.start()
    t.join()
    print('main thread: {}'.format(threading.get_ident()))

if __name__ == '__main__':
    main()

>>> from datetime import datetime

>>> datetime.now().strftime('%Y%m%d %H%M%S')
'20171203 180633'
 >>> from collections import OrderedDict
>>> d = OrderedDict()
>>> d['apple'] = 1
>>> d['google'] = 2

>>> from collections import namedtuple
>>> Point = namedtuple('P', ['x', 'y'])
>>> p = Point(10, 12)
>>> p.x
10
>>> p.y
12
from collections import Counter
http://labfile.oss-cn-hangzhou.aliyuncs.com/courses/983/week2/11-22-week2.mp4
 export FLASK_APP=app.py
export FLASK_DEBUG=1
flask shell
app = Flask(__name__)
app.config.update({
      'SECRET_KEY': 'a random string' 
})
app.config.from_pyfile('path/to/config.py')
app.config['SECRET_KEY'] 这样可以获得 SECRET_KEY 的配置值

@app.route('/user/<username>')
def user_index(username):
    # 在函数中指名变量名称,这样就能获取到通过路由传入的变量值
    return 'Hello {}'.format(username)
@app.route('/post/<int:post_id>')
def show_post(post_id):
    return 'Post {}'.format(post_id)
from flask import render_template

@app.route('/user/<username>')
def user_index(username):
    return render_template('user_index.html', username=username)
@app.route('/')
def index():
    return redirect(url_for('user_index', username='default'))
request.headers.get('User-Agent')
request.headers.get('User-Agent') 
@app.errorhandler(404)
def not_found(error):
    return render_template('404.html'), 404
from flask import make_response

@app.route('/user/<username>')
def user_index(username):
    resp = make_response(render_template('user_index.html', username=username))
    resp.set_cookie('username', username)
    return resp
app.config['TEMPLATES_AUTO_RELOAD'] = True
 每当模板发生改变时,会自动重新渲染模板

{% ... %} 包含的代码是可以被执行的语句,比如循环语句,继承语法;
{{ ... }} 包含的的 Python 对象,用于解析出这些对用的值,经常用于打印内容;
{# ... #} 用于添加注释,这些注释不会被处理,但是也不会输出到 HTML 源码中;

{% if course.is_private %}
    <p> course {{course.name}} is private </p>
{% elif course.is_member_course %}
    <p> course {{course.name}} is member course </p>
{% else %}
    <p> course {{course.name}} is normal course </p>
{% endif %}
{% macro course_item(course, type="bootstrap") %}
    <div>
        <p> type: {{ type }} </p>
        <p> name: {{ course.name }}</p>
        <p> user count: {{ course.user_count }}</p>
        <p> teacher: {{course.teacher }} </p>
        <p> is_private: {{ course.is_private }} </p>
    </div>
{% endmacro %}

<div> {{ course_item(course) }} </div>
<p>{{ '=' * 20 }}</p>
<div> {{ course_item(course, type="louplus") }} </div>

来源: 实验楼
链接: https://www.shiyanlou.com/courses/983
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播
mingyun commented 6 years ago
{% from 'macro.html' import course_item %}

<div> {{ course_item(course) }} </div>
 {% extends "base.html" %}
{% from 'macro.html' import course_item %}

{% block header %}
    <h1> header </h1>
{% endblock %}

{% block content %}
    {{ course_item(course) }}
{% endblock %}

<p> course tag length: {{ course.tags | length }} </p>
添加唯一约束还有一种方式为 alter table user modify email varchar(64) unique;,这种方式实际上是通过修改字段添加唯一索引
有了 ORM 以后可以将 Python 对象映射到数据库中,这样就不用再编写各种 SQL 语句了
$ cd ~/Code
$ sudo pip install virtualenv
$ virtualenv -p /usr/bin/python3.5 env
$ source env/bin/activate
$ pip install sqlalchemy ipython
$ deactivate
In [1]: from sqlalchemy import create_engine

In [2]: engine = create_engine('mysql://root:@localhost/shiyanlou')

In [3]: engine.execute('select * from user').fetchall()
Out[3]: [(1, 'aiden', 'luojin@simplecloud.cn'), (2, 'lxttx', 'lxttx@gmail.com')]

当在 virtualenv 下安装了包之后,需要先用 deactivate 命令退出 virtualenv 后再重新激活 virtualenv 才可以用这个包。

In [1]: from sqlalchemy import create_engine

In [2]: engine = create_engine('mysql://root:@localhost/shiyanlou')

In [3]: engine.execute('select * from user').fetchall()
Out[3]: [(1, 'aiden', 'luojin@simplecloud.cn'), (2, 'lxttx', 'lxttx@gmail.com')]
from sqlalchemy.ext.declarative import declarative_base
 Base = declarative_base()
In [19]: from sqlalchemy import Column, Integer, String

In [20]: class User(Base):
    ...:     __tablename__ = 'user'
    ...:     id = Column(Integer, primary_key=True)
    ...:     name = Column(String)
    ...:     email = Column(String)
    ...:     def __repr__(self):
    ...:         return "<User(name=%s)>" % self.name

In [27]: User.__table__
Out[27]: Table('user', MetaData(bind=None), Column('id', Integer(), table=<user>, primary_key=True, nullable=False), Column('name', String(), table=<user>), Column('email', String(), table=<user>), schema=None)
In [30]: from sqlalchemy.orm import sessionmaker

In [31]: Session = sessionmaker(bind=engine)

In [32]: session = Session()
In [63]: session.query(User).all()
Out[63]: [<User(name=aiden)>, <User(name=lxttx)>]

In [65]: session.query(User).filter(User.name=='aiden').first()
Out[65]: <User(name=aiden)>
engine = create_engine('mysql://root:@localhost/shiyanlou', echo=True)),则使用 session 查询时,可以看到相应的 SQL 输出:

数据库实例,比如一个 app 使用一个数据库;
collection 文档集合 ,一个数据库包含多个文档集合,类似于 MySQL 中的表;
document 文档,一个文档代表一项数据,类似于 JSON 对象,对应于MySQL 表中的一条记录;
字段:一个文档包含多个字段;
MongoDB 存储的数据可以是无模式的,比如在一个集合中的所有文档不需要有一致的结构。也就是说往同一个表中插入不同的数据时,这些数据之间不必有同样的字段。这和 MySQL 彻底不同,在 MySQL 中创建表时就已经确定了数据项的字段,往其中插入数据时,必须是相同的结构。

MongoDB 存储的文档记录是一个 BSON 对象,类似于 JSON 对象,由键值对组成。比如一条用户记录:

{
    name: "Aiden",
    age: 30,
    email: "luojin@simplecloud.cn"
}
每一个文档都有一个 _id 字段,该字段是主键,用于唯一的确定一条记录。如果往 MongoDB 中插入数据时没有指定 _id 字段,那么会自动产生一个 _id 字段,该字段的类型是 ObjectId,长度是 12 个字节。在 MongoDB 文档的字段支持字符串,数字,时间戳等类型。一个文档最大可以达到 16M, 可以存储相当多的数据。

$ mongo
> use shiyanlou
> db.user.insertOne({name: "Aiden", age: 30, email: "luojin@simplecloud.cn", addr: ["CD", "SH"]})
{
        "acknowledged" : true,
        "insertedId" : ObjectId("59a8034064e0acb13483d512")
}
> show databases;
admin      0.000GB
local      0.000GB
shiyanlou  0.000GB
> show collections;
user
db.user.insertMany([
> db.user.find()
{ "_id" : ObjectId("59a8034064e0acb13483d512"), "name" : "Aiden", "age" : 30, "email" : "luojin@simplecloud.cn", "addr" : [ "CD", "SH" ] }
db.user.find({name: "jin"})
 db.user.find({age: {$gt: 30}})
> db.user.updateOne(
... {name: "Aiden"},
... {$set: {age: 29, addr: ["CD", "SH", "BJ"]}}
... )
db.user.deleteMany({addr: "CD"})

In [2]: from pymongo import MongoClient

In [3]: client = MongoClient('127.0.0.1', 27017)

In [4]: db = client.shiyanlou
In [14]: user = {'name': 'Aiden', 'age': 30, 'addr': ['CD', 'SH', 'BJ']}

In [15]: db.user.insert_one(user)
Out[15]: <pymongo.results.InsertOneResult at 0x10730aa08>
In [17]: db.user.find_one({'name': 'Aiden'})
db.user.update_one({'name': 'Aiden'}, {'$set': {'email': 'aiden@simplecloud.cn'}})

In [1]: import redis

In [2]: r = redis.StrictRedis(host='127.0.0.1', db=0)

In [3]: r.ping()
Out[3]: True
In [5]: p = r.pubsub()

In [6]: p.subscribe('labreport-channel')

In [7]: for msg in p.listen():
   ...:     print(msg)
   ...:
{'type': 'subscribe', 'pattern': None, 'channel': b'labreport-channel', 'data': 1}
然后在 redis-cli 客户端中,通过 PUBLISH channel message 指令往频道中发布消息 message:

127.0.0.1:6379> publish labreport-channel "1 msg from redis-cli"
(integer) 1
http://labfile.oss-cn-hangzhou.aliyuncs.com/courses/983/week3/week3.mp4
scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
response.css('div#images a::text').extract()
将结果封装为 scrapy 内部的一个 response 对象并注入到 python shell 中,在这个 response 对象上,可以直接使用 scrapy 内置的css 和 xpath 数据提取器 extract 函数执行提取操作
response.css('div#images p::text').extract_first(default='默认值')
response.css('div#images a::attr(href)').extract()
div 中有多个 class 的情况,用 css 提取器可以写为 div[class="class1 class2"]
response.xpath('//div[@id="images"]/a/text()').extract()
response.css('div#images a::text').re('Name: (.+) ')
re() 方法中定义的正则表达式会作用到每个提取到的文本中,只保留正则表达式中的子模式匹配到的内容,也就是 () 内的匹配内容。
import scrapy

class GithubSpider(scrapy.Spider):
    name = 'shiyanlou-github'

    @property
    def start_urls(self):
        url_tmpl = 'https://github.com/shiyanlou?page={}&tab=repositories'
        return (url_tmpl.format(i) for i in range(1, 5))

    def parse(self, response):
        for repository in response.css('li.public'):
            yield {
                'name': repository.xpath('.//a[@itemprop="name codeRepository"]/text()').re_first("\n\s*(.*)"),
                'update_time': repository.xpath('.//relative-time/@datetime').extract_first() 
            }
class ShiyanlouCoursesSpider(scrapy.Spider):
    """ 所有 scrapy 爬虫需要写一个 Spider 类,这个类要继承 scrapy.Spider 类。在这个类中定义要请求的网站和链接、如何从返回的网页提取数据等等。
    """

    # 爬虫标识符号,在 scrapy 项目中可能会有多个爬虫,name 用于标识每个爬虫,不能相同
    name = 'shiyanlou-courses'

    def start_requests(self):
        """ 需要返回一个可迭代的对象,迭代的元素是 `scrapy.Request` 对象,可迭代对象可以是一个列表或者迭代器,这样 scrapy 就知道有哪些网页需要爬取了。`scrapy.Request` 接受一个 url 参数和一个 callback 参数,url 指明要爬取的网页,callback 是一个回调函数用于处理返回的网页,通常是一个提取数据的 parse 函数。
        """

    def parse(self, response):
        """ 这个方法作为 `scrapy.Request` 的 callback,在里面编写提取数据的代码。scrapy 中的下载器会下载 `start_reqeusts` 中定义的每个 `Request` 并且结果封装为一个 response 对象传入这个方法。
        """
          pass
@property
    def start_urls(self):
        """ start_urls  需要返回一个可迭代对象,所以,你可以把它写成一个列表、元组或者生成器,这里用的是生成器
        """
        url_tmpl = 'https://www.shiyanlou.com/courses/?category=all&course_type=all&fee=all&tag=all&page={}'
        return (url_tmpl.format(i) for i in range(1, 23))
def start_requests(self):
    # 课程列表页面 url 模版
    url_tmpl = 'https://www.shiyanlou.com/courses/?category=all&course_type=all&fee=all&tag=all&page={}'
    # 所有要爬取的页面
    urls = (url_tmpl.format(i) for i in range(1, 23))
    # 返回一个生成器,生成 Request 对象,生成器是可迭代对象
    for url in urls:
        yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response):
    # 遍历每个课程的 div.course-body
    for course in response.css('div.course-body'):
        # 使用 css 语法对每个 course 提取数据
        yield {
            # 课程名称
            'name': course.css('div.course-name::text').extract_first(),
            # 课程描述
            'description': course.css('div.course-desc::text').extract_first(),
            # 课程类型,实验楼的课程有免费,会员,训练营三种,免费课程并没有字样显示,也就是说没有 span.pull-right 这个标签,没有这个标签就代表时免费课程,使用默认值 `免费`就可以了。
            'type': course.css('div.course-footer span.pull-right::text').extract_first(default='Free'),
            # 注意 // 前面的 .,没有点表示整个文档所有的 div.course-body,有 . 才表示当前迭代的这个 div.course-body
               'students': course.xpath('.//span[contains(@class, "pull-left")]/text()[2]').re_first('[^\d]*(\d*)[^\d]*')
        }

scrapy runspider shiyanlou_courses_spider.py -o data.json
 scrapy startproject shiyanlou
cd /home/shiyanlou/Code/shiyanlou/shiyanlou
scrapy genspider courses shiyanlou.com

import scrapy

class CoursesFollowSpider(scrapy.Spider):
    name = 'courses_follow'
    start_urls = ['https://shiyanlou.com/courses/63']

    def parse(self, response):
        yield {
            'name': response.xpath('//h4[@class="course-infobox-title"]/span/text()').extract_first(),
            'author': response.xpath('//div[@class="mooc-info"]/div[@class="name"]/strong/text()').extract_first()
        }
        # 不需要 extract 了
        for url in response.xpath('//div[@class="sidebox-body course-content"]/a/@href'):
            # 不需要构造全 url 了
            yield response.follow(url, callback=self.parse)
mingyun commented 6 years ago

小程序 传图识字 如果你想想涨工资 1.MYSQL 优化优化再优化 索引 查询缓存 主从 分表 读写分离 都是重点 2.算法 简单算法考你思维能力, 重点是推荐算法 3.redis 单例不算个事,要集群,要了解集群分配机制 4.消息队列 简单消息队列谁都会, 要和其他语言协同就要复杂点的 rebbitmq kaffa什么的 5.分布式不会要求你会啥其它分布式方案,起码负载均衡各种要用过,要了解原理

鄙视链条是 BAT 鄙视 二三线计算机专业的 鄙视 非计算机专业自学的 鄙视 培训的

用过第三方方案redis集群的 鄙视 用redis本身集群的 鄙视 redis单例 鄙视 没用过的

用过重量级消息队列产品的 鄙视 自实现的 鄙视没用过的

玩过大数据的 鄙视 只做过推荐算法的 鄙视 简单算法的 鄙视 不会算法的 php artisan queue:work 消费的是默认队列 队列分组了,要指定消费那个组或者消费优先级

>>> from PIL import Image
>>> im=Image.open('web.jpg')
>>> im.show()
>>> im.save('web.png')
>>> box = (100, 100, 400, 400)
>>> region = im.crop(box)#裁剪
>>> region.save('web.png')
>>> im
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=640x640 at 0x2839C10>
>>> im.show()
>>> out = im.resize((128, 128))
>>> out.show()
>>> out = im.rotate(45)#变形
>>> out.show()
>>> a=im.convert("L")#变色彩http://pillow-zh-cn.readthedocs.io/zh_CN/latest/handbook/tutorial.html
>>> a.show()
>>> from PIL import ImageFilter
>>> b=im.filter(ImageFilter.DETAIL)
>>> b.show()

Numpy 使用教程 一、实验介绍

1.1 实验内容

如果你使用 Python 语言进行科学计算,那么一定会接触到 Numpy。Numpy 是支持 Python 语言的数值计算扩充库,其拥有强大的高维度数组处理与矩阵运算能力。除此之外,Numpy 还内建了大量的函数,方便你快速构建数学模型。

1.2 实验知识点

Numpy 数组 ndarray ndarray 数组创建方法 ndarray 数组属性 1.3 实验环境

python2.7 Xfce 终端 ipython 终端 1.4 适合人群

本课程难度为一般,属于初级级别课程,适合具有 Python 基础,并对使用 Numpy 进行科学计算感兴趣的用户。

二、Numpy 多维数组

2.1 ndarray 介绍

在 python 内建对象中,数组有三种形式:

list 列表:[1, 2, 3] Tuple 元组:(1, 2, 3, 4, 5) Dict 字典:{A:1, B:2} 其中,元组与列表相似,不同之处在于元组的元素不能修改。而字典由键和值构成。

python 标准类针对数组的处理局限于 1 维,并仅提供少量的功能。

而 Numpy 最核心且最重要的一个特性就是 ndarray 多维数组对象,它区别于 python 的标准类,拥有对高维数组的处理能力,这也是数值计算过程中缺一不可的重要特性。

Numpy 中,ndarray 类具有六个参数,它们分别为:

shape:数组的形状。 dtype:数据类型。 buffer:对象暴露缓冲区接口。 offset:数组数据的偏移量。 strides:数据步长。 order:{'C','F'},以行或列为主排列顺序。 下面,我们来了解创建 ndarray 的一些方法。在 numpy 中,我们主要通过以下 5 种途径创建数组,它们分别是:

从 Python 数组结构列表,元组等转换。 使用 np.arange、np.ones、np.zeros 等 numpy 原生方法。 从存储空间读取数组。 通过使用字符串或缓冲区从原始字节创建数组。 使用特殊函数,如 random。 2.2 从列表或元组转换

在 numpy 中,我们使用 numpy.array 将列表或元组转换为 ndarray 数组。其方法为:

numpy.array(object, dtype=None, copy=True, order=None, subok=False, ndmin=0) 其中,参数:

object:列表、元组等。 dtype:数据类型。如果未给出,则类型为被保存对象所需的最小类型。 copy:布尔来写,默认 True,表示复制对象。 order:顺序。 subok:布尔类型,表示子类是否被传递。 ndmin:生成的数组应具有的最小维数。 下面,通过列表创建一个 ndarray 数组:

import numpy as np

np.array([[[1, 2, 3],[1, 2, 3],[1, 2, 3]],[[1, 2, 3],[1, 2, 3],[1, 2, 3]],[[1, 2, 3],[1, 2, 3],[1, 2, 3]]])

或者是列表和元组:

import numpy as np

np.array([(1,2),(3,4),(5,6)])

2.3 arange 方法创建

除了直接使用 array 方法创建 ndarray,在 numpy 中还有一些方法可以创建一些有规律性的多维数。首先,我们来看一看 arange()。arange() 的功能是在给定区间内创建一系列均匀间隔的值。方法如下:

numpy.arange(start, stop, step, dtype=None) 你需要先设置值所在的区间,这里为 `[开始, 停止),你应该能发现这是一个半开半闭区间。然后,在设置 step 步长用于设置值之间的间隔。最后的可选参数 dtype可以设置返回ndarray 的值类型。

举个例子:

import numpy as np

在区间 [3, 7) 中以 0.5 为步长新建数组

np.arange(3, 7, 0.5, dtype='float32')

2.4 linspace 方法创建

linspace方法也可以像arange方法一样,创建数值有规律的数组。linspace 用于在指定的区间内返回间隔均匀的值。其方法如下:

numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) start:序列的起始值。 stop:序列的结束值。 num:生成的样本数。默认值为50。 endpoint:布尔值,如果为真,则最后一个样本包含在序列内。 retstep:布尔值,如果为真,返回间距。 dtype:数组的类型。 举个例子:

import numpy as np

np.linspace(0, 10, 10, endpoint=True) np.linspace(0, 10, 10, endpoint=False)

2.5 ones 方法创建

numpy.ones 用于快速创建数值全部为 1 的多维数组。其方法如下:

numpy.ones(shape, dtype=None, order='C') 其中:

shape:用于指定数组形状,例如(1, 2)或 3。 dtype:数据类型。 order:{'C','F'},按行或列方式储存数组。 举个例子:

import numpy as np

np.ones((2,3))

2.6 zeros 方法创建

zeros 方法和上面的 ones 方法非常相似,不同的地方在于,这里全部填充为 0。zeros 方法和 ones 是一致的。

numpy.zeros(shape, dtype=None, order='C') 其中:

shape:用于指定数组形状,例如(1, 2)或3。 dtype:数据类型。 order:{'C','F'},按行或列方式储存数组。 举个例子:

import numpy as np

np.zeros((3,2))

2.7 eye 方法创建

numpy.eye 用于创建一个二维数组,其特点是k 对角线上的值为 1,其余值全部为0。方法如下:

numpy.eye(N, M=None, k=0, dtype=<type 'float'>) 其中:

N:输出数组的行数。 M:输出数组的列数。 k:对角线索引:0(默认)是指主对角线,正值是指上对角线,负值是指下对角线。 举个例子:

import numpy as np

np.eye(5, 4, 3)

2.8 从已知数据创建

我们还可以从已知数据文件、函数中创建 ndarray。numpy 提供了下面 5 个方法:

frombuffer(buffer):将缓冲区转换为 1 维数组。 fromfile(file,dtype,count,sep):从文本或二进制文件中构建多维数组。 fromfunction(function,shape):通过函数返回值来创建多维数组。 fromiter(iterable,dtype,count):从可迭代对象创建 1 维数组。 fromstring(string,dtype,count,sep):从字符串中创建 1 维数组。 举个例子:

import numpy as np

np.fromfunction(lambda a, b: a + b, (5, 4))

三、ndarray 数组属性

首先,我们创建一个 ndarray 数组,这里还是沿用本章节开头的例子。

import numpy as np

a = np.array([[[1, 2, 3],[1, 2, 3],[1, 2, 3]],[[1, 2, 3],[1, 2, 3],[1, 2, 3]],[[1, 2, 3],[1, 2, 3],[1, 2, 3]]])

ndarray 多维数组支持下面这些属性:

3.1 ndarray.T

ndarray.T用于数组的转置,与 .transpose() 相同。

import numpy as np

a.T

3.2 ndarray.dtype

ndarray.dtype 用来输出数组包含元素的数据类型。

import numpy as np

a.dtype

3.3ndarray.imag

ndarray.imag 用来输出数组包含元素的虚部。

import numpy as np

a.imag

3.4ndarray.real

ndarray.real用来输出数组包含元素的实部。

import numpy as np

a.real

3.5 ndarray.size

ndarray.size用来输出数组中的总包含元素数。

import numpy as np

a.size

3.6ndarray.itemsize

ndarray.itemsize输出一个数组元素的字节数。

import numpy as np

a.itemsize

3.7 ndarray.nbytes

ndarray.nbytes用来输出数组的元素总字节数。

import numpy as np

a.nbytes

3.8 ndarray.ndim

ndarray.ndim用来输出数组尺寸。

import numpy as np

a.ndim

3.9 ndarray.shape

ndarray.shape用来输出数组维数组.

import numpy as np

a.shape

3.10 ndarray.strides

ndarray.strides用来遍历数组时,输出每个维度中步进的字节数组。

import numpy as np

a.strides

mingyun commented 6 years ago

二、Numpy 数组的基本操作

上一个章节,我们了解了如何利用 numpy 创建各式各样的 ndarray。本章节,我们将利用学会针对 ndarray 的各种花式操作技巧。

2.1 重设形状

reshape 可以在不改变数组数据的同时,改变数组的形状。其中,numpy.reshape() 等效于 ndarray.reshape()。reshape 方法非常简单:

numpy.reshape(a, newshape) 其中,a 表示原数组,newshape 用于指定新的形状(整数或者元组)。

举个例子:

import numpy as np

np.arange(10).reshape((5, 2))

2.2 数组展开

ravel 的目的是将任意形状的数组扁平化,变为 1 维数组。ravel 方法如下:

numpy.ravel(a, order='C') 其中,a 表示需要处理的数组。order 表示变换时的读取顺序,默认是按照行依次读取,当 order='F' 时,可以按列依次读取排序。

示例:

import numpy as np

a = np.arange(10).reshape((2, 5))

np.ravel(a) np.ravel(a, order='F')

2.3 轴移动

moveaxis 可以将数组的轴移动到新的位置。其方法如下:

numpy.moveaxis(a, source, destination) 其中:

a:数组。 source:要移动的轴的原始位置。 destination:要移动的轴的目标位置。 举个例子:

import numpy as np

a = np.ones((1, 2, 3))

np.moveaxis(a, 0, -1)

你可能没有看明白是什么意思,我们可以输出二者的 shape属性:

2.4 轴交换

和 moveaxis 不同的是,swapaxes 可以用来交换数组的轴。其方法如下:

numpy.swapaxes(a, axis1, axis2) 其中:

a:数组。 axis1:需要交换的轴 1 位置。 axis2:需要与轴 1 交换位置的轴 1 位置。 举个例子:

import numpy as np

a = np.ones((1, 4, 3)) np.swapaxes(a, 0, 2) 我们直接输出两个数组的 shape 值。

2.5 数组转置

transpose 类似于矩阵的转置,它可以将 2 维数组的横轴和纵轴交换。其方法如下:

numpy.transpose(a, axes=None) 其中:

a:数组。 axis:该值默认为 none,表示转置。如果有值,那么则按照值替换轴。 举个例子:

import numpy as np

a = np.arange(4).reshape(2,2) np.transpose(a)

2.6 维度改变

atleast_xd 支持将输入数据直接视为 x维。这里的 x 可以表示:1,2,3。方法分别维:

numpy.atleast_1d() numpy.atleast_2d() numpy.atleast_3d() 举个例子:

import numpy as np

np.atleast_1d([1]) np.atleast_2d([1]) np.atleast_3d([1])

2.7 类型转变

在 numpy 中,还有一系列以 as 开头的方法,它们可以将特定输入转换为数组,亦可将数组转换为矩阵、标量,ndarray 等。如下:

asarray(a,dtype,order):将特定输入转换为数组。 asanyarray(a,dtype,order):将特定输入转换为 ndarray。 asmatrix(data,dtype):将特定输入转换为矩阵。 asfarray(a,dtype):将特定输入转换为 float 类型的数组。 asarray_chkfinite(a,dtype,order):将特定输入转换为数组,检查 NaN 或 infs。 asscalar(a):将大小为 1 的数组转换为标量。 这里以 asmatrix(data,dtype) 方法举例:

import numpy as np

a = np.arange(4).reshape(2,2) np.asmatrix(a)

2.8 数组连接

concatenate 可以将多个数组沿指定轴连接在一起。其方法为:

numpy.concatenate((a1, a2, ...), axis=0) 其中:

(a1, a2, ...):需要连接的数组。 axis:指定连接轴。 举个例子:

import numpy as np

a = np.array([[1, 2], [3, 4], [5, 6]]) b = np.array([[7, 8], [9, 10]]) c = np.array([[11, 12]])

np.concatenate((a, b, c), axis=0)

这里,我们可以尝试沿着横轴连接。但要保证连接处的维数一致,所以这里用到了 .T 转置。

a = np.array([[1, 2], [3, 4], [5, 6]]) b = np.array([[7, 8, 9]])

np.concatenate((a, b.T), axis=1)

2.9 数组堆叠

在 numpy 中,还有一系列以 as 开头的方法,它们可以将特定输入转换为数组,亦可将数组转换为矩阵、标量,ndarray 等。如下:

stack(arrays,axis):沿着新轴连接数组的序列。 column_stack():将 1 维数组作为列堆叠到 2 维数组中。 hstack():按水平方向堆叠数组。 vstack():按垂直方向堆叠数组。 dstack():按深度方向堆叠数组。 这里以 stack(arrays,axis) 方法举例:

import numpy as np

a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) np.stack((a, b))

当然,也可以横着堆叠。

np.stack((a, b), axis=-1)

2.10 拆分

split 及与之相似的一系列方法主要是用于数组的拆分,列举如下:

split(ary,indices_or_sections,axis):将数组拆分为多个子数组。 dsplit(ary,indices_or_sections):按深度方向将数组拆分成多个子数组。 hsplit(ary,indices_or_sections):按水平方向将数组拆分成多个子数组。 vsplit(ary,indices_or_sections):按垂直方向将数组拆分成多个子数组。 下面,我们看一看 split 到底有什么效果:

import numpy as np

a = np.arange(10) np.split(a, 5)

除了 1 维数组,更高维度也是可以直接拆分的。例如,我们可以将下面的数组按行拆分为 2。

import numpy as np

a = np.arange(10).reshape(2,5) np.split(a, 2)

numpy 中还有针对数组元素添加或移除的一些方法。

2.11 删除

delete(arr,obj,axis):沿特定轴删除数组中的子数组。 下面,依次对 4 种方法进行示例,首先是 delete 删除:

import numpy as np

a = np.arange(12).reshape(3,4) np.delete(a, 2, 1) 这里代表沿着横轴,将第 3 列(索引 2)删除。

当然,你也可以沿着纵轴,将第三行删除。

np.delete(a, 2, 0)

2.12 数组插入

insert(arr,obj,values,axis):依据索引在特定轴之前插入值。 再看一看 insert插入, 用法和 delete 很相似,只是需要在第三个参数位置设置需要插入的数组对象:

import numpy as np

a = np.arange(12).reshape(3,4) b = np.arange(4)

np.insert(a, 2, b, 0)

2.13 附加

append(arr,values,axis):将值附加到数组的末尾,并返回 1 维数组。 append 的用法也非常简单。只需要设置好需要附加的值和轴位置就好了。它其实相当于只能在末尾插入的 insert,所以少了一个指定索引的参数。

import numpy as np

a = np.arange(6).reshape(2,3) b = np.arange(3)

np.append(a, b) 注意 append方法返回值,默认是展平状态下的 1 维数组。

2.14 重设尺寸

resize(a,new_shape):对数组尺寸进行重新设定。 resize 就很好理解了,直接举例子吧:

import numpy as np

a = np.arange(10) a.resize(2,5)

你可能会纳闷了,这个 resize 看起来和上面的 reshape 一样呢,都是改变数组原有的形状。

其实,它们是有区别的,区别在于对原数组的影响。reshape 在改变形状时,不会影响原数组,相当于对原数组做了一份拷贝。而 resize 则是对原数组执行操作。

2.15 翻转数组

在 numpy 中,我们还可以对数组进行翻转操作:

fliplr(m):左右翻转数组。 flipud(m):上下翻转数组。 举个例子:

import numpy as np

a = np.arange(16).reshape(4,4) np.fliplr(a) np.flipud(a)

三、Numpy 随机抽样

Numpy 的随机抽样功能非常强大,主要由 numpy.random 模块完成。

首先,我们需要了解如何使用 numpy 也就是生成一些满足基本需求的随机数据。主要由以下一些方法完成:

3.1 numpy.random.rand

numpy.random.rand(d0, d1, ..., dn) 方法的作用为:指定一个数组,并使用 [0, 1) 区间随机数据填充,这些数据均匀分布。

import numpy as np

np.random.rand(2,5)

3.2 numpy.random.randn

numpy.random.randn(d0, d1, ..., dn) 与 numpy.random.rand(d0, d1, ..., dn) 的区别在于,返回的随机数据符合标准正太分布。

import numpy as np

np.random.randn(1,10)

3.3 numpy.random.randint

randint(low, high, size, dtype) 方法将会生成 [low, high) 的随机整数。注意这是一个半开半闭区间。

import numpy as np

np.random.randint(2,5,10)

3.4 numpy.random.random_integers

random_integers(low, high, size) 方法将会生成 [low, high] 的 np.int 类型随机整数。注意这是一个闭区间。

import numpy as np

np.random.random_integers(2,5,10)

3.5 numpy.random.random_sample

random_sample(size) 方法将会在 [0, 1) 区间内生成指定 size 的随机浮点数。

import numpy as np

np.random.random_sample([10])

与 numpy.random.random_sample 类似的方法还有:

numpy.random.random([size]) numpy.random.ranf([size]) numpy.random.sample([size]) 它们 4 个的效果都差不多。

3.6 numpy.random.choice

choice(a, size, replace, p) 方法将会给定的 1 维数组里生成随机数。

import numpy as np

np.random.choice(10,5) 上面的代码将会在 np.arange(10) 中生成 5 个随机数。

3.7 概率密度分布

除了上面介绍的 6 中随机数生成方法,numpy 还提供了大量的满足特定概率密度分布的样本生成方法。它们的使用方法和上面非常相似,这里就不再一一介绍了。列举如下:

numpy.random.beta(a,b,size):从 Beta 分布中生成随机数。 numpy.random.binomial(n, p, size):从二项分布中生成随机数。 numpy.random.chisquare(df,size):从卡方分布中生成随机数。 numpy.random.dirichlet(alpha,size):从 Dirichlet 分布中生成随机数。 numpy.random.exponential(scale,size):从指数分布中生成随机数。 numpy.random.f(dfnum,dfden,size):从 F 分布中生成随机数。 numpy.random.gamma(shape,scale,size):从 Gamma 分布中生成随机数。 numpy.random.geometric(p,size):从几何分布中生成随机数。 numpy.random.gumbel(loc,scale,size):从 Gumbel 分布中生成随机数。 numpy.random.hypergeometric(ngood, nbad, nsample, size):从超几何分布中生成随机数。 numpy.random.laplace(loc,scale,size):从拉普拉斯双指数分布中生成随机数。 numpy.random.logistic(loc,scale,size):从逻辑分布中生成随机数。 numpy.random.lognormal(mean,sigma,size):从对数正态分布中生成随机数。 numpy.random.logseries(p,size):从对数系列分布中生成随机数。 numpy.random.multinomial(n,pvals,size):从多项分布中生成随机数。 numpy.random.multivariate_normal(mean, cov, size):从多变量正态分布绘制随机样本。 numpy.random.negative_binomial(n, p, size):从负二项分布中生成随机数。 numpy.random.noncentral_chisquare(df,nonc,size):从非中心卡方分布中生成随机数。 numpy.random.noncentral_f(dfnum, dfden, nonc, size):从非中心 F 分布中抽取样本。 numpy.random.normal(loc,scale,size):从正态分布绘制随机样本。 numpy.random.pareto(a,size):从具有指定形状的 Pareto II 或 Lomax 分布中生成随机数。 numpy.random.poisson(lam,size):从泊松分布中生成随机数。 numpy.random.power(a,size):从具有正指数 a-1 的功率分布中在 0,1 中生成随机数。 numpy.random.rayleigh(scale,size):从瑞利分布中生成随机数。 numpy.random.standard_cauchy(size):从标准 Cauchy 分布中生成随机数。 numpy.random.standard_exponential(size):从标准指数分布中生成随机数。 numpy.random.standard_gamma(shape,size):从标准 Gamma 分布中生成随机数。 numpy.random.standard_normal(size):从标准正态分布中生成随机数。 numpy.random.standard_t(df,size):从具有 df 自由度的标准学生 t 分布中生成随机数。 numpy.random.triangular(left,mode,right,size):从三角分布中生成随机数。 numpy.random.uniform(low,high,size):从均匀分布中生成随机数。 numpy.random.vonmises(mu,kappa,size):从 von Mises 分布中生成随机数。 numpy.random.wald(mean,scale,size):从 Wald 或反高斯分布中生成随机数。 numpy.random.weibull(a,size):从威布尔分布中生成随机数。 numpy.random.zipf(a,size):从 Zipf 分布中生成随机数。 四、实验总结

mingyun commented 6 years ago

2.1 三角函数

首先, 看一看 numpy 提供的三角函数功能。这些方法有:

numpy.sin(x):三角正弦。 numpy.cos(x):三角余弦。 numpy.tan(x):三角正切。 numpy.arcsin(x):三角反正弦。 numpy.arccos(x):三角反余弦。 numpy.arctan(x):三角反正切。 numpy.hypot(x1,x2):直角三角形求斜边。 numpy.degrees(x):弧度转换为度。 numpy.radians(x):度转换为弧度。 numpy.deg2rad(x):度转换为弧度。 numpy.rad2deg(x):弧度转换为度。 比如,我们可以用上面提到的 numpy.rad2deg(x) 将弧度转换为度。

import numpy as np

np.rad2deg(np.pi)

这些函数非常简单,就不再一一举例了。

2.2 双曲函数

在数学中,双曲函数是一类与常见的三角函数类似的函数。双曲函数经常出现于某些重要的线性微分方程的解中,使用 numpy 计算它们的方法为:

numpy.sinh(x):双曲正弦。 numpy.cosh(x):双曲余弦。 numpy.tanh(x):双曲正切。 numpy.arcsinh(x):反双曲正弦。 numpy.arccosh(x):反双曲余弦。 numpy.arctanh(x):反双曲正切。 2.3 数值修约

数值修约, 又称数字修约, 是指在进行具体的数字运算前, 按照一定的规则确定一致的位数, 然后舍去某些数字后面多余的尾数的过程[via. 维基百科]。比如, 我们常听到的「4 舍 5 入」就属于数值修约中的一种。

numpy.around(a):平均到给定的小数位数。 numpy.round_(a):将数组舍入到给定的小数位数。 numpy.rint(x):修约到最接近的整数。 numpy.fix(x, y):向 0 舍入到最接近的整数。 numpy.floor(x):返回输入的底部(标量 x 的底部是最大的整数 i)。 numpy.ceil(x):返回输入的上限(标量 x 的底部是最小的整数 i). numpy.trunc(x):返回输入的截断值。 随机选择几个浮点数,看一看上面方法的区别。

import numpy as np

a = np.array([1.21, 2.53, 3.86]) a array([ 1.21, 2.53, 3.86])

np.around(a) array([ 1., 3., 4.])

np.round_(a) array([ 1., 3., 4.])

np.rint(a) array([ 1., 3., 4.])

np.fix(a) array([ 1., 2., 3.])

np.floor(a) array([ 1., 2., 3.])

np.ceil(a) array([ 2., 3., 4.])

np.trunc(a) array([ 1., 2., 3.]) 2.4 求和、求积、差分

下面这些方法用于数组内元素或数组间进行求和、求积以及进行差分。

numpy.prod(a, axis, dtype, keepdims):返回指定轴上的数组元素的乘积。 numpy.sum(a, axis, dtype, keepdims):返回指定轴上的数组元素的总和。 numpy.nanprod(a, axis, dtype, keepdims):返回指定轴上的数组元素的乘积, 将 NaN 视作 1。 numpy.nansum(a, axis, dtype, keepdims):返回指定轴上的数组元素的总和, 将 NaN 视作 0。 numpy.cumprod(a, axis, dtype):返回沿给定轴的元素的累积乘积。 numpy.cumsum(a, axis, dtype):返回沿给定轴的元素的累积总和。 numpy.nancumprod(a, axis, dtype):返回沿给定轴的元素的累积乘积, 将 NaN 视作 1。 numpy.nancumsum(a, axis, dtype):返回沿给定轴的元素的累积总和, 将 NaN 视作 0。 numpy.diff(a, n, axis):计算沿指定轴的第 n 个离散差分。 numpy.ediff1d(ary, to_end, to_begin):数组的连续元素之间的差异。 numpy.gradient(f):返回 N 维数组的梯度。 numpy.cross(a, b, axisa, axisb, axisc, axis):返回两个(数组)向量的叉积。 numpy.trapz(y, x, dx, axis):使用复合梯形规则沿给定轴积分。 下面,我们选取几个举例测试一下:

import numpy as np a=np.arange(5) a array([0, 1, 2, 3, 4])

np.prod(a) # 所有元素乘积 0

np.sum(a) # 所有元素和 10

np.nanprod(a) # 默认轴上所有元素乘积 0

np.nansum(a) # 默认轴上所有元素和 10

np.cumprod(a) # 默认轴上元素的累积乘积。 array([0, 0, 0, 0, 0])

np.diff(a) # 默认轴上元素差分。 array([1, 1, 1, 1]) 2.5 指数和对数

如果你需要进行指数或者对数求解,可以用到以下这些方法。

numpy.exp(x):计算输入数组中所有元素的指数。 numpy.expm1(x):对数组中的所有元素计算 exp(x) - 1. numpy.exp2(x):对于输入数组中的所有 p, 计算 2 p。 numpy.log(x):计算自然对数。 numpy.log10(x):计算常用对数。 numpy.log2(x):计算二进制对数。 numpy.log1p(x):log(1 + x)。 numpy.logaddexp(x1, x2):log2(2x1 + 2**x2)。 numpy.logaddexp2(x1, x2):log(exp(x1) + exp(x2))。 2.6 算术运算

当然,numpy 也提供了一些用于算术运算的方法,使用起来会比 python 提供的运算符灵活一些,主要是可以直接针对数组。

numpy.add(x1, x2):对应元素相加。 numpy.reciprocal(x):求倒数 1/x。 numpy.negative(x):求对应负数。 numpy.multiply(x1, x2):求解乘法。 numpy.divide(x1, x2):相除 x1/x2。 numpy.power(x1, x2):类似于 x1^x2。 numpy.subtract(x1, x2):减法。 numpy.fmod(x1, x2):返回除法的元素余项。 numpy.mod(x1, x2):返回余项。 numpy.modf(x1):返回数组的小数和整数部分。 numpy.remainder(x1, x2):返回除法余数。

import numpy as np

a1 = np.random.randint(0, 10, 5) a2 = np.random.randint(0, 10, 5)

a1 array([3, 7, 8, 0, 0])

a2 array([1, 8, 6, 4, 4])

np.add(a1, a2) array([ 4, 15, 14, 4, 4])

np.reciprocal(a1) array([0, 0, 0, , ])

np.negative(a1) array([-3, -7, -8, 0, 0])

np.multiply(a1, a2) array([ 3, 56, 48, 0, 0])

np.divide(a1, a2) array([3, 0, 1, 0, 0])

np.power(a1, a2) array([3,5764801,262144,0,0])

np.subtract(a1, a2) array([ 2, -1, 2, -4, -4])

np.fmod(a1, a2) array([0, 7, 2, 0, 0])

np.mod(a1, a2) array([0, 7, 2, 0, 0])

np.modf(a1) (array([ 0., 0., 0., 0., 0.]), array([ 3., 7., 8., 0., 0.]))

np.remainder(a1, a2) array([0, 7, 2, 0, 0])

2.7 矩阵和向量积

求解向量、矩阵、张量的点积等同样是 numpy 非常强大的地方。

numpy.dot(a,b):求解两个数组的点积。 numpy.vdot(a,b):求解两个向量的点积。 numpy.inner(a,b):求解两个数组的内积。 numpy.outer(a,b):求解两个向量的外积。 numpy.matmul(a,b):求解两个数组的矩阵乘积。 numpy.tensordot(a,b):求解张量点积。 numpy.kron(a,b):计算 Kronecker 乘积。 2.8 其他

除了上面这些归好类别的方法,numpy 中还有一些用于数学运算的方法,归纳如下:

numpy.angle(z, deg):返回复参数的角度。 numpy.real(val):返回数组元素的实部。 numpy.imag(val):返回数组元素的虚部。 numpy.conj(x):按元素方式返回共轭复数。 numpy.convolve(a, v, mode):返回线性卷积。 numpy.sqrt(x):平方根。 numpy.cbrt(x):立方根。 numpy.square(x):平方。 numpy.absolute(x):绝对值, 可求解复数。 numpy.fabs(x):绝对值。 numpy.sign(x):符号函数。 numpy.maximum(x1, x2):最大值。 numpy.minimum(x1, x2):最小值。 numpy.nan_to_num(x):用 0 替换 NaN。 numpy.interp(x, xp, fp, left, right, period):线性插值。 三、代数运算

上面,我们分为 8 个类别,介绍了 numpy 中常用到的数学函数。这些方法让复杂的计算过程表达更为简单。除此之外,numpy 中还包含一些代数运算的方法,尤其是涉及到矩阵的计算方法,求解特征值、特征向量、逆矩阵等,非常方便。

numpy.linalg.cholesky(a):Cholesky 分解。 numpy.linalg.qr(a ,mode):计算矩阵的 QR 因式分解。 numpy.linalg.svd(a ,full_matrices,compute_uv):奇异值分解。 numpy.linalg.eig(a):计算正方形数组的特征值和右特征向量。 numpy.linalg.eigh(a, UPLO):返回 Hermitian 或对称矩阵的特征值和特征向量。 numpy.linalg.eigvals(a):计算矩阵的特征值。 numpy.linalg.eigvalsh(a, UPLO):计算 Hermitian 或真实对称矩阵的特征值。 numpy.linalg.norm(x ,ord,axis,keepdims):计算矩阵或向量范数。 numpy.linalg.cond(x ,p):计算矩阵的条件数。 numpy.linalg.det(a):计算数组的行列式。 numpy.linalg.matrix_rank(M ,tol):使用奇异值分解方法返回秩。 numpy.linalg.slogdet(a):计算数组的行列式的符号和自然对数。 numpy.trace(a ,offset,axis1,axis2,dtype,out):沿数组的对角线返回总和。 numpy.linalg.solve(a,b):求解线性矩阵方程或线性标量方程组。 numpy.linalg.tensorsolve(a,b ,axes):为 x 解出张量方程a x = b numpy.linalg.lstsq(a,b ,rcond):将最小二乘解返回到线性矩阵方程。 numpy.linalg.inv(a):计算逆矩阵。 numpy.linalg.pinv(a ,rcond):计算矩阵的(Moore-Penrose)伪逆。 numpy.linalg.tensorinv(a ,ind):计算N维数组的逆。

我们可以通过索引值(从 0 开始)来访问 Ndarray 中的特定位置元素。Numpy 中的索引和 python 对 list 索引的方式非常相似,但又有所不同。我们一起来看一下:

首先是,一维数据索引:

import numpy as np

a = np.arange(10) a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

获取索引值为 1 的数据

a[1] 1

分别获取索引值为 1,2,3 的数据

a[[1, 2, 3]] array([1, 2, 3]) 对于二维数据而言:

import numpy as np

a = np.arange(20).reshape(4,5)

a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]])

获取第 2 行,第 3 列的数据

a[1,2] 7 如果,我们使用 python 中的 list 索引同样的值,看看有什么区别:

创建一个数据相同的 list

a = [[ 0, 1, 2, 3, 4],[ 5, 6, 7, 8, 9],[10, 11, 12, 13, 14],[15, 16, 17, 18, 19]]

按照上面的方法获取第 2 行,第 3 列的数据,报错。

a[1,2] Traceback (most recent call last): File "", line 1, in TypeError: list indices must be integers or slices, not tuple

python 中 list 索引 2 维数据的方法

a[1][2] 7 如何索引二维 Ndarray 中的多个元素值,这里使用逗号,分割:

import numpy as np

a = np.arange(20).reshape(4,5)

a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]])

索引

a[[1,2],[3,4]] array([ 8, 14]) 这里需要注意索引的对应关系。我们实际获取的是[1,3],也就是第2行和第4列对于的值8。以及[2, 4],也就是第3行和第5列对于的值14。

那么,三维数据呢?

import numpy as np

a = np.arange(30).reshape(2,5,3) a array([[[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14]],

   [[15, 16, 17],
    [18, 19, 20],
    [21, 22, 23],
    [24, 25, 26],
    [27, 28, 29]]])

索引

a[[0,1],[1,2],[1,2]] array([ 4, 23]) 这里,[0,1]分布代表 axis = 0 和 axis = 1。而,后面的[1,2],[1,2] 分别选择了第 2 行第2 列和第 3 行第3 列的两个数。

2.2 数组切片

Numpy 里面针对Ndarray的数组切片和 python 里的list 切片操作是一样的。其语法为:

Ndarray[start:stop:step] start:stop:step 分布代表起始索引:截至索引:步长。对于一维数组:

import numpy as np

a = np.arange(10) a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

a[:5] array([0, 1, 2, 3, 4])

a[5:10] array([5, 6, 7, 8, 9])

a[0:10:2] array([0, 2, 4, 6, 8]) 对于多维数组,我们只需要用逗号,分割不同维度即可:

import numpy as np

a = np.arange(20).reshape(4,5)

a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]])

先取第 3,4 列(第一个维度),再取第 1,2,3 行(第二个维度)。

a[0:3,2:4] array([[ 2, 3], [ 7, 8], [12, 13]])

按步长为 2 取所有列和所有行的数据。

a[:,::2] array([[ 0, 2, 4], [ 5, 7, 9], [10, 12, 14], [15, 17, 19]]) 当超过 3 维或更多维时,用 2 维数据的切片方式类推即可。

2.3 索引与切片区别

你可能有点疑问,上面的索引和切片怎么看起来这么相似呢?

它们的语法的确很相似,但实际上有区别:

  1. 修改切片中的内容会影响原始数组。

import numpy as np

a = np.arange(10) a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

a[1] = 100

a array([0, 100, 2, 3, 4, 5, 6, 7, 8, 9]) 除此之外,切片只能通过步长控制得到连续的值,而索引可以得到任意值。也就是说,索引的自由度更大。

三、排序、搜索、计数

最后,再介绍几个 numpy 针对数组元素的使用方法,分别是排序、搜索和计数。

3.1 排序

我们可以使用 numpy.sort方法对多维数组元素进行排序。其方法为:

numpy.sort(a, axis=-1, kind='quicksort', order=None) 其中:

a:数组。 axis:要排序的轴。如果为None,则在排序之前将数组铺平。默认值为 -1,沿最后一个轴排序。 kind:{'quicksort','mergesort','heapsort'},排序算法。默认值为 quicksort。 举个例子:

import numpy as np

a = np.random.rand(20).reshape(4,5) a array([[ 0.32930243, 0.63665893, 0.67589989, 0.05413352, 0.26090526], [ 0.6996066 , 0.66006238, 0.88240934, 0.17563549, 0.03015105], [ 0.79075184, 0.40115859, 0.39336513, 0.64691791, 0.96333534], [ 0.20052738, 0.46157057, 0.48653336, 0.34537645, 0.54597273]])

np.sort(a) array([[ 0.05413352, 0.26090526, 0.32930243, 0.63665893, 0.67589989], [ 0.03015105, 0.17563549, 0.66006238, 0.6996066 , 0.88240934], [ 0.39336513, 0.40115859, 0.64691791, 0.79075184, 0.96333534], [ 0.20052738, 0.34537645, 0.46157057, 0.48653336, 0.54597273]]) 除了 numpy.sort,还有这样一些对数组进行排序的方法:

numpy.lexsort(keys ,axis):使用多个键进行间接排序。 numpy.argsort(a ,axis,kind,order):沿给定轴执行间接排序。 numpy.msort(a):沿第 1 个轴排序。 numpy.sort_complex(a):针对复数排序。 3.2 搜索和计数

除了排序,我们可以通过下面这些方法对数组中元素进行搜索和计数。列举如下:

argmax(a ,axis,out):返回数组中指定轴的最大值的索引。 nanargmax(a ,axis):返回数组中指定轴的最大值的索引,忽略 NaN。 argmin(a ,axis,out):返回数组中指定轴的最小值的索引。 nanargmin(a ,axis):返回数组中指定轴的最小值的索引,忽略 NaN。 argwhere(a):返回数组中非 0 元素的索引,按元素分组。 nonzero(a):返回数组中非 0 元素的索引。 flatnonzero(a):返回数组中非 0 元素的索引,并铺平。 where(条件,x,y):根据指定条件,从指定行、列返回元素。 searchsorted(a,v ,side,sorter):查找要插入元素以维持顺序的索引。 extract(condition,arr):返回满足某些条件的数组的元素。 count_nonzero(a):计算数组中非 0 元素的数量。 选取其中的一些方法举例:

import numpy as np a = np.random.randint(0,10,20)

a array([3, 2, 0, 4, 3, 1, 5, 8, 4, 6, 4, 5, 4, 2, 6, 6, 4, 9, 8, 9])

np.argmax(a) 17

np.nanargmax(a) 17

np.argmin(a) 2

np.nanargmin(a) 2

np.argwhere(a) array([[ 0],[ 1],[ 3],[ 4],[ 5],[ 6],[ 7],[ 8],[ 9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19]], dtype=int64)

np.nonzero(a) (array([ 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], dtype=int64),)

np.flatnonzero(a) array([ 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], dtype=int64)

np.count_nonzero(a) 19

mingyun commented 6 years ago

一维数据 Series

Series 是 Pandas 中最基本的 1 维数据形式。其可以储存整数、浮点数、字符串等形式的数据。Series 的新建方法如下:

s = pandas.Series(data, index=index) 其中,data 可以是字典、numpy 里的 ndarray 对象等。index 是数据索引,索引是 pandas 数据结构中的一大特性,它主要的功能是帮助我们更快速地定位数据,这一点后面会谈到。

3.1 字典 -> Series

下面,我们将把不同类型的数据转换为为 Series。首先是字典类型。

import pandas as pd

d = {'a' : 10, 'b' : 20, 'c' : 30} print pd.Series(d)

这里,数据值是 10, 20, 30,索引为 a, b, c 。我们可以直接通过 index= 参数来设置新的索引。

import pandas as pd d = {'a' : 10, 'b' : 20, 'c' : 30}

s = pd.Series(d, index=['b', 'c', 'd', 'a']) print s

你会发现,pandas 会自动匹配人为设定的索引值和字典转换过来的索引值。而当索引无对应值时,会显示为 NaN 缺失值。

3.2 ndarray -> Series

ndarray 是著名数值计算包 numpy 中的多维数组。我们也可以将 ndarray 直接转换为 Series。

import pandas as pd import numpy as np

data = np.random.randn(5) # 一维随机数 index = ['a', 'b', 'c', 'd', 'e'] # 指定索引

s = pd.Series(data, index) print s

上面的两个例子中,我们都指定了 index 的值。而当我们非人为指定索引值时,Pandas 会默认从 0 开始设置索引值。

s = pd.Series(data) print s

当我们需要从一维数据 Series 中返回某一个值时,可以直接通过索引完成。

import pandas as pd import numpy as np

data = np.random.randn(5) # 一维随机数 index = ['a', 'b', 'c', 'd', 'e'] # 指定索引

s = pd.Series(data, index) print s print s['a']

除此之外,Series 是可以直接进行运算的。例如:

import pandas as pd import numpy as np

data = np.random.randn(5) # 一维随机数 index = ['a', 'b', 'c', 'd', 'e'] # 指定索引

s = pd.Series(data, index) print s print 2*s print s-s

四、二维数据 DataFrame

DataFrame 是 Pandas 中最为常见、最重要且使用频率最高的数据结构。你可以想到它箱型为电子表格或 SQL 表具有的结构。DataFrame 可以被看成是以 Series 组成的字典。它和 Series 的区别在于,不但具有行索引,且具有列索引。

DataFrame 可以用于储存多种类型的输入:

一维数组、列表、字典或者 Series 字典。 二维 numpy.ndarray。 结构化的 ndarray。 一个 Series。 另一个 DataFrame。 4.1 Series 字典 -> DataFrame

import pandas as pd

带 Series 的字典

d = {'one' : pd.Series([1., 2., 3.], index=['a', 'b', 'c']),'two' : pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}

df = pd.DataFrame(d) # 新建 DataFrame print df

我们可以看到,这里的行索引为 a, b, c, d ,而列索引为 one, two。

4.2 ndarrays 或 lists 字典 -> DataFrame

import pandas as pd

列表构成的字典

d = {'one' : [1, 2, 3, 4], 'two' : [4, 3, 2, 1]}

df1 = pd.DataFrame(d) # 未指定索引 df2 = pd.DataFrame(d, index=['a', 'b', 'c', 'd']) # 指定索引

print df1 print df2

注意观察它们之间的不同。

4.3 带字典的列表 -> DataFrame

import pandas as pd

带字典的列表

d = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]

df = pd.DataFrame(d)

print df

4.4 DataFrame.from_ 方法

pandas 的 DataFrame 下面还有 4 个以 from_ 开头的方法,这也可以用来创建 Dataframe。

例如:

import pandas as pd

d = [('A', [1, 2, 3]), ('B', [4, 5, 6])] c = ['one', 'two', 'three']

df = pd.DataFrame.from_items(d, orient='index', columns=c)

print df

4.5 列选择,添加,删除

接下来,我们延续上面的 4.4 里面的数据来演示。

在一维数据结构 Series 中,我们用 df['标签'] 来选择行。而到了二维数据 DataFrame 中,df['标签'] 表示选择列了。例如:

print df['one']

删除列的方法为 df.pop('列索引名'),例如:

df.pop('one') print df

添加列的方法未 df.insert(添加列位置索引序号, '添加列名', 数值),例如:

df.insert(3, 'four', [10, 20]) print df

五、三维数据 Panel

Panel 是 Pandas 中使用频率较低的一种数据结构,但它是三维数据的重要容器。

5.1 面板数据

Panel data 又称面板数据,它是计量经济学中派生出来的一个概念。在计量经济学中,数据大致可分为三类:截面数据,时间序列数据,以及面板数据。而面板数据即是截面数据与时间序列数据综合起来的一种数据类型。

简单来讲,截面数据指在某一时间点收集的不同对象的数据。而时间序列数据是指同一对象在不同时间点所对应的数据集合。

这里引用一个城市和 GDP 关系的示例来解释上面的三个概念(面板数据):

截面数据:

例如城市:北京、上海、重庆、天津在某一年的 GDP 分别为10、11、9、8(单位亿元)。 时间序列数据:

例如:2000、2001、2002、2003、2004 各年的北京市 GDP 分别为8、9、10、11、12(单位亿元)。 面板数据:

2000、2001、2002、2003、2004 各年中国所有直辖市的 GDP 分别为(单位亿元): 北京市分别为 8、9、10、11、12; 上海市分别为 9、10、11、12、13; 天津市分别为 5、6、7、8、9; 重庆市分别为 7、8、9、10、11。 5.2 Panel 构成

在 Pandas 中,Panel 主要由三个要素构成:

items: 每个项目(item)对应于内部包含的 DataFrame。 major_axis: 每个 DataFrame 的索引(行)。 minor_axis: 每个 DataFrame 的索引列。 简而言之,在 Pandas 中,一个 Panel 由多个 DataFrame 组成。下面就生成一个 Panel。

import pandas as pd import numpy as np

wp = pd.Panel(np.random.randn(2, 5, 4), items=['Item1', 'Item2'], major_axis=pd.date_range('1/1/2000', periods=5), minor_axis=['A', 'B', 'C', 'D'])

print wp

我们可以看到,wp 由 2 个项目、5 个主要轴和 4 个次要轴组成。其中,主要轴由 2000-01-01 到 2000-01-05 这 5 天组成的时间序列,次轴从 A 到 D。

你可以输出 Item1 看一看。

print wp['Item1']

再看一看 Item2。

print wp['Item2]

可以看到,这两个 Dataframe 的行索引及列索引是一致的。由于数据是随机生成的,所以不一致。

5.2 Panel 的未来

由于 Panel 在 Pandas 中的使用频率远低于 Series 和 DataFrame,所以 Pandas 决定在未来的版本中将 Panel 移除,转而使用 MultiIndex DataFrame 来表示多维数据结构。

这里,可以用到 Panel.to_frame() 输出多维数据结构。就拿上面的例子继续:

print wp.to_frame()

Pandas 支持大部分常见数据文件读取与存储。一般清楚下,读取文件的方法以 pd.read 开头,而写入文件的方法以 pd.to 开头。详细的表格如下。

拿刚刚下载好的数据文件举例,如果没有下载,请看 1.5 小节。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件 print df

可以看到,文件已经读取出来了。由于列数太多,所以分段显示了。输出的最下方会有一个行数和列数的统计。这里是 319 行 X 7 列。

我们可以发现,由 pandas 读取的文件就已经是 DataFrame 结构了。上面演示了 csv 文件的读取,其余格式的文件也很相似。

不过,很多时候我们拿到手的数据是像 los_census.txt 文件样式的数据,如下图所示。

import pandas as pd

df = pd.read_table("los_census.txt") #读取 txt 文件 print df

其实 los_census.txt 也就是 los_census.csv 文件,因为 csv 文件又叫逗号分隔符文件,数据之间采用逗号分割。

那么,我们怎样将这种文件转换为 DataFrame 结构的数据呢?这里就要使用到读取方法中提供的一些参数了,例如 sep[] 分隔符参数。

import pandas as pd

df = pd.read_table("los_census.txt", sep=',') #读取 txt 文件 print df

除了 sep,读取文件时常用的参数还有:

header=,用来选择将第几行作为列索引名称。 names=[],自定义列索引名称。 例如:

import pandas as pd

df = pd.read_csv("los_census.csv", header=1 ) #将第二行作为列索引名称。 print df

import pandas as pd

df = pd.read_csv("los_census.csv", names=['A', 'B', 'C', 'D', 'E', 'F', 'G']) #自定义列索引名称。 print df

好了,说了这么久的读取文件,再说一说存储文件。存储文件的方法也很简单。比如我们将 los_census.csv 文件,存储为 json 格式的文件。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件

df.to_json("1.json") # 将其存储为 json 格式文件

当然,你也可以通过 to_excel("1.xlsx") 储存为 Excel 默认支持的 .xlsx 格式。只是,需要注意在线环境会报错。这时候需要再补充安装 openpyxl 包就好了:

sudo pip install openpyxl 2.2 Head & Tail

有些时候,我们读取的文件很大。如果全部输出预览这些文件,既不美观,又很耗时。还好,Pandas 提供了 head() 和 tail() 方法,它可以帮助我们只预览一小块数据。

顾名思义,head() 方法就是从数据集开头预览,不带参数默认显示头部的 5 条数据,你也可以自定义显示条数。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件

print df.head() # 默认显示前 5 条 print df.head(7) # 显示前 7 条

tail() 方法就是从数据集尾部开始显示了,同样默认 5 条,可自定义。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件

print df.tail() # 默认显示后 5 条 print df.tail(7) # 显示后 7 条

2.3 统计方法

Pandas 提供了几个统计和描述性方法,方便你从宏观的角度去了解数据集。

  1. describe()

describe() 相当于对数据集进行概览,会输出该数据集的计数、最大值、最小值等。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件

print df.describe()

例如上面,针对一个 DataFrame 会对每一列的数据单独统计。

  1. idxmin() & idxmax()

idxmin() 和 idxmax() 会计算最小、最大值对应的索引标签。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件

print df.idxmin() print df.idxmax()

  1. count()

count() 用于统计非空数据的数量。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件

print df.count()

4.value_counts()

value_counts() 仅仅针对 Series,它会计算每一个值对应的数量统计。

import pandas as pd import numpy as np

s = pd.Series(np.random.randint(0, 9, size=100)) # 生成一个 Series,并在 0-9 之间生成 100 个随机值。

print s print s.value_counts()

2.4 计算方法

除了统计类的方法,Pandas 还提供了很多计算类的方法。

  1. sum()

sum() 用于计算数值数据的总和。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件

print df.sum()

  1. mean()

mean() 用于计算数值数据的平均值。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件

print df.mean()

  1. median()

median() 用于计算数值数据的算术中值。

import pandas as pd

df = pd.read_csv("los_census.csv") #读取 csv 文件

print df.median()

除此之外,剩下的一些常见计算方法如下表所示。

2.5 标签对齐

索引标签是 Pandas 中非常重要的特性,有些时候,由于数据的缺失等各种因素导致标签错位的现象,或者想匹配新的标签。于是 Pandas 提供了索引标签对齐的方法 reindex()。

reindex() 主要有三个作用:

重新排序现有数据以匹配新的一组标签。 在没有标签对应数据的位置插入缺失值(NaN)标记。 特殊情形下,使用逻辑填充缺少标签的数据(与时间序列数据高度相关)。 import pandas as pd

s = pd.Series(data=[1, 2, 3, 4, 5], index=['a', 'b', 'c', 'd', 'e'])

print s print s.reindex(['e', 'b', 'f', 'd'])

我们可以看到,重新排列的数据中,原有索引对应的数据能自动匹配,而新索引缺失的数据通过 NaN 补全。

当然,对于 DataFrame 类型的数据也是一样的。

import pandas as pd

df = pd.DataFrame(data={'one': [1, 2, 3], 'two': [4, 5, 6], 'three': [7, 8, 9]}, index=['a', 'b', 'c'])

print df

print df.reindex(index=['b', 'c', 'a'], columns=['three', 'two', 'one'])

你甚至还可以将上面 Series 的数据按照下面的 DataFrame 的索引序列对齐。

print s.reindex(df.index)

2.6 排序

既然是数据处理,就少不了排序这一常用的操作。在 Pandas 中,排序拥有很多「姿势」,下面就一起来看一看。

  1. 按索引排序

首先是按照索引排序,其方法为Series.sort_index()或者是DataFrame.sort_index()。

import pandas as pd

df = pd.DataFrame(data={'one': [1, 2, 3], 'two': [4, 5, 6], 'three': [7, 8, 9], 'four': [10, 11, 12]}, index=['a', 'c', 'b'])

print df

下面按索引对行重新排序:

print df.sort_index()

或者添加参数,进行倒序排列:

print df.sort_index(ascending=False)

  1. 按数值排序

第二种是按照数值排序,其方法为Series.sort_values()或者是DataFrame.sort_values()。举个例子:

import pandas as pd

df = pd.DataFrame(data={'one': [1, 2, 3, 7], 'two': [4, 5, 6, 9], 'three': [7, 8, 9, 2], 'four': [10, 11, 12, 5]}, index=['a', 'c', 'b','d'])

print df

将第三列按照从小到大排序:

print df.sort_values(by='three')

也可以同时按照两列:

print df[['one', 'two', 'three', 'four']].sort_values(by=['one','two'])

mingyun commented 6 years ago

基于索引数字选择

当我们新建一个 DataFrame 之后,如果未自己指定行索引或者列对应的标签,那么 Pandas 会默认从 0 开始以数字的形式作为行索引,并以数据集的第一行作为列对应的标签。其实,这里的「列」也有数字索引,默认也是从 0 开始,只是未显示出来。

所以,我们首先可以基于数字索引对数据集进行选择。这里用到的 Pandas 中的 .iloc 方法。该方法可以接受的类型有:

整数。例如:5 整数构成的列表或数组。例如:[1, 2, 3] 布尔数组。 可返回索引值的函数或参数。 下面,我们还是用 los_census.csv 数据集演示该方法的使用。如果未下载该数据集,请看 1.5 节。

import pandas as pd

df = pd.read_csv("los_census.csv")

print df.head()

首先,我们可以选择前 3 行数据。这和 python 或者 numpy 里面的切片很相似。

print df.iloc[:3]

我们还可以选择特定的一行。

print df.iloc[5]

那么选择多行是不是 print df.iloc[1, 3, 5] 这样呢?答案是错误的。df.iloc[] 的 [[行],[列]] 里面可以同时接受行和列的位置,如果你直接键入 df.iloc[1, 3, 5] 就会报错。

所以,很简单。如果你想要选择 1,3,5 行,可以这样做。

print df.iloc[[1, 3, 5]]

选择行学会以后,选择列就应该能想到怎么办了。你可以先暂停浏览下面的内容,自己试一试。

例如,我们要选择第 2-4 列。

print df.iloc[:, 1:4]

这里选择 2-4 列,输入的却是 1:4。这和 python 或者 numpy 里面的切片操作非常相似。

既然我们能定位行和列,那么只需要组合起来,我们就可以选择数据集中的任何一块数据了。

2.2 基于标签名称选择

除了根据数字索引选择,我们还可以直接根据标签对应的名称选择。这里用到的方法和上面的 iloc 很相似,少了个 i 为 df.loc[]。

df.loc[] 可以接受的类型有:

单个标签。例如:2 或 'a',这里的 2 指的是标签而不是索引位置。 列表或数组包含的标签。例如:['A', 'B', 'C']。 切片对象。例如:'A':'E',注意这里和上面切片的不同支持,首位都包含在内。 布尔数组。 可返回标签的函数或参数。 下面,我们来演示 df.loc[] 的用法。我们先随机生成一个 DataFrame。

import pandas as pd import numpy as np # 加载 numpy 模块

df = pd.DataFrame(np.random.randn(6,5),index=list('abcdef'),columns=list('ABCDE'))

print df

先选择前 3 行:

print df.loc['a':'c']

再选择 1,3,5 行:

print df.loc[['a', 'c', 'd']]

然后,选择 2-4 列:

print df.loc[:, 'B':'D']

最后,选择 1,3 行和 C 后面的列:

print df.loc[['a','c'], 'C':]

2.3 数据随机取样

上面,的 .iloc 和 .loc 可用于精准定位数据块。而 Pandas 同样也提供了随机取样的方法,用于满足各种情况。随机取样用 .sample() 完成,下面我们就演示一下它的用法。

首先,看一看 Series 数据结构。

import pandas as pd

s = pd.Series([0,1,2,3,4,5,6,7,8,9])

print s.sample()

我们可以看到,默认情况下 .sample() 返回了一个数值。注意,前面的 2 是数字索引,后面的 2 才是值。

我们可以通过 n= 参数,设定返回值的数量。

print s.sample(n=5)

同样也可以用 frac= 参数设定返回数量的比例。

print s.sample(frac=.6) # 返回 60% 的数值

对应 DataFrame 而言,过程也很相似,只是需要选择坐标轴。举个例子:

import pandas as pd import numpy as np

df = pd.DataFrame(np.random.randn(6,5),index=list('abcdef'),columns=list('ABCDE'))

print df print df.sample(n=3)

默认会返回行,如果要随机返回 3 列。需要添加 axis= 参数。

print df.sample(n=3, axis=1)

2.4 条件语句选择

数据选择的时候,我们还可以加入一些条件语句,从而达到对数据筛选的目的。这个过程和 numpy 里面的效果很相似。我们先举一个 Series 的例子:

import pandas as pd

s = pd.Series(range(-5, 5))

print s print s[(s < -2) | (s > 1)] # 添加 逻辑或 条件

对于 DataFrame 也是相似的。

import pandas as pd import numpy as np

df = pd.DataFrame(np.random.randn(6,5),index=list('abcdef'),columns=list('ABCDE'))

print df print df[(df['B'] > 0) | (df['D'] < 0)] # 添加条件

2.5 where() 方法选择

接下来,再介绍一种通过 where() 方法进行数据选择得方法。DataFrame 和 Series 都带有 where(),可以通过一些判断句来选择数据。举个例子:

import pandas as pd import numpy as np

df = pd.DataFrame(np.random.randn(6,5),index=list('abcdef'),columns=list('ABCDE'))

print df print df.where(df < 0) # 添加条件 .where(df < 0) 会返回所有负值,而非负值就会被置为空值 NaN。

你也可以对判断条件以外得值重新替代,例如这里将非负值全部变号为负值。

print df.where(df < 0, -df) # 筛选负值并将正值变号

故,where() 实际上期待了匹配和替换得效果。我们可以借助该方法实现对数据的自由设定。

2.6 query() 方法选择

针对数据变换和筛选的方法还很多,除了上面的提到的,Pandas 0.13 之后的版本中增加了 query() 实验性方法,该方法也可以被用来选择数据。

query() 是 DataFrame 具有的方法,你可以通过一个比较语句对满足行列条件的值进行选择,举个例子:

import pandas as pd import numpy as np

df = pd.DataFrame(np.random.rand(10, 5), columns=list('abcde'))

print df print df.query('(a < b) & (b < c)') # 添加 逻辑与 条件 上面的判断语句应该很容易看明白,也就是满足 a 列的值需小于 b 列,且 b 列的值小于 c 列所在的行。

当然,在没有 query() 之前,我们也是可以通过前面提到的条件语句选择。

print df[(df.a < df.b) & (df.b < df.c)]

结果虽然一致,但是 query() 语句的确要简洁和自然很多。query() 包含很多内容,非常强大。你可以通过官方文档了解,这里就不再赘述了。

二、认识缺失值

在真实的生产环境中,我们需要处理的数据文件往往没有想象中的那么美好。其中,很大几率会遇到的情况就是缺失值。

2.1 什么是缺失值?

缺失值主要是指数据丢失的现象,也就是数据集中的某一块数据不存在。除此之外、存在但明显不正确的数据也被归为缺失值一类。例如,在一个时间序列数据集中,某一段数据突然发生了时间流错乱,那么这一小块数据就是毫无意义的,可以被归为缺失值。

当然,除了原始数据集就已经存在缺失值以外。当我们用到前面章节中的提到的索引对齐(reindex())的方法时,也容易人为导致缺失值的产生。举个例子:

首先,我们生成一个 DataFrame。

import pandas as pd import numpy as np

df = pd.DataFrame(np.random.rand(5, 5), index=list('cafed'),columns=list('ABCDE'))

print df

然后,我们使用 `reindex() 完成索引对齐。

print df.reindex(list('abcde'))

由于原始数据集中,没有索引 b,所以对齐之后,b 后面全部为缺失值,也就造成了数据缺失。

2.2 检测缺失值

Pandas 为了更方便地检测缺失值,将不同类型数据的缺失均采用 NaN 标记。这里的 NaN 代表 Not a Number,它仅仅是作为一个标记。例外是,在时间序列里,时间戳的丢失采用 NaT 标记。

Pandas 中用于检测缺失值主要用到两个方法,分别是:isnull() 和 notnull(),故名思意就是「是缺失值」和「不是缺失值」。默认会返回布尔值用于判断。

下面,演示一下这两个方法的作用,我们这里沿用上面进行索引对齐后的数据。

df2 = df.reindex(list('abcde'))

df2.isnull() df2.notnull()

然后,我们来看一下对时间序列缺失值的检测,对上面的 df2 数据集进行稍微修改。

插入 T 列,并打上时间戳

df2.insert(value=pd.Timestamp('2017-10-1'),loc=0,column='T')

将 T 列的 1,3,5 行置为缺失值

df2.loc[['a','c','e'],['T']] = np.nan 这里,我们也更清晰看到,时间序列的缺失值用 NaT 标记。我们对 df2 进行缺失值检测。

df2.isnull() df2.notnull()

三、填充和清除缺失值

上面已经对缺省值的产生、检测进行了介绍。那么,我们面对缺失值时,到底有哪些实质性的措施呢?接下来,就来看一看如何完成对缺失值填充和清除。

填充和清除都是两个极端。如果你感觉有必要保留缺失值所在的列或行,那么就需要对缺失值进行填充。如果没有必要保留,就可以选择清除缺失值。

Pandas 中,填充缺失的方法为 fillna(),清除为 dropna()。

3.1 填充缺失值 fillna()

首先,我们看一看 fillna() 的使用方法。重新打开一个 ipython 终端,我们生成和上面相似的数据。

import pandas as pd import numpy as np

df = pd.DataFrame(np.random.rand(9, 5), columns=list('ABCDE'))

插入 T 列,并打上时间戳

df.insert(value=pd.Timestamp('2017-10-1'),loc=0,column='Time')

将 1, 3, 5 列的 1,3,5 行置为缺失值

df.iloc[[1,3,5,7], [0,2,4]] = np.nan

将 2, 4, 6 列的 2,4,6 行置为缺失值

df.iloc[[2,4,6,8], [1,3,5]] = np.nan

我们用相同的标量值替换 NaN,比如用 0。

df.fillna(0)

注意,这里的填充并不会直接覆盖原数据集,你可以重新输出 df 比较结果。

除了直接填充值,我们还可以通过参数,将缺失值前面或者后面的值填充给相应的缺失值。例如使用缺失值前面的值进行填充:

df.fillna(method='pad')

或者是后面的值:

df.fillna(method='bfill')

最后一行由于没有对于的后序值,自然继续存在缺失值。

上面的例子中,我们的缺失值是间隔存在的。那么,如果存在连续的缺失值是怎样的情况呢?试一试。首先,我们将数据集的第 2,4 ,6 列的第 3,5 行也置为缺失值。

df.iloc[[3,5], [1,3,5]] = np.nan

然后来正向填充:

df.fillna(method='pad')

可以看到,连续缺失值也是按照前序数值进行填充的,并且完全填充。这里,我们可以通过 limit= 参数设置连续填充的限制数量。

df.fillna(method='pad', limit=1)

除了上面的填充方式,还可以通过 Pandas 自带的求平均值方法等来填充特定列或行。举个例子:

df.fillna(df.mean()['C':'E']) 对 C 列和 E 列用平均值填充。

3.2 清除缺失值 dropna()

上面演示了缺失值填充。但有些时候,缺失值比较少或者是填充无意义时,就可以直接清除了。

由于填充和清除在赋值之前,均不会影响原有的数据。所以,我们这里依旧延续使用上面的 df。

df.dropna()

我们可以看到,dropna() 方法带来的默认效果就是,凡是存在缺失值的行均被直接移除。此时,dropna() 里面有一个默认参数是 axis=0,代表依据行来移除。

如果我们像将凡是有缺失值的列直接移除,可以将 axis=1,试一试。

df.dropna(axis=1) 由于上面的 df 中,每一列都有缺失值,所以全部被移除了。

四、插值 interpolate()

插值是数值分析中一种方法。简而言之,就是借助于一个函数(线性或非线性),再根据已知数据去求解未知数据的值。插值在数据领域非常常见,它的好处在于,可以尽量去还原数据本身的样子。

Pandas 中的插值,通过 interpolate() 方法完成,默认为线性插值,即 method='linear'。除此之外,还有{‘linear’, ‘time’, ‘index’, ‘values’, ‘nearest’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘barycentric’, ‘krogh’, ‘polynomial’, ‘spline’, ‘piecewise_polynomial’, ‘from_derivatives’, ‘pchip’, ‘akima’}等插值方法可供选择。

举个例子:

import pandas as pd import numpy as np

生成一个 DataFrame

df = pd.DataFrame({'A': [1.1, 2.2, np.nan, 4.5, 5.7, 6.9], 'B': [.21, np.nan, np.nan, 3.1, 11.7, 13.2]})

对于上面存在的缺失值,如果通过前后值,或者平均值来填充是不太能反映出趋势的。这时候,插值最好使。我们用默认的线性插值试一试。

df.interpolate()

如果你熟悉 Matplotlib,我们可以将数据绘制成图看一看趋势。图中,第 2,3 点的坐标是我们插值的结果。

上面提到了许多插值的方法,也就是 method=。下面给出几条选择的建议:

如果你的数据增长速率越来越快,可以选择 method='quadratic'二次插值。 如果数据集呈现出累计分布的样子,推荐选择 method='pchip'。 如果需要填补缺省值,以平滑绘图为目标,推荐选择 method='akima'。 当然,最后提到的 method='akima',需要你的环境中安装了 Scipy 库。除此之外,method='barycentric' 和 method='pchip' 同样也需要 Scipy 才能使用。 Pandas 处理时间序列

接下来,我们就时间序列中常遇到的一些需求类型,列举一些示例,并使用 Pandas 提供的方法进行处理。

3.1 时间戳 Timestamp

既然是时间序列类型的数据,那么就少不了时间戳这一关键元素。Pandas 中,我们有两个创建时间戳的方法,分别是:to_datatime和 Timestamp。

to_datatime 后面集中详说。首先看一看 Timestamp,它针对于单一标量,举个例子:

import pandas as pd

pd.Timestamp('2017-10-01')

如果要包含小时:分钟:秒:

pd.Timestamp('2017-10-01 13:30:59')

当然,还支持其他的格式输入,比如:

pd.Timestamp('1/10/2017 13:30:59')

3.2 时间索引 DatetimeIndex

在实际工作中,我们很少遇到用单个时间戳的情况。而大多数时候,是使用由时间戳构成的时间索引。

首先,我们来看一下如何使用 Pandas 创建时间索引。这里用到的方法为 date_range(),date_range() 和 python 自带的 range() 很相似。它可以用来创建一系列等间距时间,并作为 Series 或者 DataFrame 的索引。

date_range() 方法带有的默认参数如下:

pandas.date_range(start=None, end=None, periods=None, freq=’D’, tz=None, normalize=False, name=None, closed=None, **kwargs) 常用参数的含义如下:

start= :设置起始时间 end=:设置截至时间 periods= :设置时间区间,若 None 则需要设置单独设置起止和截至时间。 freq= :设置间隔周期,默认为 D,也就是天。可以设置为小时、分钟、秒等。 tz=:设置时区。 举个例子:

import pandas as pd

rng1 = pd.date_range('1/10/2017', periods=24, freq='H')

可以这样:

rng2 = pd.date_range('1/10/2017', periods=10, freq='D')

我们可以发现 freq= 参数的特点:

freq='s': 秒 freq='min' : 分钟 freq='H': 小时 freq='D': 天 freq='w': 周 freq='m': 月 除了上面这些参数值,还有一些特别的:

freq='BM': 每个月最后一天 freq='W':每周的星期日 如果你想同时按天、小时更新,也是可以的。但需要像下面这样设置参数值:

rng3 = pd.date_range('1/10/2017', periods=20, freq='1H20min')

所以,只要适当地组合,你可以生成任意想要的时间序列索引。

3.3 时间转换 to_datatime

to_datatime 是 Pandas 用于处理时间序列时的一个重要方法,它可以将实参转换为时间戳。to_datatime 包含的默认参数如下:

pandas.to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=None, box=True, format=None, exact=True, unit=None, infer_datetime_format=False, origin='unix') arg:可以接受整数、浮点数、字符串、时间、列表、元组、一维数组、Series 等。 errors=:默认为 raise,表示遇到无法解析数据将会报错。还可以设置为 coerce,表示无法解析设为 NaT,或者设为 ignore 忽略错误。 dayfirst= :表示首先解析日期,例如:1/10/17 被解析为 2017-10-1。 yearfirst= :表示首先解析年,例如:1/10/17 被解析为 2001-10-17。 utc=:返回 UTC 格式时间索引。 box=:True 表示返回时间索引 DatatimeIndex,False 表示返回多维数组 ndarray。 format= :时间解析格式,例如:%d /%m /%Y。 对于 to_datatime 的返回值而言:

输入列表,默认返回时间索引 DatetimeIndex。 输入 Series,默认返回 datetime64 的 Series。 输入标量,默认返回时间戳 Timestamp。 下面,针对输入数据类型的不同,我们来看一看 to_datatime 的不同用法。

3.3.1 输入标量

import pandas as pd

pd.to_datetime('1/10/2017 10:00', dayfirst=True)

3.3.2 输入列表

pd.to_datetime(['1/10/2017 10:00','2/10/2017 11:00','3/10/2017 12:00'])

3.3.2 输入 Series

pd.to_datetime(pd.Series(['Oct 11, 2017', '2017-10-2', '3/10/2017']), dayfirst=True)

3.3.2 输入 DataFrame

pd.to_datetime(pd.DataFrame({'year': [2017, 2018], 'month': [9, 10], 'day': [1, 2], 'hour': [11, 12]}))

3.3.2 errors=

接下来,看一看 errors= 遇到无法解析的数据时,所对应的不同返回值。这个参数对于我们解析大量数据时非常有用。

pd.to_datetime(['2017/10/1', 'abc'], errors='raise')

pd.to_datetime(['2017/10/1', 'abc'], errors='ignore')

pd.to_datetime(['2017/10/1', 'abc'], errors='coerce')

3.4 时间序列检索

上面,我们介绍了时间索引 DatetimeIndex 的生成方法。那么,它主要是用来做什么呢?

答案当然是 Pandas 对象的索引啦。将时间变成索引的优点非常多,包含但不限于:

查找和检索特定日期的字段非常快。 进行数据对齐时,拥有相同时间间隔的索引的数据将会非常快。 可以很方便地通过 shift 和 ishift 方法快速移动对象。 下面,针对时间序列索引的检索等操作举几个例子。首先,我们生成 10 万条数据:

import pandas as pd import numpy as np

ts = pd.DataFrame(np.random.randn(100000,1), columns=['Value'], index=pd.date_range('20170101', periods=100000, freq='T'))

当我们对数据进行快速检索是,其实和除了 Series 和 DataFrame 数据别无二致。例如:

检索 2017 年 3 月 2 号的数据:

ts['2017-3-2'] 一共 1440 行

检索 2017 年 3 月 3 号下午 2 点到 5 点 23 分之间的数据:

ts['2017-3-2 14:00:00':'2017-3-2 17:23:00'] 一共返回了 204 行

总之,一切在 Series 和 DataFrame 上可以用的数据选择与定位的方法,像 iloc(), loc() 等均可以用于时间序列,这里就不再赘述了。

3.5 时间序列计算

在 Pandas 中,包含有很多可以被加入到时间序列计算中去的类,这些被称为 Offsets 对象。

关于这一点,我们举出几个例子就一目了然了。例如:

import pandas as pd from pandas.tseries import offsets # 载入 offsets

dt = pd.Timestamp('2017-10-1 10:59:59')

dt + offsets.DateOffset(months=1, days=2, hour=3) # 增加时间

又或者我们减去 3 个周的时间:

dt - offsets.Week(3)

看明白了吧。这类的对象非常多,就不再一一演示,通过表格列举如下:

3.6 其他方法

最后,再介绍几个与时间序列处理相关的方法。

移动 Shifting

shifting 可以将数据或者时间索引沿着时间轴的方向前移或后移,举例如下:

import pandas as pd import numpy as np

生成一个时间系列数据集

ts = pd.DataFrame(np.random.randn(7,2), columns=['Value1','Value2' ], index=pd.date_range('20170101', periods=7, freq='T'))

接下来开始移动。

ts.shift(3) 默认是数据向后移动。这里数据值向后移动了 3 行。

ts.shift(-3) 可以通过添加负号,使得向前移动。

那么,想移动索引怎么办?这里使用 tshift()。

ts.tshift(3)

向前移动索引就不再演示了,同样可以通过负号完成。除此之外,shift() 是可以接受一些参数的,比如 freq=''。而这里的 freq='' 参数和上文在介绍 时间索引 DatetimeIndex 时提到的一致。

举个例子:

ts.shift(3, freq='D') # 日期向后移动 3 天

所以说,shifting 可以让我们更加灵活地去操作时间序列数据集,完成数据对齐等目标。

重采样 Resample

重采样,即是将时间序列从一个频率转换到另一个频率的过程。实施重采样的情形如下:

有时候,我们的时间序列数据集非常大,比如百万级别甚至更高。如果将全部数据用于后序计算,其实很多情况下是没有必要的。此时,我们可以对原有的时间序列进行降频采样。 除了上面的情形,重采样还可以被用于数据对齐。比如,两个数据集,但是时间索引的频率不一致,这时候,可以通过重采样使二者频率一致,方便数据合并、计算等操作。 下面,我们看一看 resample() 的使用。首先,还是生成一个数据集。

import pandas as pd import numpy as np

生成一个时间系列数据集

ts = pd.DataFrame(np.random.randn(50,1), columns=['Value' ], index=pd.date_range('2017-01', periods=50, freq='D'))

首先,可以升频采样,间隔变成小时。但是,由于间隔变小,我们就必须对新增加的行进行填充。

ts.resample('H').ffill()

下面,接着开始降频采样,从 1 天变成 5 天:

ts.resample('5D').sum()

mingyun commented 6 years ago
def getComments(movieId, pageNum): 
    eachCommentList = []; 
    if pageNum>0: 
         start = (pageNum-1) * 20 
    else: 
        return False 
    requrl = 'https://movie.douban.com/subject/' +str( movieId) + '/comments' +'?' +'start=' + str(start) + '&limit=20' 
    print(requrl)
    html_data = rq.get(requrl).content
    soup = bs(html_data, 'html.parser') 
    comment_div_lits = soup.find_all('div', class_='comment') 
    for item in comment_div_lits: 
        if item.find_all('p')[0].string is not None:     
            eachCommentList.append(item.find_all('p')[0].string)
    return eachCommentList
import pandas as pd
import matplotlib.pyplot as plt
 from bs4 import BeautifulSoup as bs
 import jieba
 import numpy as np
 import re
from wordcloud import WordCloud
url='https://movie.douban.com/subject/27008416/comments'
import requests as rq
commentList = []
for i in range(100):
      num = i + 1
      commentList_temp = getComments(27008416, num)
      commentList.append(commentList_temp)
>>> commentList[:1]#第一页评论
[[' 男二人设其实挺苏的,热血纯情忠犬少年还是游泳冠军选手(越说越觉得像举重里的郑
俊亨。。。),奈何演员选得太接地气了这cp实在是不太好磕。\n        ', ' 好久没有
看过这么温馨又不尴尬演技还在线的校园青春剧了,上一部还是《恶作剧之吻》。 剧组是
很有心的,每一集最后的彩蛋很棒。看到里面的递情书 去网吧 默写单词  老师的唠叨 陈
小希扮演白娘子,又想起了以前的校园时光。\n        ', ' 33岁老阿姨,3集看哭2次,
傻笑20次……\n        ', ' 放出来的片花很甜很吸引人,可是正片太拖沓了吧,剧情像
是各种小段子东拼西凑起来的,手机用小灵通然而qq聊天气泡都是最新版\n        ', '
很尴尬,而且很讨厌这种男生酷女生傻的组合~要怪就怪最好的我们拍的太合我意了\n
    ', ' 零五年的故事背景,女主桌上是17年的知音漫客,用的是17年版本的qq还用了个
性气泡……我满脸都是excuse me拜托既然要弄回忆杀那就好好把年代相关的道具做好OK?
看了第一集完全被女主的傻白甜性格雷到,这样的女孩子为毛会被学神喜欢???怕了怕了
,我还是再去重刷一遍最好的我们吧\n        ', ' 可能是预期太高,前几集看来,演技
生涩了点,节奏平淡了点,不过颜值和色调蛮舒服的……\n        ', ' 预告即全剧最佳
。正片太尬了,剪辑也有问题,故事讲得很不连贯。曾以为这剧是清流,其实也就那样。不
会再浪费时间看了。\n        ', ' 这身高差太棒了!图书馆那一幕少女心泛滥了!\n
     ', ' 男主一脸二傻子样。三分钟都没有看不下去了。\n        ', ' 无脑素食盗版
《恶作剧之吻》,看完了前2集,只想重温台版恶吻\n        ', ' 年度最失望 演技什么
的都不计较毕竟是新人 男女主颜值也都在线 但是作为忠实淑芬剧情改成这个样子真他妈的
想说脏话(哦 我已经说了)跟烂俗的三角恋还有什么区别 我们全宇宙最可爱的陈小希最温
暖的小江医生 永远只在书里了\n        ', ' 我喜欢你,你会知道。怀念那段单纯的美好
时光。\n        ', ' 垃圾!是我见过最长的mv!\n        ', ' 年度最期待MV,配垃圾
长剧情。\n        ', ' 抱歉,我去看隔壁你好旧时光了。半集弃。\n        ', ' 剧情
太弱,营销太过。演技制作都不够水平啊。\n        ', ' 预告即巅峰系列\n        ',
' 原著党很气了…\n        ', ' 预告全片能看精华系列。。。。\n        ']]
#将列表中的数据转换为字符串
comments = ''
for k in range(len(commentList)):
     comments = comments + (str(commentList[k])).strip()
#使用正则表达式去除标点符号
pattern = re.compile(r'[\u4e00-\u9fa5]+')
filterdata = re.findall(pattern, comments)
cleaned_comments = ''.join(filterdata)
#使用结巴分词进行中文分词
segment = jieba.lcut(cleaned_comments)
words_df=pd.DataFrame({'segment':segment})
     segment
     segment
0          男
1         二人
2          设
3         其实
4         挺苏
5          的
6         热血
7         纯情
8         忠犬
9         少年
10        还是
11        游泳
12        冠军
13        选手
14         越
15         说
16         越
17        觉得
18         像
19        举重
20         里
21         的
22       郑俊亨
23        奈何
24        演员
25        选得
26         太
27        接地
28         气
29         了
...      ...
4728      泠冽
4729      撕碎
4730      支票
4731     扔回去
4732       说
4733      阿姨
4734      支票
4735      兑现
4736       太
4737      麻烦
4738       钱
4739      还是
4740       打
4741       我
4742     支付宝
4743       吧
4744      怎么
4745       说
4746       呢
4747       总
4748      觉着
4749      这种
4750       剧
4751      有些
4752      脑残
4753       挺
4754      平淡
4755      看看
4756      还行
4757       吧
#去掉停用词,先下载https://github.com/wendy1990/short_text_classification/blob/master/conf/stopwords.txt
stopwords=pd.read_csv("short_text_classification/conf/stopwords.txt",index_col=False,quoting=3,sep="\t",names=['stopword'], encoding='utf-8')#quoting=3全不引用words_df=words_df[~words_df.segment.isin(stopwords.stopword)]
     segment
0          男
1         二人
2          设
4         挺苏
6         热血
7         纯情
8         忠犬
9         少年
11        游泳
12        冠军
13        选手
14         越
15         说
16         越
17        觉得
19        举重
20         里
22       郑俊亨
23        奈何
24        演员
25        选得
26         太
27        接地
28         气
31        实在
33       不太好
34         磕
35        好久
37        看过
39        温馨
...      ...
4716      那种
4717      贱人
4720      支票
4721      离开
4723      儿子
4725     女主角
4727      一脸
4728      泠冽
4729      撕碎
4730      支票
4731     扔回去
4732       说
4733      阿姨
4734      支票
4735      兑现
4736       太
4737      麻烦
4738       钱
4742     支付宝
4745       说
4746       呢
4747       总
4748      觉着
4749      这种
4750       剧
4752      脑残
4753       挺
4754      平淡
4755      看看
4756      还行

[2818 rows x 1 columns]
#统计词频
words_stat=words_df.groupby(by=['segment'])['segment'].agg({"计数":np.size})
words_stat=words_stat.reset_index().sort_values(by=["计数"],ascending=False)
     segment  计数
354       喜欢  39
244       剧情  37
931       演技  32
1399      青春  31
437       女主  31
1008      男主  28
408        太  25
1069      真的  20
986        甜  20
1316      这种  18
1022      男女  17
1269       说  17
460       好看  17
1247      觉得  16
1155      美好  16
1162       老  14
240        剧  14
331        吻  14
1018      男二  13
1413      预告  13
615      恶作剧  12
523        差  12
811       有点  11
32        一集  11
928       演员  11
1296      身高  11
308       可爱  11
486       实在  11
1314      这剧  10
844       校园  10
...      ...  ..
554       开拍   1
552        开   1
551       延播   1
549       庆幸   1
548       幽默   1
547       幸小   1
544       年华   1
541       平面   1
539       平台   1
538       干脆   1
537       干胡   1
562       强大   1
563      强迫症   1
565       当好   1
579      微博上   1
587       心痛   1
585      心江辰   1
584       心思   1
583       心态   1
582      心女主   1
581       心动   1
577       很苏   1
566       当成   1
575       很棒   1
574       很快   1
573       很差   1
571       影子   1
568       彩小   1
567       当魂   1
724        撕   1

[1448 rows x 2 columns]
#用词云进行显示
wordcloud=WordCloud(font_path="c:\windos\fonts\simhei.ttf",background_color="white",max_font_size=80)
word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
word_frequence_list = []
for key in word_frequence:
     temp = (key,word_frequence[key])
     word_frequence_list.append(temp)
wordcloud=wordcloud.fit_words(word_frequence_list)
plt.imshow(wordcloud)
plt.show()
mingyun commented 6 years ago

pyechart https://github.com/napjon/krisk https://github.com/spatie/laravel-responsecache json 注释 { "//": "a", "value": "test" }我还好写过2年python,转做爬虫,数据分析之类的了 你本地连数据库的时候 不要用localhost 改用127.0.0.1 基于Redis实现的延迟队列 https://segmentfault.com/a/1190000010021748 https://github.com/ouqiang/delay-queue 利用Redis的有序集合,member为JobId, score为任务执行的时间戳, 每秒扫描一次集合,取出执行时间小于等于当前时间的任务. gocron - 定时任务管理系统 https://github.com/ouqiang/gocron Laravel5.2使用RabbitMQ初体验 http://blog.csdn.net/sinat_21125451/article/details/53422648 PHP微信APP支付接口 http://blog.csdn.net/amazingdyd/article/details/52400458 Laravel5.2集成原生微信支付 http://blog.csdn.net/pz_winner/article/details/78546247 redis的队列来实现。将要促销的商品数量以队列的方式存入redis中,每当用户抢到一件促销商品则从队列中删除一个数据,确保商品不会超卖。这个操作起来很方便,而且效率极高 http://blog.csdn.net/pz_winner/article/details/78482461 php面试题汇总(必会) laravel5.2总结--服务容器(依赖注入,控制反转) http://blog.csdn.net/pz_winner/article/details/78598837 关于php 高并发解决的一点思路 http://www.cnblogs.com/phpper/p/6716248.html php+crontab+shell方案实现的秒级定时发起异步请求回调方案 https://segmentfault.com/a/1190000011814778

* * * * * sh /web/project/src/shell/repair_build_order.sh
#!/bin/bash
cd /web/project/src
for (( i = 1; i < 60; i = i + 1 ))
do
    $(/usr/bin/php index.php task_run > /dev/null 2>&1 &)
    sleep 1
done

exit 0

redis-cli连接redis后,可以使用==monitor==查看队列情况。 秒杀场景总结 https://segmentfault.com/a/1190000002990385 https://github.com/nswbmw/N-chat Pub/Sub 服务的逻辑很简单。用命令行起一个PHP,订阅到一个Channel,这个PHP就一直等着。Web程序只要用Redis把数据Pub到同一个Channel里边,命令行的PHP就会获得数据并触发callback函数。 https://segmentfault.com/a/1190000003955944

ini_set('default_socket_timeout', -1);

$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$channelname = c('mail_channel'); 
try
{
    $redis->subscribe(array($channelname), 'mailsend');
}catch(Exception $e)
{
echo $e->getMessage();
}
$redis = new Redis();
$redis->connect('127.0.0.1',6379);

$info = array();
$info['to'] = $to;
$info['subject'] = $subject;
$info['content'] = $content;

if($ret = $redis->publish( c('mail_channel') , serialize($info) ))
{
return send_result( 'send to ' . $to . ' add to queue' );
}
else 
    return send_error( $ret );

PHP实现非对称加密 https://segmentfault.com/a/1190000003975283 分页查询的那些坑和各种技巧 https://blog.jamespan.me/2015/01/22/trick-of-paging-query select from table where id >= #minId# and xxx in (1,2,3) limit 200 假如每页显示 20 条数据,那么查询数据库的时候,用 limit #offset#, 21 取出 21 条记录,页面展现20条。如果取到了 21 条,说明下一页还有数据,在页面展示下一页按钮。如果结果集数量不足 21,说明已经到了最后一页,无需显示下一页按钮了。这种方式完全避免了在分页查询时对总条目数量的查询。 select from users where (gender,user_type) = (select min(gender),min(user_type) from users); 常用 inner join 去关联两张表,找到两张表都有的数据。如果一张表的数据比另一张表多,那么我们可以用 left join 或者 right join,把数据比较多的那张表放在 left join 的左边,或者放在 right join 的右边,得到的结果集里,数据少的那张表就会有很多行都是 null,我们就能根据这些 null 过滤出不存在于另一张表中的记录。 https://blog.jamespan.me/posts/how-to-find-primary-keys-of-deleted-row select 1 as id from dual 这样的语句,得到一个和查表一样形式的输出;然后再用 union all 把多个这样的表拼接起来,形成一个包含缓存中所有 id 的临时表;最后把临时表和源表做 left join,就可以得到缓存中还存在,但是数据库中已经删除的记录的主键。 pyiconv - 一个文本编码探测转换器 https://blog.jamespan.me/2014/08/04/pyiconv

https://github.com/wuzhc/demo/blob/master/shejimoshi/Factory.php 设计模式

$fp = fopen($filename, 'a+');
if (!$fp) {
    echo 'can\'n open filename';
    exit;
}
$retries = 0;
do {
    if ($retries > 0) {
        sleep(1);
    }
    $retries += 1;
} while (!flock($fp, LOCK_EX) && $retries < 3);
fwrite($fp, 'you content');
flock($fp, LOCK_UN);
fclose($fp);
$data = file_get_contents('./test.png');
$http_entity_body = $data;
//$http_entity_type = 'application/x-www-form-urlencoded';
$http_entity_type = 'multipart/form-data'; //经过测试,entityType设置为multipart/form-data时候也可以用php://input
$http_entity_length = strlen($http_entity_body);
$host = 'wuzhc.cm';
$port = 80;
$path = '/test/input/receive.php';
$fp = fsockopen($host, $port, $error_no, $error_desc, 30);
if ($fp) {
    fputs($fp, "POST {$path} HTTP/1.1\r\n");
    fputs($fp, "Host: {$host}\r\n");
    fputs($fp, "Content-Type: {$http_entity_type}\r\n");
    fputs($fp, "Content-Length: {$http_entity_length}\r\n");
    fputs($fp, "Connection: close\r\n\r\n");
    fputs($fp, $http_entity_body . "\r\n\r\n");
    while (!feof($fp)) {
        $d .= fgets($fp, 4096);
    }
    fclose($fp);
    echo $d;
}
class ParentClass {
    public static function name()
    {
        return __CLASS__;
    }
 public static function create()
    {
        return new static();
    }
    public static function test()
    {
        return self::name(); //改为static::name() 就可以了
    }
}
class ChildClass extends ParentClass {
    public static function name()
    {
        return __CLASS__;
    }
}
echo ChildClass::test();
$pipe = $redis->multi(Redis::PIPELINE);
for ($i = 0; $i < 10; $i++) {
    $pipe->set("ss$i", str_pad($i, 4, '0', 0));
    $pipe->get("ss$i");
}
$replies = $pipe->exec();
$requestUrls = [];
for ($i=0; $i<10; $i++) {
    array_push($requestUrls, 'http://104.194.84.229/zcshop/frontend/web/test/sms');
}
$mh = curl_multi_init();
$chs = [];
foreach ($requestUrls as $url) {
    $chs[] = $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 3000);
    curl_setopt($ch, CURLOPT_NOSIGNAL, true);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_PROXY, '127.0.0.1:8888');
    curl_multi_add_handle($mh, $ch);
}
do {
    curl_multi_exec($mh, $running);
    curl_multi_select($mh);
} while ($running > 0);
$res = [];
foreach ($chs as $k => $ch) {
    $res[] = curl_multi_getcontent($ch);
    curl_multi_remove_handle($mh, $ch);
    echo $k . ' success' . PHP_EOL;
}
curl_multi_close($mh);
mingyun commented 6 years ago

200行代码学会微信H5支付,附php可用代码 https://www.wangwenxiao.com/208 mysql用sql语句orderby多个条件排序 https://www.wangwenxiao.com/260 http://www.baidu.comhttp://112.80.248.73 的效果是等价的 所以现在要访问百度,用以下的方式都可以访问哦: http://www.baidu.com http://112.80.248.73 http://1884354633 http://0016024174111 http://0x7050f849

import socket
import struct
ip = '119.75.218.77'
num_ip=socket.ntohl(struct.unpack("I",socket.inet_aton(str(ip)))[0])
num_ip
2001459789L
ip = socket.inet_ntoa(struct.pack('I',socket.htonl(num_ip)))
ip
'119.75.218.77'
function rangeDaysAfterTimeStamp($startTimestamp, $daysNum = 1)
    {
        $range = [];

        do {
            $range[] = date('Y-m-d 00:00:00', $startTimestamp + (-- $daysNum) * 86400);
        } while ($daysNum);

        rsort($range);

        return $range;
    } 
>>> rangeDaysAfterTimeStamp(strtotime('2017-11-11'),7)
=> [
       "2017-11-17 00:00:00",
       "2017-11-16 00:00:00",
       "2017-11-15 00:00:00",
       "2017-11-14 00:00:00",
       "2017-11-13 00:00:00",
       "2017-11-12 00:00:00",
       "2017-11-11 00:00:00"
   ]
$ch = curl_init(); 

    $fp=fopen('./girl.jpg', 'w');

    curl_setopt($ch, CURLOPT_URL, "http://远程服务器地址马赛克/girl.jpg"); 
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60); 
    curl_setopt($ch, CURLOPT_FILE, $fp); 

    $output = curl_exec($ch); 
    $info = curl_getinfo($ch);

    fclose($fp);

    $size = filesize("./girl.jpg");
    if ($size != $info['size_download']) {
        echo "下载的数据不完整,请重新下载";
    } else {
        echo "下载数据完整";
    }https://segmentfault.com/a/1190000006220620 https://linkedinfo.co/infosbytags?tags=php
function array_sort($array, $on, $order=SORT_ASC)
{
    $new_array = array();
    $sortable_array = array();
    if (count($array) > 0) {
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                foreach ($v as $k2 => $v2) {
                    if ($k2 == $on) {
                        $sortable_array[$k] = $v2;
                    }
                }
            } else {
                $sortable_array[$k] = $v;
            }
        }
        switch ($order) {
            case SORT_ASC:
                asort($sortable_array);
                break;
            case SORT_DESC:
                arsort($sortable_array);
                break;
        }
        foreach ($sortable_array as $k => $v) {
            $new_array[$k] = $array[$k];
        }
    }
    return $new_array;
}function array_orderby()
{
    $args = func_get_args();
    $data = array_shift($args);
    foreach ($args as $n => $field) {
        if (is_string($field)) {
            $tmp = array();
            foreach ($data as $key => $row)
                $tmp[$key] = $row[$field];
            $args[$n] = $tmp;
        }
    }
    $args[] = &$data;
    call_user_func_array('array_multisort', $args);
    return array_pop($args);
}
// ini_set(‘default_socket_timeout’, -1); https://github.com/TIGERB/easy-tips/blob/master/redis/subscribe-publish/subscribe.php
  $redis = new \Redis();
  $redis->pconnect('127.0.0.1', 6379);
  //订阅
  echo "订阅msg这个频道,等待消息推送... \n";
  $redis->subscribe(['msg'], 'callfun');
  function callfun($redis, $channel, $msg)
  {
   print_r([
     'redis'   => $redis,
     'channel' => $channel,
     'msg'     => $msg
   ]);
  }
$redis->publish('msg', '来自msg频道的推送');
  echo "msg频道消息推送成功~ \n";
  $redis->close();

如果每天记录当天的积分排行榜,那么其他花样百出的榜单也就简单了。 比如“昨日积分榜”:

bashZREVRANGE rank:20150331 0 9 withscores 利用并集实现多天的积分总和,实现“上周积分榜”:

bashZUNIONSTORE rank:last_week 7 rank:20150323 rank:20150324 rank:20150325 rank:20150326 rank:20150327 rank:20150328 rank:20150329 WEIGHTS 1 1 1 1 1 1 1 这样就将 7 天的积分记录合并到有序集合 rank:last_week 中了。权重因子 WEIGHTS 如果不给,默认就是 1。为了不隐藏细节,特意写出。 那么查询上周积分榜 Top10 的信息就是:

bashZREVRANGE rank:last_week 0 9 withscores http://blog.csdn.net/zheng0518/article/details/47280745 http://blog.csdn.net/zeus_9i/article/details/51025175 Redis 排行榜 相同分数根据时间优先排行 https://segmentfault.com/a/1190000002694239 tail -f | redis-cli -h 10.94.120.13 -p 6380 monitor | grep "queues:snail" 监控redis对应队列消息具体产生的消息操作 https://laravel-china.org/articles/4479/analysis-of-laravel-queue-usage Beanstalkd in Laravel http://www.jianshu.com/p/9422b8d86d8a 一个简单的事情,被你说得好复杂。 主要是使用到了 这个功能吧 http://redisdoc.com/topic/notification.html

我的理解就是,

任务来了, 2 写入redis 加上键值过期监听 监听到过期,任务处理 https://cnodejs.org/topic/5577b493c4e7fbea6e9a33c9

首先我在 redis 中维护一个 sorted set。score 的值为:YYYYMMDD+HOUR,如 2015061020。当 A 用户邀请了 B 用户之后,我就推算一下 24 小时后,是多少,把 B 用户的值写入 set 中。然后另外起个定时任务,每小时读一次这个 set,读出比当前时间小的 score,批量处理一次。 https://github.com/lixuancn/LaneWeChat 微信PHP快速开发框架 http://www.liuchungui.com/blog/2016/08/01/wei-xin-gong-zhong-hao-kai-fa-zong-jie/ 微信公众号开发总结

  1. 传统架构 技术栈 其实就是 负载均衡->各种框架->缓存集群->数据库集群 | CDN 这种架构方式

  2. 使用swoole或者workman实现的分布式架构 CDN | 负载均衡->原生或者搞QBS承载的框架 集成swoole或workman ->网关服务器 例如KONG-> 各种语言的做成的服务, 使用socket通讯 如果是PHP则集成swoole workman->缓存集群->数据库集群

3.JAVA 或者其他分布式架构的 hadoop spark 以及 spring cloud, 这些分布式架构本身实现度就很高

$format = "<xml>
<Encrypt><![CDATA[%s]]></Encrypt>
<MsgSignature><![CDATA[%s]]></MsgSignature>
<TimeStamp>%s</TimeStamp>
<Nonce><![CDATA[%s]]></Nonce>
</xml>";
$format = <<<XML
<xml>
<Encrypt><![CDATA[%s]]></Encrypt>
<MsgSignature><![CDATA[%s]]></MsgSignature>
<TimeStamp>%s</TimeStamp>
<Nonce><![CDATA[%s]]></Nonce>
</xml>
XML;
$xml = new \DOMDocument();
            $xml->loadXML($xmltext);
            $array_e = $xml->getElementsByTagName('Encrypt');
            $encrypt = $array_e->item(0)->nodeValue;
$xml = (array) simplexml_load_string(file_get_contents('php://input'), 'SimpleXMLElement', LIBXML_NOCDATA);
http://blog.csdn.net/wuxing26jiayou/article/category/6689523 PHP 冒泡排序
 public static function getCurrentMonthDates() {
        $dt = Carbon::now();
        $days = $dt->daysInMonth;//天数

        $dates = array();
        for ($day = 1; $day <= $days; $day++) {
            $dt->day = $day;
            $dates[] = $dt->format('Ymd');
        }
        return $dates;
    }
查找表中name字段和email字段相同的数据:
https://segmentfault.com/a/1190000002508404 
select * from demo_table as a, demo_table as b where a.id=b.id and a.name=b.email;
create table tmp_table as select min(id) from demo_table group by email;
delete from demo_table where id not in (select * from tmp_table);
drop table tmp_table;
$season  = ceil(date('n') /3); //获取月份的季度
上季度开始时间 mktime(0, 0, 0, ($season - 2) * 3 + 1, 1, date('Y'));
 上季度结束时间 mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')) - 1;
本周之前几周的结束时间 date('d') - date('w') + 7 - 7 * $beforeWeeks
本周之前几周的开始时间 date('d') - date('w') + 1 - 7 * $beforeWeeks
date('t',strtotime('2017-02-02')) //2月 28 天
function rangeDaysAfterTimeStamp($startTimestamp, $daysNum = 1)
    {
        $range = [];

        do {
            $range[] = date('Y-m-d 00:00:00', $startTimestamp + (-- $daysNum) * 86400);
        } while ($daysNum);

        rsort($range);

        return $range;
    }
function rangeDays($beginTimestamp, $endTimestamp)
    {
        $beginTimestamp = strtotime(date('Y-m-d', $beginTimestamp));
        $endTimestamp = strtotime(date('Y-m-d', $endTimestamp));

        $range = [];
        $i = 0;

        do {
            $time = $beginTimestamp + $i * 86400;
            $range[] = date('Y-m-d 00:00:00', $time);
            $i++;
        } while ($time < $endTimestamp);

        return $range;
    }
mingyun commented 6 years ago

引用的妙用

$catList = [
    '1' => ['id' => 1, 'name' => '颜色', 'parent_id' => 0],
    '2' => ['id' => 2, 'name' => '规格', 'parent_id' => 0],
    '3' => ['id' => 3, 'name' => '白色', 'parent_id' => 1],
    '4' => ['id' => 4, 'name' => '黑色', 'parent_id' => 1],
    '5' => ['id' => 5, 'name' => '大', 'parent_id' => 2],
    '6' => ['id' => 6, 'name' => '小', 'parent_id' => 2],
    '7' => ['id' => 7, 'name' => '黄色', 'parent_id' => 1],
];$treeData = [];// 保存结果
foreach ($catList as $item) {
    if (isset($catList[$item['parent_id']]) && ! empty($catList[$item['parent_id']])) {// 肯定是子分类
        $catList[$item['parent_id']]['children'][] = &$catList[$item['id']];
    } else {// 肯定是一级分类
        $treeData[] = &$catList[$item['id']];
    }
}
$result = [
    ['id' => 1, 'name' => '颜色', 'children' => [
        ['id' => 3, 'name' => '白色'],
        ['id' => 4, 'name' => '黑色'],
        ['id' => 7, 'name' => '黄色']
    ]],
    ['id' => 2, 'name' => '规格', 'children' => [
        ['id' => 5, 'name' => '大'],
        ['id' => 6, 'name' => '小']
    ]]
];
$ php artisan tinker
PHP Fatal error:  Cannot use PhpParser\Node\Scalar\String as String because 'Str
ing' is a special class name in D:\soft\wamp\www\laravel_web\vendor\psy\psysh\sr
c\Psy\CodeCleaner\MagicConstantsPass.php on line 19

  [Symfony\Component\Debug\Exception\FatalErrorException]
  Cannot use PhpParser\Node\Scalar\String as String because 'String' is a spe
  cial class name

http://cn.php.net/manual/zh/reserved.other-reserved-words.php 以下关键字不可被用于类名、接口名和trait名,并且它们被禁止用于命名空间。 https://github.com/nikic/PHP-Parser/issues/248
$ psysh
PHP Fatal error:  Uncaught Error: Class 'Psy\Shell' not found in C:\Users\vhalll
sp\AppData\Roaming\Composer\vendor\psy\psysh\bin\psysh:108
Stack trace:
#0 {main}
  thrown in C:\Users\vhalllsp\AppData\Roaming\Composer\vendor\psy\psysh\bin\psys
h on line 108

Fatal error: Uncaught Error: Class 'Psy\Shell' not found in C:\Users\vhalllsp\Ap
pData\Roaming\Composer\vendor\psy\psysh\bin\psysh:108
Stack trace:
#0 {main}
  thrown in C:\Users\vhalllsp\AppData\Roaming\Composer\vendor\psy\psysh\bin\psys
h on line 108
http://psysh.org/  composer g require psy/psysh:@stable

>>> r=req.get(wx,headers={'cookie':c},verify=False)
d:\python27\lib\site-packages\requests\packages\urllib3\util\ssl_.py:132: Insecu
rePlatformWarning: A true SSLContext object is not available. This prevents urll
ib3 from configuring SSL appropriately and may cause certain SSL connections to
fail. You can upgrade to a newer version of Python to solve this. For more infor
mation, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-war
nings
  InsecurePlatformWarning
d:\python27\lib\site-packages\requests\packages\urllib3\connectionpool.py:852: I
nsecureRequestWarning: Unverified HTTPS request is being made. Adding certificat
e verification is strongly advised. See: https://urllib3.readthedocs.io/en/lates
t/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)

curl 返回 false $curl_errno = curl_errno($curl);
        $curl_error = curl_error($curl);
SSL certificate problem: unable to get local issuer certificate 下载https://curl.haxx.se/ca/cacert.pem
php.ini curl.cainfo = D:\phpStudy\php\cacert.pem
Fri Dec 15 15:57:13 2017 (21320): Fatal Error Unable to open base address file 
http://windows.php.net/download/
$ /d/soft/wamp/php/php  artisan tinker

Warning: date(): It is not safe to rely on the system's timezone settings. You a
re *required* to use the date.timezone setting or the date_default_timezone_set(
) function. In case you used any of those methods and you are still getting this
 warning, you most likely misspelled the timezone identifier. We selected the ti
mezone 'UTC' for now, but please set date.timezone to select your timezone. in D
:\soft\wamp\www\laravel_web\config\services.php on line 122

Fatal error: Call to undefined function Illuminate\Foundation\Bootstrap\mb_inter
nal_encoding() in D:\soft\wamp\www\laravel_web\vendor\laravel\framework\src\Illu
minate\Foundation\Bootstrap\LoadConfiguration.php on line 43

vi php.ini
date.timezone = "Asia/Shanghai"
extension=php_mbstring.dll

1.在使用requests前加入:requests.packages.urllib3.disable_warnings()
2.为requests添加verify=False参数,比如:r = requests.get('https://blog.bbzhh.com',verify=False)
mingyun commented 6 years ago

简单实现redis队列,模拟下单 https://github.com/linganmin/simple-php-queue-redis.git https://www.linganmin.cn/show/59 学习开发自己的composer包 一次PHP脚本执行卡住的问题排查记录 http://tabalt.net/blog/php-script-execution-stuck-record/