This is a notebook about how to use `Python` to do `Data Science` research. There are two main references in this notebook Python Data Analytics and Python Data Science Handbook.
Xi'an Jiaotong University **shenchi@outlook.com**
Version 0.1, created on Oct 31, 2019, updated on June 07, 2020
# Style with the main css template
import IPython.core.display as di
css_file = 'custom.css'
di.HTML(open(css_file, "r").read())
# Run (once) to allow nice html output as report (optional)
# Example: di.display_html('<h3>%s:</h3>' % str, raw=True)
# This line will hide code by default when the notebook is exported as HTML
# Reference: https://github.com/marpat/marpat.github.io/tree/master/notebook/report-print
di.display_html(
'<script>jQuery(function() {if (jQuery("body.notebook_app").length == 0) { jQuery(".input_area, .output_stderr").toggle(); jQuery(".prompt").toggle();}});</script>', raw=True)
CSS = """.input_area .output_stderr {height: 2.0em; overflow: hidden}""" # changes input_subarea width to 1 visible line
di.HTML('<style>{}</style>'.format(CSS))
# This line will add a button to toggle visibility of code blocks, for use with the HTML export version
di.display_html('''<button onclick="jQuery('.input_area').toggle(); jQuery('.prompt').toggle();">Note: Click Here to Toggle Code Chunk</button>''', raw=True)
x = 8
y = 8.8
z = 'hello python'
w = True
# 不同数据类型之间相互转换
print(int(y))
print(int(w))
print(str(x))
print(bool(x))
1)序列(Sequence)的定义: 是指它的成员有序排列,并可以通过下标(即索引)偏移量来访问成员。
需要注意的是python的索引下标是从0开始的
2)类型:
3)class()函数可以用来判断序列类型
4)序列操作符:
索引 (indexing) 和切片 (slicing) 语法:
定义字符串时可以用双引号也可以用单引号
letter = 'abcdefghijk'
number = '12345'
print(letter[1])
print(letter + number)
print(letter * 3)
print(letter[0:5])
print('a' in letter)
元组和字符串的区别在于,元组类似R中的vector,同样适用序列操作符
但是与R的vector的区别在于,同一个元组中可以同时存在num和str,并且数据类型不一样,R中vector虽然可以同时混合输入数字和字符,但是数字会被转换成字符类型
mon_day = (1, 20)
mon_day > (2, 20)
元组大小和内容都不可更改,因此只有 count 和 index 两种方法,如下例子:
week = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')
print(week.count('Monday')) #计数
print(week.index('Friday')) #取索引位置
列表和元组一样,最大的区别在于可以变更,变更即意味着可以增加(append)、减少(remove)、插入 (insert)、删除 (remove, pop) 成员
例子如下:
list_a = [1, 2, 'c']
list_b = ['a', 'b', 3]
print(list_a)
#---------------#
list_a.append('hello')
print(list_a)
#---------------#
list_a.extend(list_b)
print(list_a)
#---------------#
list_a.insert(2, 'python')
print(list_a)
#---------------#
list_a.remove('a')
print(list_a)
字典(dict)不属于序列,其本质是映射,形式为一个key对应一个value,key即是哈希值
字典和列表一样是可以变更的,也同样支持索引
字典里最常用的三个内置方法就是 keys(), values() 和 items(),分别是获取字典的键、值、对。
dict_a = {'Mon' : 1, 'Tue' : 2, 'Wed' : 3}
print(dict_a.keys())
print(dict_a.values())
print(dict_a.items())
# 字典的填补
dict_b = {}
dict_b['a'] = 1
print(dict_b)
可以使用大括号 { } 或者 set() 函数创建集合:
注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典
set_a = set(['u', 'd', 'ud', 'du', 'd', 'du'])
set_b = {'d', 'dd', 'uu', 'u'}
print(set_a)
print(set_b)
集合的并集、交集、差集:
print( set_a.union(set_b) ) # All unique elements in A or B
print( set_a | set_b ) # A or B
print( set_a.intersection(set_b) ) # All elements in both A and B
print( set_a & set_b ) # A AND B
x = 1
if x > 5:
print('x 大于5')
else:
print('x 小于5')
# elif语句的用法
x = 5
if x == 5:
print('x 等于5')
elif x > 5:
print('x 大于5')
else:
print('x 小于5')
# 注意下面代码结果与上面的区别
x = 5
if x == 5:
print('x 等于5')
if x > 5:
print('x 大于5')
else:
print('x 小于5')
x = 1
while x < 5:
print(x)
x += 1
print('循环结束')
for in循环
for x in range(1, 5):
print(x)
print('循环结束')
One more thing
函数 enumerate() 可以和 for in 循环联用,具体syntax为:
for i, a in enumerate(A):
do something with a
用 enumerate(A) 使得在遍历A的同时,顺便给元素一个索引值 (默认从 0 开始)
此外,用 enumerate(A, j) 还可以确定索引起始值为 j。
workdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
for i, days in enumerate(workdays, 1):
print(days, '是星期', i)
循环控制语句一共有三个:
break语句:
通常情况下,要想结束一个循环,只能等循环执行完毕或者报错跳出。
想着中途就结束循环,就需要用到break语句。
注意:break只能用于循环体内,其效果是直接结束并退出当前循环,剩下的未循环的工作全部被忽略和取消。
continue语句:
用于跳过当前循环的剩余部分代码,直接开始下一轮循环,即是提前结束当次循环,不影响下一次循环。
pass语句:
没有实际作用,只是为了代码的完整性和可读性,只起到占位的作用。
例子如下:
# break语句
for i in range(1, 10):
print('I am No.', i)
if i == 5:
break
# 可以看出整个循环在5时就结束了,需要注意的时当循环嵌套时,break只结束所在的循环
# pass语句
for i in range(1, 10):
print(i)
if i == 5:
continue
print('No. %s is not jumped' %i) # 可以看出使用了continue语句,只会跳过continue后面还未执行的代码,并不影响前面的代码,整个循环会继续
num = range(1, 11)
num_odd = [n * 2 for n in num if n % 2 == 1] # n即为推导式返回的值
print(num_odd)
# 以上列表推导式等同于以下方法
num_odd2 = []
for i in num:
if i % 2 == 1:
num_odd2.append(i * 2)
num_odd2
问题二:当循环嵌套时如何写推导式?
将二维元组里每个元素提取出来并存储到一个列表中:tup = ((1, 2, 3), (4, 5, 6), (7, 8, 9))
tup = ((1, 2, 3), (4, 5, 6), (7, 8, 9))
list_a = [n for item in tup for n in item]
list_a
原则上同理,只是字典涉及到key和value,例如
dict_a = {'Mon' : 10, 'Tue' : 12, 'Wed' : 15, 'Thu' : 10, 'Fri' : 10}
dict_b = {k : v for k, v in dict_a.items() if v == 10}
print(dict_b)
# key与value互换
dict_c = {v : k for k, v in dict_a.items()}
print(dict_c)
函数(function)在python中共有三大类:
语法形式:
def func_name(var1, var2 = 1, *var3, **var4, *, var5): statement
常规函数的四类参数类型:
例子:
def func1(x, y = 2):
return x + y
print(func1(1))
print(func1(1, 4))
# 加入可变参数
def func2(x, y = 2, *z):
m = x + y
for i in z:
m += i
return m
print(func2(1, 4, 1, 2, 3)) # 或者
print(func2(1, 4, *(1, 2, 3)))
# 加入关键字参数
def func3(x, y = 2, *z, **w):
m = x + y
for i in z:
m += i
print(m)
print(w)
dict = {'a' : 4, 'b' : 5, 'c' : 6}
func3(1, 4, *(1, 2, 3), **dict)
匿名函数又称为lambda函数,是对常规函数的一种省略写法,具体特点为:
基本语法为: lambda arg_list: expression
例如
m = [1, 2, 3, 4, 5]
n = map(lambda x: x * 2, m)
print(list(n))
p = filter(lambda x: x % 2 == 0, m)
print(list(p))
高阶函数 (high-order function) 在函数化编程 (functional programming) 很常见,主要有两种形式:
python的内建函数就属于第一种:
闭包属于第二种高阶函数:
Python 里面的闭包 (closure) 属于第二种高阶函数,返回值是函数。 闭包就是函数的嵌套
下面是一个闭包函数。
def sum(a):
def add(b):
return a + b
return add
sum_res = sum(1)
type(sum_res) # 注意此时返回的sum_res实际是一个函数,可以将其作为函数进行调用
print(sum_res(2))
闭包的应用
# 计步器
def counter(inti = 1):
count = [inti]
def add():
count[0] += 1
return count[0]
return add
num_1 = counter(1) # 从1开始计数
print(num_1())
print(num_1())
print(num_1())
num_5 = counter(5) # 从5开始计数
print(num_5())
print(num_5())
print(num_5())
# 解二元一次方程(a + bx = y)的闭包写法
def linear(a, b):
def argue(x):
return a + b * x
return argue
linear_1 = linear(5, 6) #设定斜率与截距
print(linear_1(1)) #对给定的x解y
print(linear_1(2))
linear_2 = linear(5, 3) #设定斜率与截距
print(linear_2(1))
print(linear_2(10))
装饰器(Decorators)是 Python 的一个重要部分。简单地说:装饰器是修改其他函数的功能的函数,有助于让代码更简短。本质是闭包的扩展用法。
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
比如,如果已经定义好了10个函数,现在额外增加一个需求:计算函数运行的时间。如果重新返回对10个函数进行修改,则需要重复修改10遍,这时就可以利用装饰器,简化操作。
具体例子如下:
import time
def timer(func):
def wrapper(*arg): #这里采用可变参数,可以适应不同函数的要求,因为不同函数传递的参数个数不一样
start_time = time.time()
func(*arg)
stop_time = time.time()
print('%s function has run %s seconds' %(func.__name__, stop_time - start_time))
return 'Decorators end' # 如果缺少return值,在print外部函数时会返回None
return wrapper
@timer # @符号叫做语法糖,是为了是代码更简洁
def add(a, b):
print(a + b)
print(add(2, 3))
更进一步的要求是不同的函数执行同一个装饰器中的不同功能
例如,一个函数执行计算执行时间,另一个函数执行运行提示
import time
def tip(name):
def decor(func):
def wrapper(*arg):
if name == 'timer':
start_time = time.time()
func(*arg)
stop_time = time.time()
print('%s function has run %s seconds' %(func.__name__, stop_time - start_time))
elif name == 'runner':
print('%s function begins running' %(func.__name__))
func(*arg)
print('%s function ends running' %(func.__name__))
else:
print('The tip name is wrong')
return wrapper
return decor
@tip('timer')
def add(a, b):
print(a + b)
@tip('runner')
def hello(a):
print('Hello %s' %(a))
add(5, 6)
hello('python')
模块很简单,就是将自定义的.py文件,通过import导入到新的环境中,文件名就是模块名
类(Class): 用来描述具有相同的属性(attribute)和方法(method)的对象的集合。该集合中每个对象具有相同的属性和方法。对类进行实例化(instance)就生成了对象。
例如:汽车就是一个类,而品牌、型号、颜色、变速箱就是汽车的属性,而加速、转弯、刹车就是汽车共有的功能或者方法,本质就是函数。
class Car: # 约定俗成将类名的首字母大写
'这是一个关于汽车的类' # 这是类的帮助文档,通过ClassNmae.__doc__可以查看
def __init__(self, band, model, color, trans): # self也是约定俗成,用来代表实例本身,__init__是用来定义类的全部属性的,self必须放在首位,其后再放其他属性名
self.band = band
self.model = model # 这部分是将属性名与实例进行连接,所谓实例就是对类进行具体化,赋值具体的属性,比如:本田civic红色自动挡,就是Car这个类的一个实例
self.color = color
self.trans = trans
def accelerate(self): # 这里定义的函数就是类的方法
print(self.band, self.model, self.trans, '的加速成绩特别好')
print(Car.__doc__)
honda_civic = Car('Honda', 'Civic', 'Blue', 'AT')
print(honda_civic.model) # 查看类的实例的属性
honda_civic.accelerate() # 类的方法
# 实例化的对象的属性也可以随时更改
honda_civic.color = 'white'
print(honda_civic.color)
面向对象技术简介:
类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
方法:类中定义的函数。
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
局部变量:定义在方法中的变量,只作用于当前实例的类。
实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
实例化:创建一个类的实例,类的具体对象。
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。
Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
面向过程编程就是指根据需要实现的需求从头到尾,一步一步去实现,其特点是逻辑清楚,便于理解且内存消耗低,缺点是需要较多的重复代码,不利于维护和复用。
面向对象编程则是根据需求将需要实现的功能区分为不同的类,然后通过对类进行实例化实现功能,优点是重复代码少,便于维护和复用,但是内存消耗高,逻辑开始难以理解。
数据科学不同于软件开发领域,数据科学在R、SAS、STATA的时代都是以面向过程编程为主,所以在数据分析过程中采用面向对象编程并未像其他领域那样成熟。 关于在python中采用面向对象编程来完成数据科学工作,可以参考这篇文章Python Object-Oriented Programming (OOP): Tutorial。
在数据科学中,更多的应该是对变量进行归类,这类变量具有相同的属性以及需要执行相同的操作,特别是在数据清洗阶段。
import pandas as pd
mtcars = pd.read_csv('https://gist.githubusercontent.com/seankross/a412dfbd88b3db70b74b/raw/5f23f993cd87c283ce766e7ac6b329ee7cc2e1d1/mtcars.csv')
mtcars.head()
# mtcars.info()
class Grouping:
def __init__(self, mpg, hp, gear):
self.mpg = mpg
self.hp = hp
self.gear = gear
def regroup(self):
if self.hp < 100:
return self.mpg / self.gear
elif self.hp >= 100 & self.hp <= 150:
return self.mpg / self.gear * 1.5
else:
return self.mpg / self.gear * 2
class_mhg = Grouping(mtcars['mpg'][0], mtcars['hp'][0], mtcars['gear'][0])
class_mhg.regroup()
异常即是一个事件,该事件(如错误)在程序执行过程中发生,影响了程序的正常执行
一般情况下,在Python无法正常处理程序时就会发生一个异常。
异常是Python对象,表示一个错误。
当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行。
捕捉异常可以使用try/except语句。
try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。 如果你不想在异常发生时结束你的程序,只需在try里捕获它。
Syntax:
try:
statement
except Error Name as newname:
do something
else:
do other thing
finally:
always do the thing
说明:
try语句下程序执行时,如果未发生异常就正常执行,如果发生except指定的异常,则执行except下操作。
else语句的含义是当指定的异常未发生时执行以下操作,发生时则不执行。
finally则是不管异常是否发生都执行以下操作。
print('#-------- Example 1 -------#')
try:
a = c
except NameError:
print('错误:对象不存在!')
finally:
print('程序执行完毕')
print('#-------- Example 2 -------#')
try:
a = c
except NameError as e: # as只是为了重命名
print('错误:对象不存在! %s' %(e)) # 用于输出错误的具体信息
finally:
print('程序执行完毕')
print('#-------- Example 3 -------#')
try:
a = 1
except NameError as e:
print('错误:对象不存在! %s' %(e))
else: # 未报错时执行
b = a
print(b)
finally:
print('程序执行完毕')
print('#-------- Example 4 -------#')
try:
a = 1
except (NameError, IndexError): # 捕捉多个异常时,放在tupple里,因为except只能接受一个参数
print('错误:对象不存在!')
else: # 未报错时执行
b = a
print(b)
finally:
print('程序执行完毕')
print('#-------- Example 5 -------#')
try:
a = 1
except Exception: # 捕捉所有错误,不指定某一特定的错误
print('错误:对象不存在!')
else: # 未报错时执行
b = a
print(b)
finally:
print('程序执行完毕')
print('#------- 手动促发异常 -------#')
try:
x = -1
if x < 0 :
raise ValueError("输入的变量小于0")
except Exception as e:
print("错误:",e)
是非常常见和有用的操作,分为读(read)和写(write),通常是对txt等文本文件进行操作。详细介绍可参考python之文件读写
打开(open)和关闭(close)文件: 不论是读取还是写入文件,第一步都是打开,最后一步都是关闭。文件的打开方式一共有8种,如下:
'r' open for reading (default)
'w' open for writing, truncating the file first
'x' create a new file and open it for writing
'a' open for writing, appending to the end of the file if it exists
'b' binary mode
't' text mode (default)
'+' open a disk file for updating (reading and writing)
'U' universal newline mode (deprecated)
读(read):
有两种方式,read()和readline()
写(write):
只有write一种方式
注意:
不论是读取还是写入文件,最后一定记得关闭(close)文件,不然会一直占用内存资源或者写入操作不成功。
但是当读取或者写入文件时报错的话,通常就不会执行close操作,就需要将对文件对操作放在try语句下,但是,这样 的操作过于繁琐,可以用with操作进行简化。
具体例子如下:
# 读取
IOfile = open('IOfile.txt', 'r', encoding='gbk', errors='ignore')
print( IOfile.read() )
IOfile.close()
# 按行读取
IOfile = open('IOfile.txt', 'r')
for line in IOfile.readlines():
print(line)
IOfile.close()
# 为了防止报错而忘记close操作
try:
f = open('IOfile.txt', 'r')
print(f.read())
finally:
f.close()
# with的用法
with open('IOfile.txt', 'r') as f:
print(f.read())
# 写入,如果文件不存在会自动新建
with open('IOfile.txt', 'w') as f:
f.write('Hello Python')
NumPy是numeric python的缩写,其前身为1995年由Jim Hugguin开发的numeric包,之后由Travils Olivant于2006年发布了numpy的第一个发行版,现在是python的基础库。
整个numpy库的核心就是n维数组ndarray(n dimensional array),指的是具有同质同大小的一组元素。
关于ndarray的基本概念:
两种方式:
import numpy as np
a = np.array( [1, 2, 3, 4, 5] ) # 一维度数组
b = np.array( [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]] )# 二维数组,多维同理
# 或者
c = np.array( ((1, 2, 3, 4, 5), (6, 7, 8, 9, 10)) )
print(a)
print(b)
print(c)
共有4中属性:
print( b.ndim )
print( b.size )
print( b.shape )
print( b.itemsize )
共有5个函数:
x = np.zeros(shape = (2, 3)) # 参数名shape可以省略
y = np.ones(shape = (2, 3))
z = np.arange(1, 11).reshape(2, 5)
m = np.linspace(1, 11, 5)
n = np.random.random(10) # 创建一维数组
w = np.random.random( (5, 5) ) # 创建二维数组
print(x)
print(y)
print(z)
print(m)
print(n)
print(w)
a = np.arange(1, 10)
b = np.arange(10, 40).reshape(3, 10)
print( '数组a是:', a)
print( '数组b是:', b)
# 索引
print( '索引:', a[1] )
print( '索引:', a[[1, 2]] )
print( '索引:', b[1, 1] )
print( '索引:', b[[1, 2], [1, 2]] )
# 切片
print( '切片:', a[2:4] ) # 注意切片是包含开始不包含结束的索引
# 删除
print( '删除', np.delete(a, [1, 2]))
print( '多维数组删除', np.delete(b, [1], axis = 0))
# 遍历
for i in np.arange(1, 5):
print( '一维遍历:', i)
for i in np.arange(1, 7).reshape(2, 3):
print( '多维遍历:', i) # 注意是按轴遍历的
for i in np.arange(1, 7).reshape(2, 3).flat:
print( '多维打平遍历:', i)
# 向量式遍历
np.apply_along_axis(np.mean, 0, np.arange(1, 7).reshape(2, 3)) # 与r中apply同理,只是0表示列,即按长度计算
拼接:
拆分:
Pandas是python进行数据分析过程中的核心库。于2008年开始开发,2012年正式上线。
1)数据结构
共定义了两种有别于python自带和numpy的数据结构:
2)创建Series和DataFrame
具体例子如下:
import pandas as pd
import numpy as np
# Series
ser1 = pd.Series([1, 'a', 2, 'b']) # 如果不指定index,则默认从0开始编号
ser2 = pd.Series([1, 'a', 2, 'b'], index = ['r1', 'r2', 'r3', 'r4'])
# DataFrame
df1 = pd.DataFrame({'band' : ['honda', 'volkswagen', 'toyota', 'mazda'],
'type' : ['civic', 'golf', 'crolla', 'mx-5']})
df2 = pd.DataFrame(np.arange(0, 10).reshape(5, 2),
columns = ['col1', 'col2'],
index = range(1, 6))
print('序列1:', ser1)
print('序列2:', ser2)
print('数据框1:', df1)
print('数据框2:', df2)
3)Series和DataFrame的索引与切片
具体例子如下:
# 索引
print( '序列索引:', ser2[1] )
print( '序列索引:', ser2['r1'] )
print( '数据框索引:', df1['band'] )
print( '数据框索引:', df1.band )
# 切片
print( '序列切片:', ser1[1:4] )
print( '数据框切片:', df1['band'][1:4] )
# series删除索引
ser2.drop('r1')
# dataframe删除行和列
df1.drop([0, 1]) # 删除行
df1.drop('band', axis = 1) # 删除列需要指名axis是1,默认是0,删除多列用列表的形式
4)DataFrame利用loc和iloc进行切片
具体例子如下:
# 取列
print('-取列-')
print( df1.loc[:, 'band'] ) # 前面的冒号不可省略,代表取全部行
print( df1.iloc[:, 1] ) # 前面的冒号不可省略,代表取全部行
#--多列--#
print('--取多列--')
print( df1.loc[:, ['band', 'type']] ) # 前面的冒号不可省略,代表取全部行
print( df1.iloc[:, 0:2] ) # 如果删除冒号则变成取行了
# 取行
df3 = pd.DataFrame(np.arange(0, 10).reshape(5, 2),
columns = ['col1', 'col2'],
index = ['a', 'b', 'c', 'd', 'e'])
print('-取行-')
print( df3.loc['a'] ) # 后面不可加冒号
print( df3.iloc[1] )
#--多行--#
print('--取行--')
print( df3.loc[['a', 'b']] ) # 后面不可加冒号
print( df3.iloc[0:2] )
# 同时取行和列
print('-取行和列-')
print( df3.loc['a', 'col1'] ) # 后面不可加冒号
print( type(df3.loc['a', 'col1']) )
print( df3.iloc[0:1, 1:2] ) # 前面如果加冒号,则代表取行列,注意!
# 注意两种方法返回的类型不一样
(1) 删除
使用drop函数可删除行和列
(2) 排序
使用sort_index, sort_values或者order:
(3) 重命名
有两种方式:
(4) 替换
值的替换采用replace函数。例如当某列中包含了特定值999,想要将其替换为0,则可以:
import pandas as pd
mtcars = pd.read_csv('https://gist.githubusercontent.com/seankross/a412dfbd88b3db70b74b/raw/5f23f993cd87c283ce766e7ac6b329ee7cc2e1d1/mtcars.csv')
mt_1 = mtcars.drop('mpg', axis=1)
mt_2 = mtcars.sort_values(by=['mpg', 'model'])
mt_3 = mtcars.rename(columns={'mpg':'mpower'})
print(mt_1.head())
print(mt_2.head())
print(mt_3.head())
两个函数filter或select,均可实现行列的筛选,当然索引和切片同样可以实现。
filter:共有四个参数item、like、regex、axis
. item用来指定选中轴上的标签,即如果axis指定列,此处指定的即为列名
. like Keep labels from axis for which “like in label == True”
. regex指定正则表达式
. axis指定轴,默认参数为行,注意!
select:0.21版本后不推荐使用,建议使用loc实现
query:Alternative solution that uses .query() method:
df.query("countries in @countries")
df.query("countries not in @countries")
@用来指定外部对象
df.drop_duplicates(subset=['sex'], keep='first', inplace=True)
包含参数:
subset,为选定的列做distinct,默认为所有列;
keep,值选项{'first', 'last', False},保留重复元素中的第一个、最后一个,或全部删除;
inplace ,默认为False,返回一个新的dataframe;若为True,则返回去重后的原dataframe
mt_4 = mtcars.filter(items=['mpg', 'model'])
mt_4.head()
拼接:即列与列合并,也称为横向合并,使用merge函数,使用方式与sql数据库中一致。
merge常用的参数:
. on:指定连接的健,当健名不同时,使用left_on, right_on
. how:用来指定连接方式:inner、left、right、outer
. suffiex:用来指定同名列的后缀
其他参数详见帮助文档
轴向连接:即按照不同的轴(行或列)实现数据框之间的连接,同样可以实现merge的功能,常用函数为concat。
concat常用参数:
. obj:必须为列表或者字典
. axis:轴,0和1
. join:只有outer和inner两个值,指名轴方向上,索引的连接方式
#----横向拼接----#
mt_left = mtcars[['model', 'mpg']][0:10]
mt_right = mtcars[['model', 'gear']][5:15]
mt_me = pd.merge(mt_left, mt_right, on='model', how='left')
#----纵向追加----#
mt_up = mtcars.iloc[0:5]
mt_down = mtcars.iloc[5:10]
mt_ap = pd.concat([mt_up, mt_down], axis=0)
通常称为数据库长宽转换,在pandas中共有两组可以实现这一功能。
mt_pivt = pd.pivot(mtcars, index='model', columns='cyl', values='mpg')
mt_pivt.head(8)
mt_melt = pd.melt(mtcars.iloc[0:10], id_vars='model', value_vars=['mpg', 'cyl'], value_name='mpg_cyl', var_name="variable")
mt_melt.head(20)
通常将series转换为string(.str即可))格式,再进行字符串操作,此操作即为矢量化
见单独学习笔记,python中使用re库进行正则表达式操作
ser = pd.Series(['a123 ', 'b2 34', 'c567'])
print(ser.str.strip())
print(ser.str.cat(sep=':'))
print(ser.str.slice(0, 1))
Python时间和日期操作需要用到datetime、time、calendar标准库模块。本文主要介绍datetime包,它比time包更高级。
datetime模块的数据类型:
datatime模块的now()函数,返回一个datetime对象,则具有以下属性:
from datetime import datetime
#--获得当前时间戳--#
time_now = datetime.now()
print('当前时间戳:', time_now)
#--查看datetime对象的属性--#
print('年份:', time_now.year)
#--datetime转成字符串--#
print('datetime转成字符串:', str(time_now))
print('日期时间格式:', time_now.strftime('%Y-%m-%d'))
#-字符串转成datetime--#
time_input = datetime.strptime('2010-01-01', '%Y-%m-%d')
print(time_input)
matlibplot库是由John Hunter在2002年开始开发的图形包,旨在实现matlab式的图形接口,后由ipython的开发者之一的Fernando参与联合开发。
matlibplot是一个比较底层的图形库,功能很强大,但是对于常见的统计作图并不方便。
(1) matlibplot架构,从表层到底层可分为三层:
(2) matlibplot画图对象构成(自上而下):
(3) matlibplot画图基本步骤
plot()函数为基本画图命令,有以下参数:
具体示例如下:
import matplotlib.pyplot as plt
#--one plot--#
plt.figure()
plt.plot(mtcars['mpg'], mtcars['hp'], linestyle='dashed', color='red')
plt.plot(mtcars['mpg'], mtcars['gear'], linestyle='dashed', color='blue')
plt.title('mpg vs hp')
plt.legend(['hp', 'gear'])
plt.grid()
plt.xlabel('mpg')
plt.ylabel('hp & gear')
plt.show()
#--two plot--#
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2)
ax1.plot(mtcars['mpg'], mtcars['hp'], 'bo') #bo代表blue circle,同时指定了color和linestyle
ax1.set_title('plot one') #若是通过axes实例,属性为set_
ax2.plot(mtcars['mpg'], mtcars['cyl'], linestyle='dashdot', color='red')
ax2.legend('legend')
plt.show()
#--two plot--#
fig, ax = plt.subplots(2, 2)
ax[0, 0].plot(mtcars['mpg'], mtcars['hp'], 'bo') #bo代表blue circle,同时指定了color和linestyle
ax[0, 0].set_title('plot one') #若是通过axes实例,属性为set_
ax[1, 0].plot(mtcars['mpg'], mtcars['cyl'], linestyle='dashdot', color='red')
plt.show()
(1) 关系型
. 散点图:scatter(),scatter有x和y两个数据对象,另有s、c、marker三个常用参数来指定点的大小、颜色、样式
(2) 比较型
. 线图与条图:plot()默认为线图,bar()有x和y两个数据对象,x通常为分类变量,另有yerr画误差线、hatch='\\'指定填充阴影等参数;barh()函数可用来画水平方向的条图;条图的变化最多,如堆积条图、分组条图等,可以见详细的参数来进行自定义。
(3) 分布型
. 直方图:hist(),hist只有x一个数据对象,另有bins参数用来指定区间的个数
(4) 构成型
. 饼图:pie(),pie有三个参数values、lables、colors分别用来指定值、分类、颜色,最后通常需要使用axis('equal')来形成圆形
matplotlib的功能很强大,可以实现很多图形样式,但是由于其代码过于底层,并不适合进行统计作图,统计作图通常使用基于matplotlib封装的seaborn进行作图,见下节
import numpy as np
#--scatter--#
x = np.arange(-2 * np.pi, 2 * np.pi, 0.01)
y = np.sin(x)
fig, ax = plt.subplots(2, 2, figsize=[10, 10])
ax[0, 0].scatter(x, y, s=0.5, c='red')
ax[0, 0].hlines(0, -6, 6, colors='black', linestyle='dashed')
#--bar--#
phone = ['apple', 'huawei', 'sony', 'xiaomi', 'samsung']
price = [1899, 1399, 1499, 1280, 1980]
ax[0, 1].bar(phone, price, hatch='---')
ax[0, 1].set_xlabel('Phone')
ax[0, 1].set_ylabel('Price($)')
#--hist--#
age = np.random.randint(0, 100, 100)
ax[1, 0].hist(age, bins=20)
ax[1, 0].set_xlabel('Age(year)')
ax[1, 0].set_ylabel('Frequency')
#--pie--#
amount = [35, 68, 72, 43, 56]
ax[1, 1].pie(amount, labels=phone,
colors=['red', 'green', 'yellow', 'blue', 'grey'],
explode=[0, 0, 0, 0.3, 0.1])
# plt.savefig('sci_figs.pdf', dpi=300, bbox_inches='tight')
plt.show()
pandas的数据结构对象也有一个plot的属性,可以用来画一些简单的统计图形。
plot函数的参数:
只适用于dataframe,不适用与series的plot参数:
除plot属性外,还有hist和scatter_matrix()函数
具体而言,对dataframe对象画图时,需要先对数据进行处理成适合画图的结构,再画图
fig, ax = plt.subplots(2, 2, figsize=[8, 8])
mtcars['hp'].hist(ax=ax[0, 0])
mtcars['hp'].plot(kind='kde', ax=ax[0, 1])
mtcars['gear'].value_counts().plot(kind='barh', ax=ax[1, 0])
pd.crosstab(mtcars['gear'], mtcars['cyl']).plot(kind='barh', ax=ax[1, 1])
官方介绍:Seaborn is a library for making statistical graphics in Python. It is built on top of matplotlib and closely integrated with pandas data structures.
根据seaborn的官方文档介绍,将统计图形分成4大类,前两个大类都有一个综合函数以及直接函数,通过kind参数可相互转换:
(1) 关系型图形(Relation):适用于两个数值型变量之间的关系可视化
. 综合函数为relplot(),kind参数可取值为:'scatter','line'(第一个为默认参数)
为了单独使用,还设置了scatterplot()和lineplot()两个直接函数,实际功能和relplot取对应的kind值是一致的
(2) 分类型图形(Categorical):适用于一个分类变量与一个数值变量的关系可视化
. 综合函数为catplot()
. 直接函数:3类7个
- 1)Categorical scatterplots:
. stripplot()
. swarmplot()- 2)Categorical distribution plots:
. boxplot()
. violinplot()
. boxenplot()- 3)Categorical estimate plots: . pointplot()
. barplot()
. countplot()
(3) 分布型图形(Distribution):无综合函数,主要包括单变量或双变量的直方图、密度图
- jointplot(x, y[, data, kind, stat_func, …]) Draw a plot of two variables with bivariate and univariate graphs.
- pairplot(data[, hue, hue_order, palette, …]) Plot pairwise relationships in a dataset.
- distplot(a[, bins, hist, kde, rug, fit, …]) Flexibly plot a univariate distribution of observations.
- kdeplot(data[, data2, shade, vertical, …]) Fit and plot a univariate or bivariate kernel density estimate.
- rugplot(a[, height, axis, ax]) Plot datapoints in an array as sticks on an axis.
(4) 回归图型(Regression):无综合函数,主要适用对回归模型结果的可视化
- lmplot(x, y, data[, hue, col, row, palette, …]) Plot data and regression model fits across a FacetGrid.
- regplot(x, y[, data, x_estimator, x_bins, …]) Plot data and a linear regression model fit.
- residplot(x, y[, data, lowess, x_partial, …]) Plot the residuals of a linear regression.
(5) 矩阵图(Matrix):无综合函数,主要包括热力图和聚类图
- heatmap(data[, vmin, vmax, cmap, center, …]) Plot rectangular data as a color-encoded matrix.
- clustermap(data[, pivot_kws, method, …]) Plot a matrix dataset as a hierarchically-clustered heatmap. Multi
此部分主要介绍通用参数,特定函数的特定参数在有具体需求时详细查询官方文档
个人将通用参数分为两大类:映射参数,标尺参数:
(1) 映射参数:即将数据类型中的变量与图形中的元素对应起来,如颜色、大小、分组等
(2) 标尺参数:即用来定义颜色、大小的取值范围,及取什么颜色、多大多小等
seaborn并未设置title和label等参数,由于seaborn是基于matplotlib的封装,因此可以将seaborn图形赋值为一个对象,调用matplotlib的函数即可:
对色版、图表主题、字体、字号等可以进行全局设置,主要函数为set(),具体参数如下:
context : string or dict Plotting context parameters, see plotting_context()
style : string or dict Axes style parameters, see axes_style()
palette : string or sequence Color palette, see color_palette(),如sns.color_palette("hls", 8)
font : string Font family, see matplotlib font manager.
font_scale : float, optional Separate scaling factor to independently scale the size of the font elements.
color_codes : bool If True and palette is a seaborn palette, remap the shorthand color codes (e.g. “b”, “g”, “r”, etc.) to the colors from this palette.
rc : dict or None Dictionary of rc parameter mappings to override the above.
单独的参数也可使用set_style等形式进行单独设定
可以借用的配置:sns.set(style="ticks", palette="muted")
可以用sns.despine()移除top和right的坐标线
import seaborn as sns
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 3, figsize=[15, 5])
sns.set(style='ticks', palette='muted', font='STSong')
fig = sns.scatterplot(x='qsec', y='disp', hue='cyl', style='cyl', size='cyl', legend='brief', data=mtcars, ax=ax[0])
fig.set(title='A figure drawn by Seaborn',
xlabel='横轴', ylabel='Verticle')
sns.stripplot(x='cyl', y='mpg', hue='gear', data=mtcars, ax=ax[1])
sns.countplot(x='cyl', data=mtcars, ax=ax[2])
sns.despine()
plt.savefig('sns.pdf', dpi=300)
# 如果是用relplot和catplot,当使用ax赋值到不同到坐标系时,会额外输出空白坐标系(可使用plt.close(1)来解决)
# 因为这两个函数为figure-level作图,其他为axes-level
# 设置标题也可以换如下方法:
# sns.scatterplot(x='qsec', y='disp', hue='cyl', style='cyl', size='cyl', data=mtcars, ax=ax[0])
# plt.title('This is the title of Matplotlib object')
sns.distplot(mtcars['disp'])
+ 加 - 两个对象相加
- 减 - 得到负数或是一个数减去另一个数
* 乘 - 两个数相乘或是返回一个被重复若干次的字符串
/ 除 - x除以y
% 取模 - 返回除法的余数
幂 - 返回x的y次幂 ab 为10的20次方
// 取整除 - 返回商的整数部分(向下取整)
== 等于 - 比较对象是否相等 (a == b) 返回 False。
!= 不等于 - 比较两个对象是否不相等 (a != b) 返回 true.
<> 不等于 - 比较两个对象是否不相等。python3 已废弃。 (a <> b) 返回 true。这个运算符类似 != 。
> 大于 - 返回x是否大于y (a > b) 返回 False。
< 小于 - 返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。 (a < b) 返回 true。
>= 大于等于 - 返回x是否大于等于y。 (a >= b) 返回 False。
<= 小于等于 - 返回x是否小于等于y。 (a <= b) 返回 true。
in 如果在指定的序列中找到值返回 True,否则返回 False。 x 在 y 序列中 , 如果 x 在 y 序列中返回 True。
not in 如果在指定的序列中没有找到值返回 True,否则返回 False。 x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。
not in
operation
df[np.isin(df['countries'], c1, invert=True)]
Alternative solution that uses .query() method:
@表明外部引用对象
In [5]: df.query("countries in @countries")
Out[5]:
countries
1 UK
3 China
is 是判断两个标识符是不是引用自一个对象 x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False。
is not 是判断两个标识符是不是引用自不同对象 x is not y , 类似 id(a) != id(b)。如果引用的不是同一个对象则返回结果 True,否则返回 False。
主要的运算函数在numpy库中,但pandas中也提供了部分。区别在于numpy中的运算函数本身不支持矢量运算,而pandas中的运算函数结合groupby时支持矢量运算
(1) 聚合运算函数:指将一组数组或者series计算为标量的运算 ,以下列出的为pandas中对groupby优化了的运算函数
(2) 分组运算函数:指不是返回一个标量的函数
单组统计较为简单,直接应用相应的运算函数即可
数值型:mean等数值型运算函数
分类型:count等分类计数函数
分组描述的基本原理:split-apply-combine
(1) 包含在数据库内部的描述统计:即生成的统计结果常作为变量或者新的数据集的形式存在
此部分主要采用基于groupby函数的操作方法,适用于dataframe和series对象
1) groupby基本语法及知识
groupby操作后得到的实际是一个分组后的对象,可以赋与对象名单独存储
基本语法为:
df['var'].groupby(df['group_var']).func()
或
df.group('group_var')['var'].func()
2) 可以作为分组变量的类型
. dataframe中的变量,即series对象
. 列表:当有多个变量作为分组变量时使用,如groupby(['group_var1', 'group_var2'])
. 字典:当对分组变量二次分组后再分组时使用,如分组变量为a、b、c、d、e、f,现在需要改变分组,将a、b分为high,c、d分为medi,e、f为low,则可采用字典{'a':'high', 'b':'high', 'c':'medi'}(有省略),将字典传入groupby()中,但此方法多适用于按索引进行分组
. 函数:若将函数作为分组对象,其本质是对行(默认)或列的索引进行函数运算后的返回值作为分组对象
. 混合使用:可以将以上对象混合使用
3)groupby的常用参数:
. axis:指定分组的轴,默认为0,即按行分组
. as_index:布尔值,默认为true,输出结果时是否包含分组变量
. add_prefix:并非groupby的参数,可在func后面使用,对生成对列添加前缀
4) 分组后计算函数的使用
. 对于经过优化的运算函数,其支持矢量运算,直接应用与groupby的对象即可,如df.groupby('group_var')['var'].mean()
. 对于未经优化的函数或者是自定义函数,需要使用aggregate或apply或transform函数
. 其中apply适用度最高,aggregate(缩写为agg)只适用聚合操作,transform对函数的返回值有要求,因此主要介绍apply
5) apply的应用:
即所有不支持矢量运算的函数,均应该放在apply中再执行,如df.groupby('group_var')['var'].apply(func),注意这里函数不带括号了
apply函数的默认参数有apply(func, axis, *args, **kwds)
. axis是用来指定作用轴,默认为0,即向row的方向逐个遍历
. *args为可变参数,用来传入func的多个参数,必须为元祖,且参数位置顺序不可变,也不可少,位置需要用,占位
. **kwds为关键字参数,同样用来传入func的多个参数,必须为字典apply有三种衍生的应用场景:
. 单变量单函数: 即只有一列执行一个函数运算,apply(func)即可,若需要在输出对象中不使用函数名作为变量名,则可以将('name', func)的元组传入apply()
. 单变量多函数: 即一列需执行多个函数运算,则需要将函数组合成列表再传入apply,如apply([func1, func2]),如果同样需要改名,则列表中传入的对象为元组即可
. 多变量多函数: 即不同的列执行不同的操作,则需要利用字典,将列名与函数名映射起来,如apply({'var1':'func1', 'var2':'func2'}),如果同时包含上述需求,组合使用即可
. 以上操作均先单独生成元组、列表、字典对象,再将对象名传入apply
. 字典实际也可以自定义为函数形式,return字典就可以
. groupby对象应用func后返回的对象实际为包含层次索引的dataframe或series,可使用stack和unstack对结构进行转换
1) apply函数的使用,对行或列应用某个函数
df.apply(fun, axis=0) 行
df.apply(fun, axis=1) 列
通常情况下apply返回一个标量,但也可以返回一个series,例如:
def func(x):
return pd.Series([x.max(), x.min()], index=['max', 'min'])
df.apply(func, axis=1)
2) 当apply函数中传人的func有多个参数时(arg1, arg2, arg3)
则以元组的方式传入额外的参数 data["age"] = data["age"].apply(func, args=(arg2, arg3)) 当只有两个参数时,第一个参数默认参数df的列,第二参数需要再后面补充逗号,即args=(arg2,)
或:
data["age"] = data["age"].apply(func, arg2=value, arg3=value))直接用参数名传入,这种方法更方便
6) map和applymap的应用:
map函数仅适用于series,且传入的func只能带一个参数
applymap函数是对dataframe的所有对象,即单元格进行操作,适用于替换或判断missing value,或者所有对象的格式变换等操作
#-- apply参数func有多个参数情况
import pandas as pd
df = pd.DataFrame({"m": [1, 2, 3], "n": [4, 5, 6]}, index=["a", "b", "c"])
#两个参数
def pluse(x, y):
return x + y
print( df["m"].apply(pluse, args=(3, )) ) # 后面的逗号不可省略
#三个参数
def pluse(x, y, z):
return (x + y) * z
print( df["m"].apply(pluse, args=(3, 2)) )
# 直接传入
print( df["m"].apply(pluse, y=3, z=2) ) # 这种方式更为方便
(2) 输出型的描述统计:即生成的统计结果常作为表格输出
主要包括pivot_table和crosstab两个函数
pivot_table:主要适用于聚合操作的表格输出,主要针对数值操作,分类变量也可以,但较为繁琐,需要注意与pivot的区别,主要参数如下:
. values:需要进行聚合操作的变量名,缺失表示所有数值列
. index:放在表格行上的分组变量名
. columns:放在表格列上的分组变量名
. aggfunc:聚合函数或函数列表,默认为mean
. fill_value:缺失值替换值
. margins:是否添加行列合计及总计,默认为false
. 语法为df.pivot_table(values='var', rows='group_var1', columns='group_var2', aggfunc='mean', fill_value=0)
crosstab:适用分类变量的交叉表操作,共有三个参数如下:
. index: 输出表格的行变量:可以是数组、数组列表、series
. columns: 输出表格的列变量:取值范围同上
. margins: 行列合计
. normalize: 计算百分比,取True表示计算单元格百分比,取‘index’表示计算行百分比,取‘columns’表示计算列百分比
. values和aggfunc: 作用同上
. 语法为pd.crosstab([df['var1'], df['var2']])
其实pivot_table和crosstab的可以完成相同的交叉透视表
具体示例如下:
#--groupby--单变量单函数--#
mtcars.groupby('cyl')['mpg'].mean()
#--groupby--单变量多函数--#
mtcars.groupby('cyl')['mpg'].agg(['mean', 'std'])
#--groupby--单变量多函数(改名)--#
mtcars.groupby('cyl')['mpg'].agg([('Mean', 'mean'), ('STD', 'std')]).add_prefix('mpg_')
#--groupby--单变量多函数(自定义函数apply)--#
def mix(x):
return {'N':x.count(), 'Mean':x.mean(), 'Median':x.median(), 'Min':x.min(), 'Max':x.max()}
mtcars.groupby('cyl')['mpg'].apply(mix).unstack()
#--groupby--多变量多函数--#
mtcars.groupby('cyl')[['mpg', 'hp']].agg({'mpg':'mean', 'hp':'std'})
Pivot table演示
仅演示最复杂的情况
#--pivot_table--#
# 多value变量,多func
mtcars.pivot_table(values=['hp', 'mpg'], index=['cyl', 'gear'], columns='vs', margins=True, aggfunc={'hp': 'mean', 'mpg': 'min'}).round(2)
Crosstab演示
仅演示最复杂情况
#--crosstab--#
pd.crosstab(index=mtcars['gear'], columns=mtcars['vs'], normalize=True, margins=True).style.format('{:.2%}')
#--crosstab--#
pd.crosstab(index=mtcars['gear'], columns=mtcars['vs'], normalize='columns', margins=True).style.format('{:.2%}')
(3) 第三方库的使用
一个比较好用的第三方库researchpy,现在最新版是0.1.8
主要函数有:
import researchpy as rp
rp.summary_cat(df["var"])
(4) 批量导入同一个文件夹下的同一类文件
import os
import pandas as pd
os.chdir("/Users/Chi/Documents/Python Doc/COVID-19-master/csse_covid_19_data/csse_covid_19_daily_reports")
file_dir = os.getcwd()
filename = []
for root, dirs, files in os.walk(file_dir):
for file in files:
if os.path.splitext(file)[1] == ".csv":
filename.append(file)
df = pd.DataFrame()
for file in filename:
data = pd.read_csv(file)
df = df.append(data)
官方介绍:s a Python module that provides classes and functions for the estimation of many different statistical models, as well as for conducting statistical tests, and statistical data exploration.
可以看出,该模块不仅支持几乎所有的统计和计量经济回归模型,还支持统计检验
模型风格:Since version 0.5.0 of statsmodels, you can use R-style formulas together with pandas data frames to fit your models.
个人认为R-style formulas是一个相对比较容易理解和更为方便的形式,也降低了两个统计语言之间相互转换的学习成本
官方示例如下:
import numpy as np
import statsmodels.api as sm
import statsmodels.formula.api as smf
import pandas as pd
# Load data
df = sm.datasets.get_rdataset("Guerry", "HistData").data
df = df[['Lottery', 'Literacy', 'Wealth', 'Region']].dropna()
# Fit regression model (using the natural log of one of the regressors)
mod = smf.ols(formula='Lottery ~ Literacy + Wealth + Region', data=df)
res = mod.fit()
res2 = smf.ols(formula='Lottery ~ Literacy + Region', data=df).fit()
# Inspect the results
print(res.summary())
# 注意region这个分类变量,如果在dataframe中是一个character会默认识别为分类哑变量,若是numeric,而又想作为分类变量,可用C()操作符
# If Region had been an integer variable that we wanted to treat explicitly as categorical, we could have done so by using the C() operator:
# smf.ols(formula='Lottery ~ Literacy + Wealth + C(Region)', data=df).fit()
# 输出为html形式
import IPython.core.display as di
di.HTML(res.summary().as_html())
from stargazer.stargazer import Stargazer
star = stargazer.Stargazer([res, res2])
star.title('Result of Regression')
di.HTML(star.render_html())
# https://github.com/mwburke/stargazer/blob/master/examples.ipynb
# 传统方法
# from statsmodels.iolib.summary2 import summary_col
# fitoutput = summary_col([res,res2],stars=True)
# print(fitoutput)
import statsmodels.formula.api as smf
smf.ols()
smf.glm
family=sm.families.Gaussian()或family=sm.families.Gaussian(sm.links.log)
分布函数Gaussian(), Binomial(), Poisson(), NegativeBinomial()
连接函数log, logit, identity
logistic回归
smf.logit
Poisson回归
smf.poisson
其中:
offset参数是用来指定事件发生的总体数,即total sample,需要注意的是要手动进行log转换
exposure参数同样是指定事件发生的总体数,但是其会自动进行log转换,不需要手动指定
使用linearmodels模块
Panel Data Models
Fixed Effects (PanelOLS)
Random Effects (RandomEffects)
First Difference (FirstDifferenceOLS)
Between Estimation (BetweenOLS)
Pooled OLS (PooledOLS)
Fama-MacBeth Estimation (FamaMacBeth)
High-dimensional Regression
Absorbing Least Squares (AbsorbingLS)
Single equation Instrumental Variables (IV) models
Two-stage least squares (2SLS, IV2SLS)
Limited Information ML (LIML, IVLIML)
Generalized Method of Moments (GMM, IVGMM)
Continuously Updating GMM (CUE-GMM, IVGMMCUE)
reference(https://zhiyzuo.github.io/Python-Plot-Regression-Coefficient/)
import pandas as pd
import statsmodels.formula.api as smf
url = "https://raw.githubusercontent.com/vincentarelbundock/Rdatasets/master/csv/datasets/swiss.csv"
df = pd.read_csv(url, index_col=0)
# rename the column name
df.columns = ['fertility', 'agri', 'exam', 'edu', 'catholic', 'infant_mort']
fitted = smf.ols('fertility ~ agri + exam + edu + catholic + infant_mort', data=df).fit()
fitted.summary()
def coef_plot(fit, vars, label, ax):
'''ploting the coef of a fit'''
# extract coef and ci from a model
coef_ci = pd.DataFrame({"vars" : fit.params.index.values[1:],
"coef" : fit.params.values[1:],
"lower" : fit.conf_int().iloc[1:, 0],
"upper" : fit.conf_int().iloc[1:, 1]})
coef_ci["err"] = coef_ci["coef"] - coef_ci["upper"]
df = coef_ci[coef_ci["vars"].isin(vars)]
# plot
df.plot(x="vars", y="coef", kind="scatter", color="black", yerr="err", marker="s", s=80, legend=False, ax=ax)
ax.set_xlabel("")
ax.set_ylabel("Coefficient", fontsize=16)
ax.axhline(y=0, linestyle='--', color='black', linewidth=2)
ax.xaxis.set_ticks_position('none')
ax.set_xticklabels(label, rotation=0, fontsize=16)
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=[8, 5])
ctl_var = ["agri", "exam", "edu", "catholic", "infant_mort"]
label = ["Pre 2 yr", "Pre 1 yr", "Current", "Post 1 yr", "Post 2 yr"]
coef_plot(fitted, ctl_var, label, ax)
fig, ax = plt.subplots(figsize=[8, 5])
ctl_var = ["Region[T.E]", "Region[T.N]", "Region[T.S]", "Region[T.W]", "Literacy"]
coef_plot(res, ctl_var, label, ax)
import pandas as pd
df = pd.read_excel("/Users/Chi/Documents/Temp/italy and us.xlsx")
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="ticks", palette="muted")
fig, ax = plt.subplots(2, 1, figsize=[12, 12])
sns.lineplot("date", "Ep", hue="country", data=df, ax=ax[0])
sns.scatterplot("date", "Ep", hue="country", data=df, ax=ax[0], legend=False)
ax[0].set_title(r"$N_{d+1} = (1+E \cdot p)N_d$", fontsize=20)
ax[0].set_ylabel(r"$1+E \cdot p$", fontsize=15)
ax[0].set_xlabel("")
ax[0].set_xticklabels(["2/25", "2/29", "3/01", "3/05", "3/09", "3/13", "3/17", "3/21"])
sns.lineplot("date", "GF", hue="country", palette=["black", "red"], data=df, ax=ax[1])
sns.scatterplot("date", "GF", hue="country", data=df, ax=ax[1], legend=False)
ax[1].hlines(1, df["date"].min(), df["date"].max(), colors='blue', linestyle='dashed')
ax[1].set_title(r"Growth Factor = $\Delta N_{d+1} / \Delta N_d$", fontsize=20)
ax[1].set_ylabel("Growth Factor", fontsize=15)
ax[1].set_xlabel("")
ax[1].set_xticklabels(["2/21", "2/25", "2/29", "3/01", "3/05", "3/09", "3/13", "3/17", "3/21"])
#plt.savefig("/Users/Chi/Documents/Temp/italy-and-us.pdf")
import pandas as pd
mor = pd.read_excel("/Users/Chi/Documents/Temp/morbidity.xlsx")
mor["num"] = mor.index.values + 1
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style='ticks', palette='muted', font='STSong')
def change_width(ax, new_value) :
for patch in ax.patches :
current_width = patch.get_width()
diff = current_width - new_value
# we change the bar width
patch.set_width(new_value)
# we recenter the bar
patch.set_x(patch.get_x() + diff * .5)
fig, ax = plt.subplots(2, 1, figsize=[10, 12])
def covid(var, ax, label, title, lim):
sns.barplot(x="num", y=var, hue="country", data=mor, ax=ax, dodge=False)
for x, y in zip(mor["num"], mor[var]):
ax.text(x-1, y*1.02, round(y, 2), horizontalalignment="center")
change_width(ax, .35)
ax.set_ylabel(label, fontsize=18)
ax.set_xlabel("")
ax.set_title(title, fontsize=20)
ax.set_xticklabels(mor["region"])
ax.set_ylim(ymax=lim)
plt.legend(title="Country")
covid("incidence", ax[0], "Incidence (per thousand)", "Incidence of COVID-19", 5)
covid("inc_area", ax[1], "Case Density ($person/km^2$)", "Case Density of COVID-19", 28)
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
sns.set(style='ticks', palette='muted', font='STSong')
def bin(n, p, size, ax):
rd_1 = np.random.binomial(n, p, size=size)
ax.hist(rd_1, bins=20)
ax.set_title(f"事件成功概率为{p},每次试验{n}次事件,进行{size}次试验", fontsize=15)
ax.set_xlabel("事件成功次数", fontsize=12)
ax.set_ylabel("频数", fontsize=12)
# fig, ax = plt.subplots(2, 2, figsize=[16, 16])
# bin(100, 0.2, 100, ax[0, 0])
# bin(100, 0.2, 1000, ax[0, 1])
# bin(100, 0.2, 10000, ax[1, 0])
# bin(100, 0.2, 50000, ax[1, 1])
fig, ax = plt.subplots(2, 2, figsize=[16, 16])
bin(20, 0.2, 1000, ax[0, 0])
bin(50, 0.2, 1000, ax[0, 1])
bin(100, 0.2, 1000, ax[1, 0])
bin(200, 0.2, 1000, ax[1, 1])
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import seaborn as sns
sns.set(style='ticks', palette='muted', font='STSong')
# calculate coordinates
def circle(a, b, r):
theta = np.arange(0, 2*np.pi, 0.01)
x = a + r * np.cos(theta)
y = b + r * np.sin(theta)
return x, y
x1, y1 = circle(0, 0, 3)
x2, y2 = circle(0, 0, 2.75)
# plot
fig, ax = plt.subplots(1, 1)
ax.plot(x1, y1, color="black")
ax.plot(x2, y2, color="black")
ax.axis('equal')
ax.axis('off')
ax.hlines(y=-1, xmin=x2.min()+0.5, xmax=x2.max()-0.5, color="black")
# add text
plt.text(-1.6, 1.2, "s", color="green", fontsize=32, family="serif", style="oblique", ha="center")
plt.text(-0.6, 1.2, "ata", color="red", fontsize=32, family="serif", style="oblique", ha="center")
plt.text(0.35, 1.2, "r", color="blue", fontsize=32, family="serif", style="oblique", ha="center")
plt.text(1.2, 1.2, "py", color="orange", fontsize=32, family="serif", style="oblique", ha="center")
plt.text(0, -1.8, "肆大派", color="black", fontsize=22, family="STsong", style="normal", ha="center")
plt.text(-2.2, 0, "Science", size=12, ha="left", va="center", rotation=30,
bbox={"boxstyle": "round", "ec": "black", "fc": "lightgreen", "alpha": 0.8})
plt.text(-0.8, 0, "Data", size=12, ha="left", va="center", rotation=-30,
bbox={"boxstyle": "round", "ec": "black", "fc": "yellow", "alpha": 0.8})
plt.text(0.4, 0, "R", size=12, ha="left", va="center", rotation=-30,
bbox={"boxstyle": "round", "ec": "black", "fc": "lightblue", "alpha": 0.8})
plt.text(1.2, 0, "Python", size=12, ha="left", va="center", rotation=30,
bbox={"boxstyle": "round", "ec": "black", "fc": "Orange", "alpha": 0.8})
plt.savefig("wechat-logo.pdf")
import numpy as np
import matplotlib.pyplot as plt
# ensure your arr is sorted from lowest to highest values first!
arr = np.random.randint(1, 100, 150)
arr.sort()
def gini(arr):
count = arr.size
coefficient = 2 / count
indexes = np.arange(1, count + 1)
weighted_sum = (indexes * arr).sum()
total = arr.sum()
constant = (count + 1) / count
return coefficient * weighted_sum / total - constant
def lorenz(arr):
# this divides the prefix sum by the total sum
# this ensures all the values are between 0 and 1.0
scaled_prefix_sum = arr.cumsum() / arr.sum()
# this prepends the 0 value (because 0% of all people have 0% of all wealth)
return np.insert(scaled_prefix_sum, 0, 0)
# show the gini index!
print(gini(arr))
lorenz_curve = lorenz(arr)
# we need the X values to be between 0.0 to 1.0
plt.plot(np.linspace(0.0, 1.0, lorenz_curve.size), lorenz_curve)
# plot the straight line perfect equality curve
plt.plot([0,1], [0,1])
plt.show()
''' individual-level dataset must include three essencital variables: id, health sector variable, live standard variable
then, we can calculate fractional rank from econ_var and cumulative proportion of the population from id
'''
def con_index(heal_var, living_var):
df = pd.DataFrame({"health": heal_var, "living": living_var})
fract_rank = living_var.rank(ascending=True, method='average')
cov_h_l = np.cov(heal_var, fract_rank)[1, 0]
mean_h = heal_var.mean()
return (2 / mean_h) * cov_h_l
np.random.seed(2020)
health = pd.Series([15, 12, 14, 17, 22, 28, 30, 12, 12, 11, 15, 50, 54, 56, 48, 89])
income = pd.Series([1, 4, 6, 7, 8, 9, 1, 2, 3, 6, 7, 8, 8, 9, 9, 10])
con_index(health, income)
def con_curve(heal_var, living_var):
df = pd.DataFrame({"health": heal_var, "living": living_var})
df.sort_values(by="living", ascending=True)
health_cuml = np.array(df["health"].cumsum() / df["health"].sum())
return np.insert(health_cuml, 0, 0)
cc = con_curve(health, income)
# we need the X values to be between 0.0 to 1.0
plt.plot(np.linspace(0.0, 1.0, cc.size), cc)
# plot the straight line perfect equality cu
plt.plot([0,1], [0,1])
plt.show()
def lorenz(arr):
# this divides the prefix sum by the total sum
# this ensures all the values are between 0 and 1.0
scaled_prefix_sum = arr.cumsum() / arr.sum()
# this prepends the 0 value (because 0% of all people have 0% of all wealth)
return np.insert(scaled_prefix_sum, 0, 0)
# show the gini index!
print(gini(arr))
lorenz_curve = lorenz(arr)
# we need the X values to be between 0.0 to 1.0
plt.plot(np.linspace(0.0, 1.0, lorenz_curve.size), lorenz_curve)
# plot the straight line perfect equality curve
plt.plot([0,1], [0,1])
plt.show()
income.size
import numpy as np
def area_calculator(length, moved_len):
# calculate the radius
r = (length - moved_len) / 2
# make a vertical line from cross point
delta_vertical_to_focus2 = r - (2 * r - moved_len) / 2
vertical_line_len = np.sqrt(r**2 - delta_vertical_to_focus2**2)
# calculate the area of triangle
area_triangle = 0.5 * vertical_line_len * delta_vertical_to_focus2
# calculate the area of sector
area_sector = (np.pi * r**2) * np.arccos(delta_vertical_to_focus2 / r) / (2 * np.pi)
# calculate the area of shadow
area_shadow = 0.5 * (np.pi * r**2) - 2 * (area_sector - area_triangle)
return f"当移动距离为 {moved_len} 厘米,下底横线长度为 {length} 厘米时,阴影部分面积为: {area_shadow} 平方厘米"
area_calculator(10, 2)
def area_calculator(r, moved_len):
# make a vertical line from cross point
delta_vertical_to_focus2 = r - (2 * r - moved_len) / 2
vertical_line_len = np.sqrt(r**2 - delta_vertical_to_focus2**2)
# calculate the area of triangle
area_triangle = 0.5 * vertical_line_len * delta_vertical_to_focus2
# calculate the area of sector
area_sector = (np.pi * r**2) * np.arccos(delta_vertical_to_focus2 / r) / (2 * np.pi)
# calculate the area of shadow
area_shadow = 0.5 * (np.pi * r**2) - 2 * (area_sector - area_triangle)
return area_shadow
import matplotlib.pyplot as plt
r = 10
move_list = np.arange(0, r, 0.1)
for i in move_list:
area = area_calculator(r, i)
plt.plot(i, area, marker="o", color="blue", markersize=1.5)
plt.xlabel("Moved distance")
plt.ylabel("Area of shadow")
import seaborn as sns
import matplotlib.pyplot as plt
# load dataset from GitHub seaborn repository
tips = sns.load_dataset("tips")
tips.head()
plt.figure(figsize=[8, 5])
fig = sns.barplot(x="day", y="total_bill", hue="sex", palette="magma",
ci=None, data=tips, **{"alpha": 0.8})
fig.set(title="Bar plot",
xlabel="Day",
ylabel="Total Bill")
fig.legend(loc="best")