xjtu_logo


Python in Data Science Learning Note


Shen, Chi

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

In [12]:
# Style with the main css template 
import IPython.core.display as di
css_file = 'custom.css'
di.HTML(open(css_file, "r").read())
Out[12]:
@import url("custom.css");
In [3]:
#                 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)

I. Python Data Science之基本语法

1. 基本数据类型

1.1 数据类型:

  • 整数(int): 8
  • 浮点数(float): 8.8
  • 字符串(str): '8' 'Hello Python'
  • 布尔值(bool): True False

2) type()函数可以用来判断数据类型

3) 数据类型转换函数:int(), str(), bool()

In [2]:
x = 8
y = 8.8
z = 'hello python'
w = True

# 不同数据类型之间相互转换
print(int(y))
print(int(w))
print(str(x))
print(bool(x))
8
1
8
True

2. 序列的定义

1)序列(Sequence)的定义: 是指它的成员有序排列,并可以通过下标(即索引)偏移量来访问成员。

需要注意的是python的索引下标是从0开始的

2)类型:

  • 字符串(str): 'abc'
  • 列表(list): [0, 'abc'], 内容可变更
  • 元组(tuple): ('abc', 'def'),内容不可变更

3)class()函数可以用来判断序列类型

4)序列操作符:

  • 判断操作符:判断某个字符是否在一个序列中 “a” in “abc” 判断不在用not in
  • 连接操作符: +,序列+序列
  • 重复操作符: ,序列\整数
  • 切片操作符: [:],序列[0:整数]

索引 (indexing) 和切片 (slicing) 语法:

  • 索引位置从 0 开始
  • 切片通常写成 start:end 这种形式,包括「start 索引」对应的元素,不包括「end索引」对应的元素。因此 s[2:4] 只获取字符串第 3 个到第 4 个元素
  • 索引值可正可负,正索引从 0 开始,从左往右;负索引从 -1 开始,从右往左。使用负数索引时,会从最后一个元素开始计数。最后一个元素的位置编号是 -1
  • 切片的通用完整的写法是start : stop : step,但是通常step省略且默认为1

2.1 字符串的定义与使用

定义字符串时可以用双引号也可以用单引号

In [28]:
letter = 'abcdefghijk'
number = '12345'
print(letter[1])

print(letter + number)
print(letter * 3)
print(letter[0:5])
print('a' in letter)
b
abcdefghijk12345
abcdefghijkabcdefghijkabcdefghijk
abcde
True

2.2 元组的定义与使用

元组和字符串的区别在于,元组类似R中的vector,同样适用序列操作符

但是与R的vector的区别在于,同一个元组中可以同时存在num和str,并且数据类型不一样,R中vector虽然可以同时混合输入数字和字符,但是数字会被转换成字符类型

In [29]:
mon_day = (1, 20)
mon_day > (2, 20)
Out[29]:
False

元组大小和内容都不可更改,因此只有 count 和 index 两种方法,如下例子:

In [4]:
week = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')

print(week.count('Monday')) #计数
print(week.index('Friday')) #取索引位置
1
4

2.3 列表的定义与使用

列表和元组一样,最大的区别在于可以变更,变更即意味着可以增加(append)、减少(remove)、插入 (insert)、删除 (remove, pop) 成员

  • append 是追加,把一个东西整体添加在列表后
  • extend 是扩展,把一个东西里的所有元素添加在列表后
  • insert(i, x) 在编号 i 位置前插入 x
  • remove 和 pop 都可以删除元素
    • 前者是指定具体要删除的元素,比如 'python'
    • 后者是指定一个编号位置,比如 3,删除 l[3] 并返回出来

例子如下:

In [5]:
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)
[1, 2, 'c']
[1, 2, 'c', 'hello']
[1, 2, 'c', 'hello', 'a', 'b', 3]
[1, 2, 'python', 'c', 'hello', 'a', 'b', 3]
[1, 2, 'python', 'c', 'hello', 'b', 3]

3. 字典的定义

字典(dict)不属于序列,其本质是映射,形式为一个key对应一个value,key即是哈希值

字典和列表一样是可以变更的,也同样支持索引

字典里最常用的三个内置方法就是 keys(), values() 和 items(),分别是获取字典的键、值、对。

In [6]:
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)
dict_keys(['Mon', 'Tue', 'Wed'])
dict_values([1, 2, 3])
dict_items([('Mon', 1), ('Tue', 2), ('Wed', 3)])
{'a': 1}

4. 集合的定义

可以使用大括号 { } 或者 set() 函数创建集合:

  • 两个特点:无序 (unordered) 和唯一 (unique)

注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典

In [7]:
set_a = set(['u', 'd', 'ud', 'du', 'd', 'du'])
set_b = {'d', 'dd', 'uu', 'u'}
print(set_a)
print(set_b)
{'d', 'du', 'u', 'ud'}
{'u', 'd', 'dd', 'uu'}

集合的并集、交集、差集:

  • 并:union
  • 交:intersection
  • 差:difference
  • 对称差集:symmetric_difference,All elements in either A or B, but not both
In [8]:
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
{'d', 'dd', 'uu', 'du', 'u', 'ud'}
{'d', 'dd', 'uu', 'du', 'u', 'ud'}
{'d', 'u'}
{'d', 'u'}

5. 条件和循环语句

5.1 if条件语句

if条件语句一共有四种类型:

  • if 语句
  • if-else 语句
  • if-elif-else 语句
  • nested 语句 (不常用)

if语句的执行原理为:如果条件为True,则执行操作,如果条件为False,则不执行操作

elif语句与if语句的区别在于,当多个判断条件嵌套时,如果elif为True,则不再继续执行后面的else语句,为False时才继续执行, 而if语句则不论False或者True都会继续执行

In [9]:
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 小于5
x 等于5
x 等于5
x 小于5

5.2 循环语句

循环语句有while 和 for in两种

while循环

  • 只要条件为True则一直执行
In [10]:
x = 1
while x < 5:
    print(x)
    x += 1
print('循环结束')
1
2
3
4
循环结束

for in循环

  • 通常结合遍历使用
In [11]:
for x in range(1, 5):
    print(x)
print('循环结束')
1
2
3
4
循环结束

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。

In [12]:
workdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
for i, days in enumerate(workdays, 1):
    print(days, '是星期', i)
Monday 是星期 1
Tuesday 是星期 2
Wednesday 是星期 3
Thursday 是星期 4
Friday 是星期 5

5.3 循环控制

循环控制语句一共有三个:

  • break
  • continue
  • pass

break语句:
通常情况下,要想结束一个循环,只能等循环执行完毕或者报错跳出。
想着中途就结束循环,就需要用到break语句。

注意:break只能用于循环体内,其效果是直接结束并退出当前循环,剩下的未循环的工作全部被忽略和取消。

continue语句:
用于跳过当前循环的剩余部分代码,直接开始下一轮循环,即是提前结束当次循环,不影响下一次循环。

pass语句:
没有实际作用,只是为了代码的完整性和可读性,只起到占位的作用。

例子如下:

In [13]:
# break语句

for i in range(1, 10):
    print('I am No.', i)
    if i == 5:
        break
# 可以看出整个循环在5时就结束了,需要注意的时当循环嵌套时,break只结束所在的循环
I am No. 1
I am No. 2
I am No. 3
I am No. 4
I am No. 5
In [14]:
# pass语句

for i in range(1, 10):
    print(i)
    if i == 5:
        continue
    print('No. %s is not jumped' %i) # 可以看出使用了continue语句,只会跳过continue后面还未执行的代码,并不影响前面的代码,整个循环会继续
1
No. 1 is not jumped
2
No. 2 is not jumped
3
No. 3 is not jumped
4
No. 4 is not jumped
5
6
No. 6 is not jumped
7
No. 7 is not jumped
8
No. 8 is not jumped
9
No. 9 is not jumped

6. 列表、字典和集合推导式

推导式comprehensions(又称解析式),是Python的一种独有特性。
推导式是可以从一个数据序列构建另一个新的数据序列的结构体,共有三类:

  • 列表推导式
  • 字典推导式
  • 集合推导式

具体而言,就是推导式用for循环遍历旧的序列,用if条件筛选旧的序列,将结果返回给新的序列。

6.1 列表推导式

问题一:如何从一个含整数列表中奇数乘以2再输出?

In [15]:
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
[2, 6, 10, 14, 18]
Out[15]:
[2, 6, 10, 14, 18]

问题二:当循环嵌套时如何写推导式?
将二维元组里每个元素提取出来并存储到一个列表中:tup = ((1, 2, 3), (4, 5, 6), (7, 8, 9))

In [16]:
tup = ((1, 2, 3), (4, 5, 6), (7, 8, 9))

list_a = [n for item in tup for n in item]
list_a
Out[16]:
[1, 2, 3, 4, 5, 6, 7, 8, 9]

6.2 字典推导式

原则上同理,只是字典涉及到key和value,例如

In [17]:
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)
{'Mon': 10, 'Thu': 10, 'Fri': 10}
{10: 'Fri', 12: 'Tue', 15: 'Wed'}

7. 函数的定义与使用

函数(function)在python中共有三大类:

  • 常规函数,用def定义
  • 匿名函数,用lambda定义
  • 高阶函数

7.1 常规函数

语法形式:

def func_name(var1, var2 = 1, *var3, **var4, *, var5): statement

常规函数的四类参数类型:

  • 位置参数 (positional argument),即var1
  • 默认参数 (default argument),即var2,也就是在定义函数时已经给了默认值, 但是要注意的是,默认参数一定要在位置参数后,否则报错
  • 可变参数 (variable argument),即var3,前面的*不能省略,可变的意思是指该参数名下传入的参数可以是大于0的任意个数,默认以元组的形式传入函数。
  • 关键字参数 (keyword argument),即var4,前面的**不能省略,意义与可变参数一样,但是默认是以字典的形式传入函数。
  • 命名关键字参数 (name keyword argument),用户想要输入的关键字参数,定义方式是在nkw 前面加个分隔符 *。 注意:命名关键字参数,在调用函数时,必须写上参数名
  • 参数组合,将以上参数组合,但是有顺序要求

例子:

In [18]:
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)
3
5
11
11
11
{'a': 4, 'b': 5, 'c': 6}

7.2 匿名函数

匿名函数又称为lambda函数,是对常规函数的一种省略写法,具体特点为:

  • 只能写在一行,不能换行
  • 只是省略了函数名和return
  • 通常和python的内置函数(filter,reduce, map,zip)联用做一些简单计算

基本语法为: lambda arg_list: expression

例如

In [19]:
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))
[2, 4, 6, 8, 10]
[2, 4]

7.3 高阶函数

高阶函数 (high-order function) 在函数化编程 (functional programming) 很常见,主要有两种形式:

  • 参数是函数 (map, filter, reduce)
  • 返回值是函数 (closure, partial, currying)

python的内建函数就属于第一种:

  • map(函数 f, 序列 x):对序列 x 中每个元素依次执行函数 f,将 f(x) 组成一个「map 对象」返回 (可以将其转换成 list 或 set)
  • filter(函数 f, 序列 x):对序列 x 中每个元素依次执行函数 f,将 f(x) 为 True 的结果组成一个「filter 对象」返回 (可以将其转换成 list 或 set)
  • reduce(函数 f, 序列 x):对序列 x 的第一个和第二个元素执行函数 f,得到的结果和序列 x 的下一个元素执行函数 f,一直遍历完的序列 x 所有元素。

闭包属于第二种高阶函数:

Python 里面的闭包 (closure) 属于第二种高阶函数,返回值是函数。 闭包就是函数的嵌套

下面是一个闭包函数。

In [20]:
def sum(a):
    def add(b):
        return a + b
    return add

sum_res = sum(1) 
type(sum_res) # 注意此时返回的sum_res实际是一个函数,可以将其作为函数进行调用

print(sum_res(2))
3

闭包的应用

  • 计步器
  • 解方程
In [21]:
# 计步器
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())
2
3
4
6
7
8
In [22]:
# 解二元一次方程(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))
11
17
8
35

8. 函数的装饰器

装饰器(Decorators)是 Python 的一个重要部分。简单地说:装饰器是修改其他函数的功能的函数,有助于让代码更简短。本质是闭包的扩展用法。
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

比如,如果已经定义好了10个函数,现在额外增加一个需求:计算函数运行的时间。如果重新返回对10个函数进行修改,则需要重复修改10遍,这时就可以利用装饰器,简化操作。

具体例子如下:

In [23]:
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))
5
add function has run 0.00040912628173828125 seconds
Decorators end

更进一步的要求是不同的函数执行同一个装饰器中的不同功能

例如,一个函数执行计算执行时间,另一个函数执行运行提示

In [24]:
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')
11
add function has run 0.0003437995910644531 seconds
hello function begins running
Hello python
hello function ends running

9. 模块的定义与使用

模块很简单,就是将自定义的.py文件,通过import导入到新的环境中,文件名就是模块名

10. 类的定义与使用

类(Class): 用来描述具有相同的属性(attribute)和方法(method)的对象的集合。该集合中每个对象具有相同的属性和方法。对类进行实例化(instance)就生成了对象。

例如:汽车就是一个类,而品牌、型号、颜色、变速箱就是汽车的属性,而加速、转弯、刹车就是汽车共有的功能或者方法,本质就是函数。

In [25]:
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)
这是一个关于汽车的类
Civic
Honda Civic AT 的加速成绩特别好
white

11. 面向对象编程在数据科学中的应用

面向对象技术简介:

类(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

在数据科学中,更多的应该是对变量进行归类,这类变量具有相同的属性以及需要执行相同的操作,特别是在数据清洗阶段。

  • 如果需要转变为面向对象编程,就需要转变思维,整个数据科学项目不再是拿到数据后step-by-step的去实现
  • 而是在项目开始之前就将需要操作的变量和操作进行归类,寻找变量与操作之间的共同点,其本质就是对观测(observation)划分类,通过设置类,寻找具有相同属性和方法的观测,通过实例化来完成数据科学项目。
  • 观测(observation)的属性实际就是通过不同的变量组合来进行区分,而方法就需要对观测执行的操作,比如在数据清洗阶段的寻找异常值、缺失值,在描述分析阶段的分组及分组统计等。
In [26]:
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()
Out[26]:
7.875

12. 异常处理

异常的定义

异常即是一个事件,该事件(如错误)在程序执行过程中发生,影响了程序的正常执行
一般情况下,在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则是不管异常是否发生都执行以下操作。

In [27]:
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)
#-------- Example 1 -------#
错误:对象不存在!
程序执行完毕
#-------- Example 2 -------#
错误:对象不存在! name 'c' is not defined
程序执行完毕
#-------- Example 3 -------#
1
程序执行完毕
#-------- Example 4 -------#
1
程序执行完毕
#-------- Example 5 -------#
1
程序执行完毕
#------- 手动促发异常 -------#
错误: 输入的变量小于0

13. 文件的读写(IO)

是非常常见和有用的操作,分为读(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操作进行简化。

具体例子如下:

In [47]:
# 读取
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')
Hello Python
Hello World
Happy New Year
Hello Python

Hello World

Happy New Year

II. Python Data Science之数据库操作

1. NumPy库的介绍及使用

1.1 NumPy简介

NumPy是numeric python的缩写,其前身为1995年由Jim Hugguin开发的numeric包,之后由Travils Olivant于2006年发布了numpy的第一个发行版,现在是python的基础库。

整个numpy库的核心就是n维数组ndarray(n dimensional array),指的是具有同质同大小的一组元素。

关于ndarray的基本概念:

  • 型(shape): 即用来描述数组的维度,以及每一维度的长度,由元组来确定。
  • 轴(axes): 数组的维度又称为轴,而轴的数量称为秩(rank), 比如一个2维数组,那么这个数组的秩就是2。
  • dtype: ndarry有一个新的数据类型属性,dtype。

1.2 创建n维数组

两种方式:

  • 利用numpy包中的array函数,结合列表,创建ndarray
  • 痛仰是用array函数,还可以传入元组,以及列表和元组混合
In [30]:
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)
[1 2 3 4 5]
[[ 1  2  3  4  5]
 [ 6  7  8  9 10]]
[[ 1  2  3  4  5]
 [ 6  7  8  9 10]]

1.3 查看n维数组的属性

共有4中属性:

  • ndim:查看轴的数量
  • size:查看数组长度,就是轴数量 与 每条轴长度 的乘积
  • shape:数组的型,就是 轴数量,轴长度
  • itemsize:表示数组中每个元素的字节
  • data:数据实际元素的缓冲区,不常用
In [31]:
print( b.ndim )
print( b.size )
print( b.shape )
print( b.itemsize )
2
10
(2, 5)
8

1.4 预设创建数据函数

共有5个函数:

  • zeros():创建全是0的数组,只需要指定维度,以及每维长度
  • ones():创建全是1的数组,只需要指定维度,以及每维长度
  • arange():创建指定区间的数组,需要指定区间、维度,以及每维长度
  • linespace():与arange相似,但是第三个参数是用来将区间切分为组的
  • random:将一组随机数字创建为数组
In [32]:
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)
[[0. 0. 0.]
 [0. 0. 0.]]
[[1. 1. 1.]
 [1. 1. 1.]]
[[ 1  2  3  4  5]
 [ 6  7  8  9 10]]
[ 1.   3.5  6.   8.5 11. ]
[0.39891349 0.08455814 0.10669926 0.82511391 0.08941182 0.30457922
 0.48917027 0.00488054 0.55982357 0.4986448 ]
[[0.66022576 0.26959079 0.43281628 0.01699986 0.30596501]
 [0.74394341 0.02631349 0.07642746 0.08519971 0.47457166]
 [0.79886989 0.40055746 0.25048555 0.14672594 0.92873543]
 [0.07919575 0.08963657 0.05145185 0.4518491  0.01113728]
 [0.66253902 0.01591283 0.57187602 0.53763535 0.00507342]]

1.5 数组的运算

n维数组支持常规的算术运算和逻辑运算,需要注意一个就是矩阵积(dot),相对简单,不做详细介绍


1.6 数组的索引、切片、遍历

索引:

  • 一维数组:单个索引:a[1]; 多个索引a[ [1, 2] ]
  • 二维数组:单个索引:b[1, 1], 逗号前代表轴,逗号后代表轴内第几个元素;多个索引:b[ [1,2], [1, 2] ]

切片:

  • a[1:2:1] 与序列的切片同理

遍历:

  • 一维数组遍历同序列
  • 二维及以上数组遍历,是逐一遍历每一个轴,如果想要将多维数组打平,使用flat,如a.flat
In [33]:
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表示列,即按长度计算
数组a是: [1 2 3 4 5 6 7 8 9]
数组b是: [[10 11 12 13 14 15 16 17 18 19]
 [20 21 22 23 24 25 26 27 28 29]
 [30 31 32 33 34 35 36 37 38 39]]
索引: 2
索引: [2 3]
索引: 21
索引: [21 32]
切片: [3 4]
删除 [1 4 5 6 7 8 9]
多维数组删除 [[10 11 12 13 14 15 16 17 18 19]
 [30 31 32 33 34 35 36 37 38 39]]
一维遍历: 1
一维遍历: 2
一维遍历: 3
一维遍历: 4
多维遍历: [1 2 3]
多维遍历: [4 5 6]
多维打平遍历: 1
多维打平遍历: 2
多维打平遍历: 3
多维打平遍历: 4
多维打平遍历: 5
多维打平遍历: 6
Out[33]:
array([2.5, 3.5, 4.5])

1.7 数组条件与判断

  • 判断: a < 5, 返回bool值的数组
  • 条件: a[ a < 5],返回小于5的元素组成的数组

1.8 数组形状变化

  • reshape(dim, length): 一维变多维
  • ravel(): 多维变一维
  • transpose(): 行列互换,也就是轴与长度互换

1.9 数组的拼接与拆分

拼接:

  • vstack和hstack:分别表示纵向合并,和横行合并
  • column_stack 和 row_stack:类似与r中的rbind和cbind,这个应该比上面两个更实用

拆分:

  • hsplit
  • vsplit

1.10 数组的读写

  • save:写入,文件格式为npy
  • load:读取

2. Pandas库的介绍及使用

2.1 Pandas库简介

Pandas是python进行数据分析过程中的核心库。于2008年开始开发,2012年正式上线。

2.2 Pandas库基本操作

1)数据结构

共定义了两种有别于python自带和numpy的数据结构:

  • Series: 即只有一列的dataframe,具有index和values两个属性
  • DataFrame: 同r中的dataframe,即电子表格

2)创建Series和DataFrame

  • 创建 Series:即利用Series函数将数组或者列表转换成series对象,同时也可用index参数指定索引列
  • 创建DataFrame:即利用DataFrame函数将字典转换成dataframe,或者通过指定数组,columns和index来创建

具体例子如下:

In [34]:
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)
序列1: 0    1
1    a
2    2
3    b
dtype: object
序列2: r1    1
r2    a
r3    2
r4    b
dtype: object
数据框1:          band    type
0       honda   civic
1  volkswagen    golf
2      toyota  crolla
3       mazda    mx-5
数据框2:    col1  col2
1     0     1
2     2     3
3     4     5
4     6     7
5     8     9

3)Series和DataFrame的索引与切片

  • Series的索引和切片与之前的序列和数组并无较大差别,但多了reindex和drop两个函数,分别是重置索引和删除某个索引
  • DataFame在进行取列操作时有两种方式: df['col1'] 或者将列名作为数据框的属性进行操作 df.var1

具体例子如下:

In [35]:
# 索引
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,删除多列用列表的形式 
序列索引: a
序列索引: 1
数据框索引: 0         honda
1    volkswagen
2        toyota
3         mazda
Name: band, dtype: object
数据框索引: 0         honda
1    volkswagen
2        toyota
3         mazda
Name: band, dtype: object
序列切片: 1    a
2    2
3    b
dtype: object
数据框切片: 1    volkswagen
2        toyota
3         mazda
Name: band, dtype: object
Out[35]:
type
0 civic
1 golf
2 crolla
3 mx-5

4)DataFrame利用loc和iloc进行切片

  • loc主要是对index的label进行切片
  • iloc主要是对index的位置进行切片

具体例子如下:

In [36]:
# 取列
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] ) # 前面如果加冒号,则代表取行列,注意!

# 注意两种方法返回的类型不一样
-取列-
0         honda
1    volkswagen
2        toyota
3         mazda
Name: band, dtype: object
0     civic
1      golf
2    crolla
3      mx-5
Name: type, dtype: object
--取多列--
         band    type
0       honda   civic
1  volkswagen    golf
2      toyota  crolla
3       mazda    mx-5
         band    type
0       honda   civic
1  volkswagen    golf
2      toyota  crolla
3       mazda    mx-5
-取行-
col1    0
col2    1
Name: a, dtype: int64
col1    2
col2    3
Name: b, dtype: int64
--取行--
   col1  col2
a     0     1
b     2     3
   col1  col2
a     0     1
b     2     3
-取行和列-
0
<class 'numpy.int64'>
   col2
a     1

3 数据库之基本操作

3.1 变量的排序、重命名、删除

(1) 删除
使用drop函数可删除行和列

  • 删除行:df.drop('row index')
  • 删除列:df.drop('var', axis = 1) 或使用del df['var']

(2) 排序
使用sort_index, sort_values或者order:

  • 对于series,对索引排序使用sort_index,对元素排序使用order。如:ser.sort_index() 或ser.order()
  • 对于dataframe,对索引(包括行和列,通过axis指定)排序使用sort_index(),对除索引外的列排序,使用sort_values(by = 'var'),多个排序变量时sort_values(by = ['var1', 'var2'])
  • 通过ascending=False指定升降序

(3) 重命名
有两种方式:

  • 使用rename函数:df.rename(columns={'old_name':'new_name', 'old_name':'new_name'})
  • 直接修改columns属性:colnames = ['var1', 'var2'], df.columns = colnames,类似于R中的colnames函数

(4) 替换
值的替换采用replace函数。例如当某列中包含了特定值999,想要将其替换为0,则可以:

  • df['var'].replace(999, 0)
  • 当有多个值需要替换如999和888,则可df['var'].replace([999, 888], 0)
  • 当不同的值替换为不同的结果,则可df['var'].replace([999, 888], [0, 1]),当然这种情况也可以采用字典形式{'999':0, '888':1}
In [1]:
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())
model  cyl   disp   hp  drat     wt   qsec  vs  am  gear  carb
0          Mazda RX4    6  160.0  110  3.90  2.620  16.46   0   1     4     4
1      Mazda RX4 Wag    6  160.0  110  3.90  2.875  17.02   0   1     4     4
2         Datsun 710    4  108.0   93  3.85  2.320  18.61   1   1     4     1
3     Hornet 4 Drive    6  258.0  110  3.08  3.215  19.44   1   0     3     1
4  Hornet Sportabout    8  360.0  175  3.15  3.440  17.02   0   0     3     2
                  model   mpg  cyl   disp   hp  drat     wt   qsec  vs  am  \
14   Cadillac Fleetwood  10.4    8  472.0  205  2.93  5.250  17.98   0   0   
15  Lincoln Continental  10.4    8  460.0  215  3.00  5.424  17.82   0   0   
23           Camaro Z28  13.3    8  350.0  245  3.73  3.840  15.41   0   0   
6            Duster 360  14.3    8  360.0  245  3.21  3.570  15.84   0   0   
16    Chrysler Imperial  14.7    8  440.0  230  3.23  5.345  17.42   0   0   

    gear  carb  
14     3     4  
15     3     4  
23     3     4  
6      3     4  
16     3     4  
               model  mpower  cyl   disp   hp  drat     wt   qsec  vs  am  \
0          Mazda RX4    21.0    6  160.0  110  3.90  2.620  16.46   0   1   
1      Mazda RX4 Wag    21.0    6  160.0  110  3.90  2.875  17.02   0   1   
2         Datsun 710    22.8    4  108.0   93  3.85  2.320  18.61   1   1   
3     Hornet 4 Drive    21.4    6  258.0  110  3.08  3.215  19.44   1   0   
4  Hornet Sportabout    18.7    8  360.0  175  3.15  3.440  17.02   0   0   

   gear  carb  
0     4     4  
1     4     4  
2     4     1  
3     3     1  
4     3     2  

3.2 变量与观测的筛选

两个函数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")
    @用来指定外部对象

3.3 缺失、重复值处理

  • 缺失值判断:isnull,notnull
  • 缺失值删除:dropna,该函数有axis和how两个参数,分别指定轴和删除方式
  • 缺失值填充:fillna,有两种方法ffill和bfill
  • 重复值判断:
    . duplicated返回一个布尔series
    . drop_duplicates删除重复值返回一个dataframe,如df.drop_duplicates(),或指定列df.drop_duplicates(['var'])

    df.drop_duplicates(subset=['sex'], keep='first', inplace=True)
    包含参数:
    subset,为选定的列做distinct,默认为所有列;
    keep,值选项{'first', 'last', False},保留重复元素中的第一个、最后一个,或全部删除;
    inplace ,默认为False,返回一个新的dataframe;若为True,则返回去重后的原dataframe

In [10]:
mt_4 = mtcars.filter(items=['mpg', 'model'])
mt_4.head()
Out[10]:
mpg model
0 21.0 Mazda RX4
1 21.0 Mazda RX4 Wag
2 22.8 Datsun 710
3 21.4 Hornet 4 Drive
4 18.7 Hornet Sportabout

4 数据库之结构变换

4.1 拼接与轴向连接

  • 拼接:即列与列合并,也称为横向合并,使用merge函数,使用方式与sql数据库中一致。
    merge常用的参数:
    . on:指定连接的健,当健名不同时,使用left_on, right_on
    . how:用来指定连接方式:inner、left、right、outer
    . suffiex:用来指定同名列的后缀
    其他参数详见帮助文档

  • 轴向连接:即按照不同的轴(行或列)实现数据框之间的连接,同样可以实现merge的功能,常用函数为concat。
    concat常用参数:
    . obj:必须为列表或者字典
    . axis:轴,0和1
    . join:只有outer和inner两个值,指名轴方向上,索引的连接方式

In [13]:
#----横向拼接----#
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)

4.2 数据库结构重塑

通常称为数据库长宽转换,在pandas中共有两组可以实现这一功能。

  • stack和unstack . 适用于层次化索引结构(即有多个index),stack将列旋转为行(堆积),unstack将行旋转为列(平铺)
  • pivot和melt 将数据框进行长宽转换
    。 pivot将行(记录)转换为列(变量),即将长数据转换为宽数据,基本参数有:index、columns、values
    。 melt将列(变量)转换为行(记录),即将宽数据转换为长数据,基本参数有:id_vars、value_vars、value_name、var_name
In [6]:
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)
Out[6]:
model variable mpg_cyl
0 Mazda RX4 mpg 21.0
1 Mazda RX4 Wag mpg 21.0
2 Datsun 710 mpg 22.8
3 Hornet 4 Drive mpg 21.4
4 Hornet Sportabout mpg 18.7
5 Valiant mpg 18.1
6 Duster 360 mpg 14.3
7 Merc 240D mpg 24.4
8 Merc 230 mpg 22.8
9 Merc 280 mpg 19.2
10 Mazda RX4 cyl 6.0
11 Mazda RX4 Wag cyl 6.0
12 Datsun 710 cyl 4.0
13 Hornet 4 Drive cyl 6.0
14 Hornet Sportabout cyl 8.0
15 Valiant cyl 6.0
16 Duster 360 cyl 8.0
17 Merc 240D cyl 4.0
18 Merc 230 cyl 4.0
19 Merc 280 cyl 6.0

5 字符串操作及正则表达式

5.1 pandas中的常用字符操作函数:

通常将series转换为string(.str即可))格式,再进行字符串操作,此操作即为矢量化

  • strip:去除空白符及换行符
  • split:按指定字符拆分,split(',')
  • lower和upper:大小写转换
  • find:查找指定字符,返回第一次出现该字符的位置,若无则返回-1
  • replace:用一个字符替换指定字符
  • join:将指定字符作为连接其他字符串序列的分隔符
  • count:对指定字符进行计数
  • endswith和startswith:判断是否以某指定字符开始和结尾
  • len:计数字符串长度
  • cat(sep=''):使用指定字符进行字符串连接,等同于r语言对paste
  • contains(pattern):判断是否包含特定字符串
  • repeat(value):重复每个原始指定次数
  • islower和isupper:判断是否大小写
  • slice(start, end):使用给定的字符串,提取指定的位置的字符
  • slice_replace:使用给定的字符串,替换指定的位置的字符
  • match(pattern):判断匹配的正则表达式
  • extract(pattern):提取匹配的正则表达式

5.2 正则表达式

见单独学习笔记,python中使用re库进行正则表达式操作

In [5]:
ser = pd.Series(['a123 ', 'b2 34', 'c567'])

print(ser.str.strip())
print(ser.str.cat(sep=':'))
print(ser.str.slice(0, 1))
0     a123
1    b2 34
2     c567
dtype: object
a123 :b2 34:c567
0    a
1    b
2    c
dtype: object

6 日期与时间操作

Python时间和日期操作需要用到datetime、time、calendar标准库模块。本文主要介绍datetime包,它比time包更高级。

6.1 datetime包简介

datetime模块的数据类型:

  • date:日期
  • time:时间
  • datetime:日期和时间
  • timedelta:两个datetime之间的差值

6.2 获得时间戳

datatime模块的now()函数,返回一个datetime对象,则具有以下属性:

  • year: datetime.year
  • month:
  • day
  • hour
  • minute
  • second
  • microsecond: 毫秒
  • tzinfo:时区信息

6.3 字符串与datetime对象之间互转

  • datetime对象转换为字符串,使用str()函数或者strftime方法:
  • 字符串转换为datetime格式,使用datetime模块中的strptime()函数,另外pandas库中的to_datetime()函数也可以实现此功能

6.4 时间的格式

  • %y 两位数的年份表示(00-99)
  • %Y 四位数的年份表示(000-9999)
  • %m 月份(01-12)
  • %d 月内中的一天(0-31)
  • %H 24小时制小时数(0-23)
  • %I 12小时制小时数(01-12)
  • %M 分钟数(00=59)
  • %S 秒(00-59)
  • $W 每年的第九周
  • %w 用整数表示星期几
  • %F '%Y-%m-%d'的简写形式
  • %D '%m/%d/%y'的简写形式
In [33]:
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)
当前时间戳: 2020-01-08 17:25:34.856643
年份: 2020
datetime转成字符串: 2020-01-08 17:25:34.856643
日期时间格式: 2020-01-08
2010-01-01 00:00:00

III. Python Data Science之数据可视化方法

1. matplotlib库的介绍及使用

1.1 matplotlib简介

matlibplot库是由John Hunter在2002年开始开发的图形包,旨在实现matlab式的图形接口,后由ipython的开发者之一的Fernando参与联合开发。
matlibplot是一个比较底层的图形库,功能很强大,但是对于常见的统计作图并不方便。

1.2 matplotlib画图流程

(1) matlibplot架构,从表层到底层可分为三层:

  • scripting脚本层:即pyplot所在层,常见的图形功能主要在这一层
  • artist表现层:即matplotlib的对象层,比如坐标系、坐标轴等,见后介绍
  • backend后端层:即底层matplotlib api处于这一层,常见的图形应用功能不涉及这一层的知识点

(2) matlibplot画图对象构成(自上而下):

  • figure:即最基础的对象,指代整个图对象,每张图只能有一个figure对象
  • axes:即坐标系,有坐标系才能构建坐标轴,subplot的本质就是同一个figure里有多个axes对象
    . text:即坐标系中的文本
    . grid:即网格
    . axis:即坐标轴,分为x和y
    .. xaxis和yaxis:即横坐标轴和纵坐标轴
    .. ticks:即刻度值,分横轴和纵轴
    .. ticks label:刻度值标签,同样分横轴和纵轴
    .. label:即坐标轴标题,同样分横轴和纵轴
  • title:即标题
  • legend:图例
  • xlim和ylim:指定横纵坐标的取值范围,参数值为列表

(3) matlibplot画图基本步骤

  • 导入pyplot模块:import matplotlib.pyplot as plt
  • 实例化figure对象:fig = plt.figure(),还有一个figsize的参数,此步骤不是必须的
  • 创建subplot:单纯的figure是无法画图的,必须在figure中新建至少一个subplot才能开始画图,ax = fig.add_subplot(1, 1, 1)
  • 如果多个子图:fig, (ax1, ax2) = plt.subolots(1, 2),1和2代表子图的行列数,即共有2个子图,子图也可以图通过ax = plt.subplots(2, 2)生成和ax[1, 1]来指定 subplot还有一些参数:ncols、nrows、sharex、sharey等。或者用add_subplot(2, 2, 1), 最后一个用来标示第几个子图
  • 对子图进行画图,通过指定ax1.plot()或ax[1, 1].plot()即可
  • 保存图片:使用plt.savefig()函数,包括dpi和bbox_inches='tight'(剪除图片中的空白部分),可以到处pdf、png、svg、eps等格式
  • 显示图片:plt.show()即可,注意:如果在savefig之前使用了show,则保存的图片将会是空白的!!!

1.3 基本画图函数plot

plot()函数为基本画图命令,有以下参数:

  • x:指定横轴
  • y:指定纵轴
  • linestyle:指定线型,如'--'、'dashed'等
  • color:指定颜色,如'black',或rgb代码
  • marker:指定点标记的形状,如'o'

具体示例如下:

In [2]:
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.4 复杂关系图形

  • (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进行作图,见下节

In [36]:
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()

2. pandas中的绘图函数

pandas的数据结构对象也有一个plot的属性,可以用来画一些简单的统计图形。

2.1 plot

plot函数的参数:

  • label:图例的标签
  • ax:指定要在那个坐标轴上画图,即用来指定subplot的位置
  • style:设定matplotlib的风格,如‘ko--’
  • alpha:填充的透明度
  • color:颜色
  • kind:设定图形类型,有5个值:line、bar、barh、kde、pie
  • logy:y轴使用对数转换
  • use_index:将索引作为刻度标签
  • rot:旋转刻度标签
  • xticks:x轴刻度值
  • yticks:y轴刻度值
  • xlim:x轴界限,传入列表对象
  • ylim:y轴界限
  • grid:布尔值,是否加网格,默认为True
  • stacked:布尔值,kind为bar时,设定是否为堆积条图

只适用于dataframe,不适用与series的plot参数:

  • subplots:布尔值,将dataframe的各列绘制到不同的子图中
  • sharex:布尔值,子图是否共用x轴
  • sharey:布尔值,子图是否共用y轴
  • figsize:图像大小
  • title:标题
  • legend:布尔值,图例,默认为True
  • sort_columns: 对各列按字母排序作图

2.2 hist和scatter_matrix

除plot属性外,还有hist和scatter_matrix()函数

具体而言,对dataframe对象画图时,需要先对数据进行处理成适合画图的结构,再画图

In [61]:
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])
Out[61]:
<matplotlib.axes._subplots.AxesSubplot at 0x1249eb0d0>

3. seaborn库的介绍及使用

3.1 seaborn库简介

官方介绍:Seaborn is a library for making statistical graphics in Python. It is built on top of matplotlib and closely integrated with pandas data structures.

3.2 seaborn画图函数类型

根据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

3.3 seaborn画图函数通用参数介绍

此部分主要介绍通用参数,特定函数的特定参数在有具体需求时详细查询官方文档

个人将通用参数分为两大类:映射参数,标尺参数:

(1) 映射参数:即将数据类型中的变量与图形中的元素对应起来,如颜色、大小、分组等

  • x:横轴
  • y:纵轴
  • hue:指定颜色,字符或数值变量均可,等同于ggplot2中的color
  • size:指定大小,字符或数值变量均可
  • style:指定样式,字符或数值变量均可,等同于ggplot2中的shape
  • data:指定数据框
  • row:指定按行分面的变量,等同于ggplot2中的facet_grid
  • col:指定按列分面的变量
  • col_wrap:指定列折叠的宽度,整数
  • kind:指定画图类型,字符
  • legend:指定图例的类型,可取值“brief”, “full”, or False
    关于legend的详细设定可参考 [https://jakevdp.github.io/PythonDataScienceHandbook/04.06-customizing-legends.html]

(2) 标尺参数:即用来定义颜色、大小的取值范围,及取什么颜色、多大多小等

  • palette : palette name, list, or dict, optional
  • hue_order : list, optional Specified order for the appearance of the hue variable levels, otherwise they are determined from the data. Not relevant when the hue variable is numeric.
  • sizes : 定义大小的范围,list, dict, or tuple, optional
  • facet_kws:定义分面的关键参数,只能传入字典,如facet_kws=dict(sharex=False)
  • height : scalar, optional Height (in inches) of each facet. See also: aspect.
  • aspect : scalar, optional Aspect ratio of each facet, so that aspect * height gives the width of each facet in inches.
  • ax:用来指定seaborn的图对象放在matplotlib类中的那个坐标系中,同pandas中画图的操作

3.4 seaborn设置标题和标签

seaborn并未设置title和label等参数,由于seaborn是基于matplotlib的封装,因此可以将seaborn图形赋值为一个对象,调用matplotlib的函数即可:

3.5 seaborn全局配置函数

对色版、图表主题、字体、字号等可以进行全局设置,主要函数为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的坐标线

In [34]:
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')
In [22]:
sns.distplot(mtcars['disp'])
Out[22]:
<matplotlib.axes._subplots.AxesSubplot at 0x1a368fbfd0>

IV. Python Data Science之统计分析

1. 基础运算函数介绍

1.1 算术运算符

+ 加 - 两个对象相加
- 减 - 得到负数或是一个数减去另一个数
* 乘 - 两个数相乘或是返回一个被重复若干次的字符串
/ 除 - x除以y
% 取模 - 返回除法的余数
幂 - 返回x的y次幂 ab 为10的20次方
// 取整除 - 返回商的整数部分(向下取整)

1.2 比较运算符

== 等于 - 比较对象是否相等 (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。

1.3 逻辑运算符

  • 且:and
  • 或:or
  • 非:not

1.4 成员运算符

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

1.4 身份运算符

is 是判断两个标识符是不是引用自一个对象 x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False。
is not 是判断两个标识符是不是引用自不同对象 x is not y , 类似 id(a) != id(b)。如果引用的不是同一个对象则返回结果 True,否则返回 False。

1.5 运算函数

主要的运算函数在numpy库中,但pandas中也提供了部分。区别在于numpy中的运算函数本身不支持矢量运算,而pandas中的运算函数结合groupby时支持矢量运算

(1) 聚合运算函数:指将一组数组或者series计算为标量的运算 ,以下列出的为pandas中对groupby优化了的运算函数

  • count
  • sum
  • mean
  • std
  • var
  • min
  • max
  • first
  • last
  • prod:矩阵级

(2) 分组运算函数:指不是返回一个标量的函数

  • 自定义的函数
  • 除聚合运算之外的其他运算函数,如quantile

2. 描述性统计分析

2.1 单组描述

单组统计较为简单,直接应用相应的运算函数即可

  • 数值型:mean等数值型运算函数

  • 分类型:count等分类计数函数

2.2 分组描述

分组描述的基本原理: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,或者所有对象的格式变换等操作

In [47]:
#-- 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) ) # 这种方式更为方便
a    4
b    5
c    6
Name: m, dtype: int64
a     8
b    10
c    12
Name: m, dtype: int64
a     8
b    10
c    12
Name: m, dtype: int64

(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的可以完成相同的交叉透视表

具体示例如下:

In [36]:
#--groupby--单变量单函数--#
mtcars.groupby('cyl')['mpg'].mean()
Out[36]:
cyl
4    26.663636
6    19.742857
8    15.100000
Name: mpg, dtype: float64
In [39]:
#--groupby--单变量多函数--#
mtcars.groupby('cyl')['mpg'].agg(['mean', 'std'])
Out[39]:
mean std
cyl
4 26.663636 4.509828
6 19.742857 1.453567
8 15.100000 2.560048
In [46]:
#--groupby--单变量多函数(改名)--#
mtcars.groupby('cyl')['mpg'].agg([('Mean', 'mean'), ('STD', 'std')]).add_prefix('mpg_')
Out[46]:
mpg_Mean mpg_STD
cyl
4 26.663636 4.509828
6 19.742857 1.453567
8 15.100000 2.560048
In [52]:
#--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()
Out[52]:
N Mean Median Min Max
cyl
4 11.0 26.663636 26.0 21.4 33.9
6 7.0 19.742857 19.7 17.8 21.4
8 14.0 15.100000 15.2 10.4 19.2
In [50]:
#--groupby--多变量多函数--#
mtcars.groupby('cyl')[['mpg', 'hp']].agg({'mpg':'mean', 'hp':'std'})
Out[50]:
mpg hp
cyl
4 26.663636 20.934530
6 19.742857 24.260491
8 15.100000 50.976886

Pivot table演示
仅演示最复杂的情况

In [3]:
#--pivot_table--#
# 多value变量,多func
mtcars.pivot_table(values=['hp', 'mpg'], index=['cyl', 'gear'], columns='vs', margins=True, aggfunc={'hp': 'mean', 'mpg': 'min'}).round(2)
Out[3]:
hp mpg
vs 0 1 All 0 1 All
cyl gear
4 3 NaN 97.000000 97.000000 NaN 21.5 21.5
4 NaN 76.000000 76.000000 NaN 21.4 21.4
5 91.000000 113.000000 102.000000 26.0 30.4 26.0
6 3 NaN 107.500000 107.500000 NaN 18.1 18.1
4 110.000000 123.000000 116.500000 21.0 17.8 17.8
5 175.000000 NaN 175.000000 19.7 NaN 19.7
8 3 194.166667 NaN 194.166667 10.4 NaN 10.4
5 299.500000 NaN 299.500000 15.0 NaN 15.0
All 189.722222 91.357143 146.687500 10.4 17.8 10.4

Crosstab演示
仅演示最复杂情况

In [7]:
#--crosstab--#
pd.crosstab(index=mtcars['gear'], columns=mtcars['vs'], normalize=True, margins=True).style.format('{:.2%}')
Out[7]:
vs 0 1 All
gear
3 37.50% 9.38% 46.88%
4 6.25% 31.25% 37.50%
5 12.50% 3.12% 15.62%
All 56.25% 43.75% 100.00%
In [8]:
#--crosstab--#
pd.crosstab(index=mtcars['gear'], columns=mtcars['vs'], normalize='columns', margins=True).style.format('{:.2%}')
Out[8]:
vs 0 1 All
gear
3 66.67% 21.43% 46.88%
4 11.11% 71.43% 37.50%
5 22.22% 7.14% 15.62%

(3) 第三方库的使用

一个比较好用的第三方库researchpy,现在最新版是0.1.8

主要函数有:

  • summary_cont:对连续性数值变量进行统计描述,结合groupby和apply可以实现分组统计
  • summary_cat:对分类变量进行统计描述,结合groupby和apply可以实现分组统计
  • crosstab:分类变量交叉表
  • ttest:两组独立和配对t检验
In [ ]:
import researchpy as rp
rp.summary_cat(df["var"])

(4) 批量导入同一个文件夹下的同一类文件

In [ ]:
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)

3. 推断统计分析

3.1 t检验

3.2 方差检验

3.3 卡方检验

In [ ]:
 

4. 回归模型分析

4.1 主要依赖模块statsmodels简介

官方介绍: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是一个相对比较容易理解和更为方便的形式,也降低了两个统计语言之间相互转换的学习成本

官方示例如下:

In [54]:
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()
OLS Regression Results                            
==============================================================================
Dep. Variable:                Lottery   R-squared:                       0.338
Model:                            OLS   Adj. R-squared:                  0.287
Method:                 Least Squares   F-statistic:                     6.636
Date:                Sat, 22 Feb 2020   Prob (F-statistic):           1.07e-05
Time:                        21:02:28   Log-Likelihood:                -375.30
No. Observations:                  85   AIC:                             764.6
Df Residuals:                      78   BIC:                             781.7
Df Model:                           6                                         
Covariance Type:            nonrobust                                         
===============================================================================
                  coef    std err          t      P>|t|      [0.025      0.975]
-------------------------------------------------------------------------------
Intercept      38.6517      9.456      4.087      0.000      19.826      57.478
Region[T.E]   -15.4278      9.727     -1.586      0.117     -34.793       3.938
Region[T.N]   -10.0170      9.260     -1.082      0.283     -28.453       8.419
Region[T.S]    -4.5483      7.279     -0.625      0.534     -19.039       9.943
Region[T.W]   -10.0913      7.196     -1.402      0.165     -24.418       4.235
Literacy       -0.1858      0.210     -0.886      0.378      -0.603       0.232
Wealth          0.4515      0.103      4.390      0.000       0.247       0.656
==============================================================================
Omnibus:                        3.049   Durbin-Watson:                   1.785
Prob(Omnibus):                  0.218   Jarque-Bera (JB):                2.694
Skew:                          -0.340   Prob(JB):                        0.260
Kurtosis:                       2.454   Cond. No.                         371.
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
In [55]:
# 输出为html形式
import IPython.core.display as di
di.HTML(res.summary().as_html())
Out[55]:
OLS Regression Results
Dep. Variable: Lottery R-squared: 0.338
Model: OLS Adj. R-squared: 0.287
Method: Least Squares F-statistic: 6.636
Date: Sat, 22 Feb 2020 Prob (F-statistic): 1.07e-05
Time: 21:02:31 Log-Likelihood: -375.30
No. Observations: 85 AIC: 764.6
Df Residuals: 78 BIC: 781.7
Df Model: 6
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Intercept 38.6517 9.456 4.087 0.000 19.826 57.478
Region[T.E] -15.4278 9.727 -1.586 0.117 -34.793 3.938
Region[T.N] -10.0170 9.260 -1.082 0.283 -28.453 8.419
Region[T.S] -4.5483 7.279 -0.625 0.534 -19.039 9.943
Region[T.W] -10.0913 7.196 -1.402 0.165 -24.418 4.235
Literacy -0.1858 0.210 -0.886 0.378 -0.603 0.232
Wealth 0.4515 0.103 4.390 0.000 0.247 0.656
Omnibus: 3.049 Durbin-Watson: 1.785
Prob(Omnibus): 0.218 Jarque-Bera (JB): 2.694
Skew: -0.340 Prob(JB): 0.260
Kurtosis: 2.454 Cond. No. 371.


Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
In [45]:
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)
Out[45]:
Result of Regression
Dependent variable:
(1)(2)
Intercept38.652***65.022***
(9.456)(8.104)
Literacy-0.186-0.398*
(0.21)(0.227)
Region[T.E]-15.428-6.505
(9.727)(10.555)
Region[T.N]-10.017-14.501
(9.26)(10.213)
Region[T.S]-4.548-3.329
(7.279)(8.071)
Region[T.W]-10.091-7.686
(7.196)(7.962)
Wealth0.451***
(0.103)
Observations85.085.0
R20.3380.174
Adjusted R20.2870.122
Residual Std. Error20.891(df = 78.0)23.181(df = 79.0)
F Statistic6.636***(df = 6.0; 78.0)3.337***(df = 5.0; 79.0)
Note: *p<0.1; **p<0.05; ***p<0.01

4.2 一般线性模型

import statsmodels.formula.api as smf

smf.ols()

4.3 广义线性模型

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转换,不需要手动指定

4.4 多水平或混合效应模型

Linear Mixed Effects Models

4.5 面板数据的固定和随机效应模型

使用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)

4.6 自定义函数画coef plot

reference(https://zhiyzuo.github.io/Python-Plot-Regression-Coefficient/)

In [1]:
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()
Out[1]:
OLS Regression Results
Dep. Variable: fertility R-squared: 0.707
Model: OLS Adj. R-squared: 0.671
Method: Least Squares F-statistic: 19.76
Date: Sat, 22 Feb 2020 Prob (F-statistic): 5.59e-10
Time: 20:36:57 Log-Likelihood: -156.04
No. Observations: 47 AIC: 324.1
Df Residuals: 41 BIC: 335.2
Df Model: 5
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Intercept 66.9152 10.706 6.250 0.000 45.294 88.536
agri -0.1721 0.070 -2.448 0.019 -0.314 -0.030
exam -0.2580 0.254 -1.016 0.315 -0.771 0.255
edu -0.8709 0.183 -4.758 0.000 -1.241 -0.501
catholic 0.1041 0.035 2.953 0.005 0.033 0.175
infant_mort 1.0770 0.382 2.822 0.007 0.306 1.848
Omnibus: 0.058 Durbin-Watson: 1.454
Prob(Omnibus): 0.971 Jarque-Bera (JB): 0.155
Skew: -0.077 Prob(JB): 0.925
Kurtosis: 2.764 Cond. No. 807.


Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

V. Python Data Science之机器学习

1. 机器学习库介绍

2. 机器学习方法介绍

实例

实例一

In [50]:
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)
In [53]:
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)
In [62]:
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)

实例二

In [2]:
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")
Out[2]:
[Text(0, 0, '2/21'),
 Text(0, 0, '2/25'),
 Text(0, 0, '2/29'),
 Text(0, 0, '3/01'),
 Text(0, 0, '3/05'),
 Text(0, 0, '3/09'),
 Text(0, 0, '3/13'),
 Text(0, 0, '3/17'),
 Text(0, 0, '3/21')]

实例三

In [1]:
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)
No handles with labels found to put in legend.

实例四

In [4]:
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])

实例五

In [4]:
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")

实例六

In [112]:
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()
0.334342833986222
In [119]:
''' 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)
Out[119]:
5.196975945017182
In [129]:
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()
In [90]:
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()
Out[90]:
0      0.004976
1      0.012165
2      0.017971
3      0.024606
4      0.030412
         ...   
145    0.973735
146    0.980370
147    0.986729
148    0.992259
149    1.000000
Length: 150, dtype: float64
In [83]:
income.size
Out[83]:
150
In [71]:
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)
Out[71]:
'当移动距离为 2 厘米,下底横线长度为 10 厘米时,阴影部分面积为: 7.91586742848067 平方厘米'
In [72]:
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")

实例七

In [52]:
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")
Out[52]:
<matplotlib.legend.Legend at 0x7fe11a78ead0>
In [ ]: