阅读 74

Pandas从入门到精通(1)- 基础

我们都知道Python之所有能在数据科学领域占有一席之地,主要是数据分析三剑客:numpy、pandas、matplotlib这三个库的功劳。而在这三个库中,我觉得最核心,用的最多的还是pandas。不管是在平时处理数据还是打比赛中,都要求能够对pandas进行熟练的应用。基于此,笔者参加了Datawhale开源社区组织的Pandas学习,目标就是爆肝一个月,精通Pandas!

从本期开始,我们就开始来系统学习并梳理一下Pandas的知识。我们将按照下面的大纲分10期进行。我相信通过通过10期丰富的案例学习,掌握并熟练运用Pandas,水到渠成。

  • Pandas基础
  • 索引
  • 分组
  • 变形
  • 连接
  • 缺失数据
  • 文本数据
  • 分类数据
  • 时序数据
  • 综合练习

本期作为第一期,主要是熟悉一些基础知识,为后期的学习做准备。主要包括Python中的一些常用函数和numpy库的一些操作。

1.1 列表推导式

列表推导式是Python语言的一大特色,可以快速简洁的创建列表。

1.1.1 基本格式:

[* for i in k]: * 可以是一个函数,变量为i(也可以与i无关),k为一个可迭代对象,如列表。
应用: 1. 一句代码输出一个1到5的立方

  1. 一句代码创建一个列表,包含10个60-100的随机整数
# 一句代码输出一个1到5的立方
[i**3 for i in range(1,6)]
>>>[1, 8, 27, 64, 125]
# 一句代码创建一个列表,包含10个60-100的随机整数(模拟学生成绩)
import random
[random.randint(60,100) for _ in range(10)]
>>> [76, 89, 62, 83, 61, 80, 89, 99, 76, 78]

1.1.2 for循环嵌套

列表推导式中的for循环支持嵌套功能。
举例: 现有3个列表分别保存了顾客的姓名,衣服的颜色,尺码,用一句代码输出所有顾客和衣服颜色尺码的组合

names = ['zhangsan', 'lisi', 'wangba']
color = ['red', 'yellow']
size = ['S', 'M', 'L']
[name + '-' + c + '-' + s for name in names for c in color for s in size]
>>>
['zhangsan-red-S',
 'zhangsan-red-M',
 'zhangsan-red-L',
 'zhangsan-yellow-S',
 'zhangsan-yellow-M',
 'zhangsan-yellow-L',
 'lisi-red-S',
 'lisi-red-M',
 'lisi-red-L',
 'lisi-yellow-S',
 'lisi-yellow-M',
 'lisi-yellow-L',
 'wangba-red-S',
 'wangba-red-M',
 'wangba-red-L',
 'wangba-yellow-S',
 'wangba-yellow-M',
 'wangba-yellow-L']

上面的代码等价于:

for name in names:
    for c in color:
        for s in size:
            print(name + '-' + c + '-' + 's')
>>>
zhangsan-red-s
zhangsan-red-s
zhangsan-red-s
zhangsan-yellow-s
zhangsan-yellow-s
zhangsan-yellow-s
lisi-red-s
lisi-red-s
lisi-red-s
lisi-yellow-s
lisi-yellow-s
lisi-yellow-s
wangba-red-s
wangba-red-s
wangba-red-s
wangba-yellow-s
wangba-yellow-s
wangba-yellow-s

1.1.3 筛选功能

列表推导式中for循环后还可以加入if (或者if...else...)进行筛选 。
举例: 一句代码输出0-100内可以被7整除的整数

# 输出1-100内可以被7整除的数:
[i for i in range(1,101) if i%7 == 0]
>>>
[7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]

综合上面的案例,我们可以清晰的看到列表推导式的简洁与优雅!同时也体现Python的强大之处。

1.2 lambda匿名函数

我们都知道函数在python世界中属于一等公民,具有很高的权限。对于经常需要重复使用的代码块,一般都要优先考虑通过函数来实现。但是当我们想要使用一个简单定义的,或者只需要调用一两次的函数时,取名并编写一个完整的函数块就显得多余。这时候lambda匿名函数就有了用武之地。
格式: lambda [arg1 [,arg2, ... argN]] : expression
这里的lamdbda是系统保留的关键字, [arg1 [,arg2, ... argN]]是参数列表,它的结构与Python中函数(function)的参数列表是一样的。expression是一个关于参数的表达式。表达式中出现的参数需要在argument_list中有定义,并且表达式只能是单行的。
举例:例如我们定义一个函数,将字符串中的所有字母大写输出

def str_capital(s):
    return str.upper(s)

str_capital('datawhale')
>>>
'DATAWHALE'

如果改用匿名函数的写法:

upper = lambda x: str.upper(x)
upper('datawhale')
>>>
'DATAWHALE'

对比一下可以看到匿名函数有如下优点:

  • 可以直接在使用的地方定义,如果需要修改,直接找到修改即可,方便以后代码的维护工作
  • 语法结构简单,不用使用def 函数名(参数名):这种方式定义,直接使用lambda 参数:返回值 定义即可
    但是需要注意的是lambda匿名函数让程序简洁,但是并不能让程序高效,这个也是很多程序员反对使用lambda的原因。

1.3 map()方法

在Python中,匿名函数lambda经常和map()、reduce()和filter()三个应用于序列的内置函数联合使用,用于对序列进行遍历、递归计算以及筛选。这其中,最常用的就是map方法。在Python中,map()函数的本质是一种映射,即对输入其中的可迭代对象(列表)中每个元素执行定义的映射。例如我们编写了一个将给定的字符串大写输出的函数,在使用该函数将若干字符串大写输出

def str_capital(s):
    return str.upper(s)
L1 = ['I', 'like', 'Datawhale']
L2 = []
for s in L1:
    L2.append(str_capital(s))
L2
>>> 
['I', 'LIKE', 'DATAWHALE']

如果我们用map()替代for循环:

L3 = map(str_capital, L1)
list(L3)
>>>
['I', 'LIKE', 'DATAWHALE']

可以看到更加简洁!需要注意的是map()方法返回的是一个map()对象,需要用list()方法输出其中的元素。上面我们说了map经常和lambda匿名函数结合使用,如下:

L4 = map(lambda x: str.upper(x), L1)
list(L4)
>>>
['I', 'LIKE', 'DATAWHALE']

优雅!

1.4 zip方法

我们都知道zip是一个文件解压程序,同样的,在python中zip()函数就有点类似于解压缩包的感觉:传入一个列表或者其他可迭代对象,依次从中选取一个组成新的元组输出。下面举例:

a = [3,4,5,6]
b = ['a', 'b', 'c']
s1 = {'zhangsan': 20, 'lisi': 25}
print(zip(a))
print('*' * 10)
print(list(zip(a)))
print(list(zip(b)))
print(list(zip(s1)))
>>>
<zip object at 0x000001A7D4FF7940>
**********
[(3,), (4,), (5,), (6,)]
[('a',), ('b',), ('c',)]
[('zhangsan',), ('lisi',)]

可以看到zip的输出也是一个zip对象,需要用list查看其中的元素。
当zip()函数有两个参数时 ,如zip(a,b),则分别从a和b依次各取出一个元素组成元组,再将依次组成的元组组合成一个新的迭代器。如:

print(list(zip(a,b)))
>>>
[(3, 'a'), (4, 'b'), (5, 'c')]

这样设计有个特殊的用途,用于矩阵(二维数组)的加减和点乘,举例如下:

import numpy as np
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
n = [[2, 2, 2], [3, 3, 3], [4, 4, 4]]
# 矩阵点乘
print('=*'*10 + "矩阵点乘" + '=*'*10)
print(np.array([x*y for a, b in zip(m, n) for x, y in zip(a, b)]).reshape(3,3))
# 矩阵相加,相减雷同
print('=*'*10 + "矩阵相加,相减" + '=*'*10)
print(np.array([x+y for a, b in zip(m, n) for x, y in zip(a, b)]).reshape(3,3))
>>>
=*=*=*=*=*=*=*=*=*=*矩阵点乘=*=*=*=*=*=*=*=*=*=*
[[ 2  4  6]
 [12 15 18]
 [28 32 36]]
=*=*=*=*=*=*=*=*=*=*矩阵相加,相减=*=*=*=*=*=*=*=*=*=*
[[ 3  4  5]
 [ 7  8  9]
 [11 12 13]]

知识链接:矩阵点乘
矩阵点乘: 对应元素相乘,要求两个矩阵的形状必须相同。这个要和矩阵叉乘区分开来。

2. Numpy复习回顾

pandas是基于numpy来实现高效计算的,因而在学习pandas之前有必要先把之前学习的numpy的知识温习一下,这里总结了一些numpy一些常用的知识点

2.1 np.array

np里面最基本的数据结构是array(数组),构造也非常简单,np.array即可。下面总结几种特殊的array

  1. 等差序列
  • np.linspace(起始,终止(包含),样本个数): 适用于提前知道需要创建多少个样本的情况
  • np.arange(起始,终止(不包含),步长): 适用于提前知道相邻间隔的情况
    注意 np.arange和python数组中的range不要混淆了。range只能生成整数数列,而np.arange可以生成小数数列
import numpy as np
a = np.linspace(1,100,10)
b = np.arange(1,10,1.5)
print(a)
print(b)
>>>
[  1.  12.  23.  34.  45.  56.  67.  78.  89. 100.]
[1.  2.5 4.  5.5 7.  8.5]
    1. 特殊矩阵,包括zeros/ones/eye/full等
      直接上代码参考:
print('3行4列全0矩阵')
print(np.zeros((3,4)))
print('*' * 10)
print('3行3列全1矩阵')
print(np.ones((3, 3)))
print('*' * 10)
print('3行3列的单位矩阵')
print(np.eye(3))
print('*' * 10)
print('指定维度的/数值填充矩阵')
print(np.full((2,3), 6))
>>>
3行4列全0矩阵
[[0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [0. 0. 0. 0.]]
**********
3行3列全1矩阵
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
**********
3行3列的单位矩阵
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
**********
指定维度的/数值填充矩阵
[[6 6 6]
 [6 6 6]]
    1. 随机矩阵
  • np.random.rand() : 取值0-1之间的随机分布,这里不要传元组,直接指定不同维度的个数即可
  • np.random.randn(): 0~1标准正态分布
  • np.random.randint(low,high,size) :指定生成随机整数的最小值最大值和维度大小
  • np.random.choice(): 可以从给定的列表中,以一定概率和方式抽取结果,当不指定概率时为均匀采样,默认抽取方式为有放回抽样
  • np.random.seed(0) : 设置种子,就相当是设定了随机值,之后每次随机都一样

2. 练习题:

  1. 使用列表推导式完成矩阵乘法:
    矩阵乘法定义:


    image.png

    一般的矩阵乘法根据公式,可以由三重循环写出:


    image.png

使用列表推导式来替代for循环完成

# 先定义零个矩阵
M1 = np.random.randint(1,10,10).reshape(2,5)
M2 = np.random.randint(1,10,10).reshape(5,2)
print(M1)
print('-' * 5)
print(M2)
M1@M2 # 矩阵乘法
>>>
[[6 1 2 8 5]
 [6 1 7 9 4]]
-----
[[6 2]
 [7 7]
 [1 4]
 [7 1]
 [8 3]]
array([[141,  50],
       [145,  68]])
# 使用列表推导式来完成
[[sum([M1[i][k] * M2[k][j] for k in range(M1.shape[1])]) for j in range(M2.shape[1])] for i in range(M1.shape[0])]
>>>
[[141, 50], [145, 68]]
  1. 更新矩阵
    设矩阵 Am×n ,现在对 A 中的每一个元素进行更新生成矩阵 B ,更新方法是


    image.png

例如下面的矩阵为 A ,则 =5×(1/4+1/5+1/6)=37/12 ,请利用 Numpy 高效实现。

image.png

解答:

A = np.arange(1,10).reshape(3,3)
B = A*(1/A).sum(1).reshape(-1,1)
image.png

使用内置的函数

B = A.sum(0) * A.sum(1).reshape(-1,1) / A.sum()
print(B)
res = ((A-B) ** 2 / B).sum()
print(res)

参考:开源内容Joyful Pandas, 作者 DataWhale耿远昊
另外,更多精彩内容也可以微信搜索,并关注公众号:‘Python数据科学家之路“ ,期待您的到来和我交流

作者:木头里有虫911

原文链接:https://www.jianshu.com/p/070dc0cac260

文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐