在家为国家做贡献太无聊, 不如跟我一起学点 Python
顺便问一下, 你们都喜欢什么什么样的文章封面图, 老用这一张感觉有点丑
人生苦短, 我用 Python
前文传送门:
小白学 Python 数据分析(1): 数据分析基础 https://www.geekdigging.com/2020/01/19/6719980708/
小白学 Python 数据分析 (2):Pandas (一) 概述 https://www.geekdigging.com/2020/01/20/6718497214/
先介绍下 Pandas 的数据结构, 毕竟数据结构是万物的基础.
Pandas 有两种主要的数据结构: Series 和 DataFrame , 本文就先介绍第一种 Series .
模块导入
首先我们在代码中引入 Pandas 和 Numpy , 如下:
- import numpy as np
- import pandas as pd
- Series
Series 可以简单的理解为一维数组, 可以存储整数, 浮点数, 字符串, Python 对象等类型的数据.
这个概念有点像 Java 中的集合.
如果无法理解的话, 那么可以看下面这个图(Excel 简单画画, 灵魂画手登场):
这里的 data 可以是上面提到的那些数据类型, 并不仅限于图中的整数.
如果 index 的值未指定, 那么将会自动的创建数值类型的索引, 从 0 开始, 例如: 0 , 1 , 2, 3 ... len(data) - 1 .
创建一个 Series , 这里我们可以使用 pd.Series 函数来创建, 如下:
- s = pd.Series(np.random.rand(5), index=['a', 'b', 'c', 'd', 'e'])
- print(s)
- print(s.index)
- s1 = pd.Series(np.random.randn(5))
- print(s1)
结果如下:
- a 0.218164
- b 0.153201
- c 0.572437
- d 0.142784
- e 0.710664
- dtype: float64
- Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
- 0 0.255452
- 1 1.354357
- 2 2.092490
- 3 0.353899
- 4 1.692989
- dtype: float64
从上面我们可以看到, 如果我们手动指定了索引, 那么将会按照我们指定的索引进行创建, 如果没有指定会直接使用数值索引.
注意: 如果我们手动指定索引, 索引的长度必须与数据的长度一致. 如果不一致, 将会抛出 ValueError 的异常, 如下:
s = pd.Series(np.random.rand(6), index=['a', 'b', 'c', 'd', 'e'])
异常部分内容:
ValueError: Length of passed values is 6, index implies 5
字典实例化
Series 是可以使用字典进行实例化的, 示例如下:
- d = {
- 'b': 1, 'a': 0, 'c': 2
- }
- s2 = pd.Series(d)
- print(s2)
结果如下:
- b 1
- a 0
- c 2
- dtype: int64
注意: 当我们使用的 data 为字典的时候, 且未设置 index 参数时, 如果 Python 版本>= 3.6 且 Pandas 版本>= 0.23, Series 按字典的插入顺序排序索引. Python <3.6 或 Pandas < 0.23, 且未设置 index 参数时, Series 按字母顺序排序字典的键 (key) 列表.
在上面的这个示例中, 如果当前的环境 Python < 3.6 或 Pandas < 0.23, Series 将会按照字母的顺序进行排序, 而不是当前字典的顺序, 输出的结果将会是 ['a', 'b', 'c'] .
同时, 如果我们在使用字典做 data 的时候, 同样可以设置索引, 这样将会按照索引来提取 data 中对应的值, 如果索引在 data 中无对应, 将会使用 NaN 来表示缺失的数据, 示例如下:
- s3 = pd.Series(d, index=['b', 'c', 'd', 'a'])
- print(s3)
结果如下:
- b 1.0
- c 2.0
- d NaN
- a 0.0
- dtype: float64
标量值实例化
data 还支持标量值进行实例化, 当 data 是标量值的时候, 实例化 Series 的时候必须提供索引, Series 将会按照索引的长度重复这个标量值, 如下:
- s4 = pd.Series(5., index=['a', 'b', 'c', 'd', 'e'])
- print(s4)
结果如下:
- a 5.0
- b 5.0
- c 5.0
- d 5.0
- e 5.0
- dtype: float64
基于索引的操作方式
- print(s[0])
- print(s[:3])
- print(s[s> s.median()])
- print(s[[4, 3, 1]])
结果如下:
- 0.481205137399224
- a 0.481205
- b 0.045604
- c 0.108321
- dtype: float64
- d 0.495208
- e 0.817171
- dtype: float64
- e 0.817171
- d 0.495208
- b 0.045604
- dtype: float64
同时, Series 还支持通过索引标签进行设置值或者是取值, 如下:
- print(s['a'])
- s['e'] = 12.
- print(s)
结果如下:
- 0.481205137399224
- a 0.481205
- b 0.045604
- c 0.108321
- d 0.495208
- e 12.000000
- dtype: float64
如果直接使用 Series 中没有的索引标签, 会抛出 KeyError 异常:
- # 抛出 KeyError 异常
- # print(s['f'])
我们可以通过 in 来判断当前的 Series 中有没有含有索引标签, 如下:
- print('e' in s)
- print('f' in s)
结果如下:
True False
可以通过 get 这个方法获取 Series 没有的索引标签, 同时可以设置返回的默认值:
- print(s.get('f'))
- print(s.get('f', np.nan))
结果如下:
None nan
常用方法
- # 打印 e 的幂次方, e 是一个常数为 2.71828
- print (np.exp(s))
- # 打印 s 里每个元素的开方
- print (np.sqrt(s))
- print(s.dtype)
- print(s.array)
- print(s.to_numpy())
结果如下:
- a 1.618023
- b 1.046659
- c 1.114406
- d 1.640840
- e 2.264085
- dtype: float64
- a 0.693690
- b 0.213550
- c 0.329122
- d 0.703711
- e 0.903975
- dtype: float64
- float64
- <PandasArray>
- [ 0.481205137399224, 0.04560362121419126, 0.10832121726528887,
- 0.49520848929233285, 0.8171705710254773]
- Length: 5, dtype: float64
- [0.48120514 0.04560362 0.10832122 0.49520849 0.81717057]
从上面的示例中可以看到, 当使用 Series 做一些算数运算的时候, 是不需要循环 Series 中每个值的.
注意: Series 之间的操作会自动基于标签对齐数据.
print(s[1:] + s[:-1])
结果如下:
- a NaN
- b 0.091207
- c 0.216642
- d 0.990417
- e NaN
- dtype: float64
操作未对齐索引的 Series, 其计算结果是所有涉及索引的并集. 如果在 Series 里找不到标签, 运算结果标记为 NaN, 即缺失值.
名称属性
Series 支持 name 属性, 我们可以给我们自己定义的 Series 起一个自己喜欢的名字:
- s5 = pd.Series(np.random.randn(5), name='my_series')
- print(s5)
- print(s5.name)
- print(id(s5))
结果如下:
- 0 0.491450
- 1 0.939965
- 2 0.868437
- 3 -0.099575
- 4 1.866875
- Name: my_series, dtype: float64
- my_series
- 1492397351368
这里小编顺手使用 id 方法打印一下 s5 的内存地址.
同样, Series 为我们提供了重命名的方法 rename() :
- # 重命名 series
- s6 = s5.rename("my_series_different")
- print(id(s6))
结果如下:
- 1492397351368
- 0 0.491450
- 1 0.939965
- 2 0.868437
- 3 -0.099575
- 4 1.866875
- Name: my_series_different, dtype: float64
- 1492400065800
对比上下两个 s5 和 s6 可以看到, 这两个 Series 具有相同的 data 内容, name 属性并不相同.
但是, 有一点要注意的是: s5 和 s6 是两个不同的对象, 这里打印的内存地址不同也说明了这一点, 这里实际上并不是将 s5 的 name 修改了一下, 而是新建了一个新的对象并使用了新的 name 属性.
示例代码
老规矩, 所有的示例代码都会上传至代码管理仓库 GitHub 和 Gitee 上, 方便大家取用.
示例代码 - GitHub
示例代码 - Gitee
参考
来源: https://www.cnblogs.com/babycomeon/p/12316511.html