背景Numpy 提供的最重要的数据结构是 ndarray,它是 Python 中 list 的扩展。 Pandas 提供了两种非常重要的数据结构 Series和DataFrame。 Numpy 中的一维数组与 Series 相似,一维数组只是提供了从0开始与位置有关的索引,而Series除了位置索引之外还可以附加额外的索引。本文将从对象的创建、属性的访问、数据的获取以及常用方法等方面来总结这两种结构的异同。 1. 如何创建对象1.1 创建一维数组对象 - 通过数值范围来创建一维数组,比如
linspace() 函数,返回指定间隔内的等间隔数字。arange() 函数,返回给定间隔内的均匀间隔的值。
import numpy as np
a0 = np.array((10, 40, 5, 90, 35, 40)) print(a0) # [10 40 5 90 35 40]
a1 = np.array([10, 40, 5, 90, 35, 40]) print(a1) # [10 40 5 90 35 40]
a2 = np.linspace(start=0, stop=5, num=5) print(a2) # [0. 1.25 2.5 3.75 5. ]
a3 = np.arange(10, 15) print(a3) # [10 11 12 13 14]
1.2 创建Series对象 Series 可以看作是能够附加索引的一维数组,所以可以像 Numpy 创建一维数组一样使用 list或tuple 来创建,甚至可以使用 Numpy的一维数组 直接创建。 - 通过列表
list 、元组tuple 创建Series 。
另外,Series 可以附加索引,所以可以在创建的时候直接指定需要附加的索引,以及利用字典的key-value 键值对 来直接创建。 - 通过指定
index 关键字的方式创建带有自定义索引的Series 。
import pandas as pd import numpy as np
s0 = pd.Series((10, 40, 5, 90, 35, 40)) print(s0) # 0 10 # 1 40 # 2 5 # 3 90 # 4 35 # 5 40 # dtype: int64
s1 = pd.Series([10, 40, 5, 90, 35, 40]) print(s1) # 0 10 # 1 40 # 2 5 # 3 90 # 4 35 # 5 40 # dtype: int64
s2 = pd.Series(np.linspace(start=0, stop=5, num=5)) print(s2) # 0 0.00 # 1 1.25 # 2 2.50 # 3 3.75 # 4 5.00 # dtype: float64
s3 = pd.Series(np.arange(10, 15)) print(s3) # 0 10 # 1 11 # 2 12 # 3 13 # 4 14 # dtype: int32
s4 = pd.Series([100, 79, 65, 77], index=["chinese", "english", "history", "maths"], name='score') print(s4) # chinese 100 # english 79 # history 65 # maths 77 # Name: score, dtype: int64
s5 = pd.Series({"name": "张三", "Gender": "男", "age": 20, "height": 180, "weight": 66}) print(s5) # name 张三 # Gender 男 # age 20 # height 180 # weight 66 # dtype: object
2. 如何获取属性2.1 获取一维数组对象属性 在使用 Numpy 时,有时会想知道数组的某些信息,可以通过以下属性来得到: numpy.ndarray.ndim 用于返回数组的维数(轴的个数)也称为秩,一维数组的秩为 1,二维数组的秩为 2,以此类推。numpy.ndarray.shape 表示数组的维度,返回一个元组,这个元组的长度就是维度的数目,即 ndim 属性(秩)。numpy.ndarray.size 数组中所有元素的总量,相当于数组的shape 中所有元素的乘积,例如矩阵的元素总量为行与列的乘积。numpy.ndarray.dtype ndarray 对象的元素类型。
import numpy as np
a0 = np.array([10, 40, 5, 90, 35, 40]) print(a0.ndim) # 1 print(a0.size) # 6 print(a0.shape) # (6,) print(a0.dtype) # int32
2.2 获取Series对象属性 Series 除了拥有 Numpy 中ndim 、size 、shap 、dtype 属性外,还拥有下列属性: import pandas as pd
s0 = pd.Series((10, 40, 5, 90, 35, 40)) print(s0.ndim) # 1 print(s0.size) # 6 print(s0.shape) # (6,) print(s0.dtype) # int64 print(s0.index) # RangeIndex(start=0, stop=6, step=1) print(s0.values) # [10 40 5 90 35 40] print(s0.name) # None
s1 = pd.Series([100, 79, 65, 77], index=["chinese", "english", "history", "maths"], name='score') print(s1.index) # Index(['chinese', 'english', 'history', 'maths'], dtype='object')
print(s1.values) # [100 79 65 77]
3. 如何获取数据3.1 获取一维数组对象数据 一维数组只有默认的位置索引,即从0开始的索引,所以获取数据只有通过位置索引这一种方式。 - 通过整数索引(要获取数组的单个元素,指定元素的索引即可。)
- 通过切片索引(切片操作是指抽取数组的一部分元素生成新数组。)
- 通过整数数组索引(方括号内传入多个索引值,可以同时选择多个元素。)
import numpy as np
a0 = np.array([10, 40, 5, 90, 35, 40]) print(a0[0]) # 10 print(a0[0:2]) # [10 40] print(a0[2:]) # [ 5 90 35 40] print(a0[0::2]) # [10 5 35] print(a0[[0, 1, 2]]) # [10 40 5] print(a0[:5]) # [10 40 5 90 35] print(a0[-5:]) # [40 5 90 35 40] print(a0[a0 > 35]) # [40 90 40] print(a0[a0 != 35]) # [10 40 5 90 40]
3.2 获取Series对象数据 因为不附加索引的 Series 也拥有位置索引,所以可以延用一维数组获取数据的方式。另外 Series 也可以通过附加索引来获取数据。 import pandas as pd
s0 = pd.Series((10, 40, 5, 90, 35, 40)) print(s0[0]) # 10 print(s0[0:2]) # 0 10 # 1 40 # dtype: int64 print(s0[2:]) # 2 5 # 3 90 # 4 35 # 5 40 # dtype: int64 print(s0[0::2]) # 0 10 # 2 5 # 4 35 # dtype: int64 print(s0.head()) # 0 10 # 1 40 # 2 5 # 3 90 # 4 35 # dtype: int64 print(s0.tail()) # 1 40 # 2 5 # 3 90 # 4 35 # 5 40 # dtype: int64 print(s0[[0, 1, 2]]) # 0 10 # 1 40 # 2 5 # dtype: int64
s1 = pd.Series([100, 79, 65, 77], index=["chinese", "english", "history", "maths"], name='score') print(s1["chinese"]) # 100 print(s1[["english", "history"]]) # english 79 # history 65 # dtype: int64 print(s1[s1.values > 70]) # chinese 100 # english 79 # maths 77 # Name: score, dtype: int64 print(s1[s1.index != 'chinese']) # english 79 # history 65 # maths 77 # Name: score, dtype: int64
s2 = pd.Series({"name": "张三", "Gender": "男", "age": 20, "height": 180, "weight": 66}) print(s2["name"]) # 张三 print(s2[["name", "height", "weight"]]) # name 张三 # height 180 # weight 66 # dtype: object
4. 基本运算4.1 查看描述性统计数据 一维数组对象 描述性统计分析最常见的函数如下: numpy.min() 函数:返回数组的最小值或沿轴的最小值。numpy.max() 函数:返回数组的最大值或沿轴的最大值。numpy.quantile() 函数:计算沿指定轴的数据的分位数。numpy.median() 函数:沿指定轴计算中位数。返回数组元素的中位数。numpy.mean() 函数:计算沿指定轴的算术平均值。numpy.std() 函数:计算沿指定轴的标准偏差。
import numpy as np
a0 = np.array([10, 40, 5, 90, 35, 40]) print(np.size(a0)) # 6 print(np.mean(a0)) # 36.666666666666664 print(np.std(a0, ddof=1)) # 30.276503540974915 print(np.max(a0)) # 90 print(np.min(a0)) # 5 print(np.median(a0)) # 37.5 print(np.quantile(a0, [.25, .5, .75])) # [16.25 37.5 40. ]
Series对象 除了一维数组所提供的函数之外,Series也提供了更多的函数用于描述性统计分析。 import pandas as pd
s0 = pd.Series((10, 40, 5, 90, 35, 40)) print(type(s0.values)) # <class 'numpy.ndarray'> print(s0.count()) # 6 print(s0.mean()) # 36.666666666666664 print(s0.std()) # 30.276503540974915 print(s0.max()) # 90 print(s0.min()) # 5 print(s0.median()) # 37.5 print(s0.quantile([.25, .5, .75])) # 0.25 16.25 # 0.50 37.50 # 0.75 40.00 # dtype: float64
print(s0.mode()) # 0 40 # dtype: int64 print(s0.value_counts()) # 40 2 # 35 1 # 5 1 # 90 1 # 10 1 # dtype: int64 print(s0.describe()) # count 6.000000 # mean 36.666667 # std 30.276504 # min 5.000000 # 25% 16.250000 # 50% 37.500000 # 75% 40.000000 # max 90.000000 # dtype: float64
4.2 数学运算 一维数组对象 numpy.subtract() 函数:按元素相减。numpy.multiply() 函数:按元素相乘。numpy.divide() 函数:返回输入的实际除法(按元素)。numpy.floor_divide() 函数:返回小于或等于输入除法的最大整数(地板除)。
在 Numpy 中对以上函数进行了运算符的重载,且运算符为 元素级。也就是说,它们只用于位置相同的元素之间,所得到的运算结果组成一个新的数组。 import numpy as np
a0 = np.array([10, 40, 5, 90, 35, 40]) print(a0 + 1) # [11 41 6 91 36 41] print(a0 - 1) # [ 9 39 4 89 34 39] print(a0 * 2) # [ 20 80 10 180 70 80] print(a0 / 2) # [ 5. 20. 2.5 45. 17.5 20. ] print(a0 // 2) # [ 5 20 2 45 17 20] print(a0 % 2) # [0 0 1 0 1 0] print(a0 ** 2) # [ 100 1600 25 8100 1225 1600]
print(np.sqrt(a0)) # [3.16227766 6.32455532 2.23606798 9.48683298 5.91607978 6.32455532] print(np.log(a0)) # [2.30258509 3.68887945 1.60943791 4.49980967 3.55534806 3.68887945]
Series对象 Series 与 Numpy 中的一维数组一样支持常用运算符的重载,并且可以把 Series对象 作为参数带入到 Numpy 的数学运算中。 numpy.sqrt() 函数:按元素返回数组的非负平方根。
import pandas as pd import numpy as np
s0 = pd.Series((10, 40, 5, 90, 35, 40)) print(type(s0.values)) # <class 'numpy.ndarray'> print(s0 + 1) # 0 11 # 1 41 # 2 6 # 3 91 # 4 36 # 5 41 # dtype: int64
print(s0 - 1) # 0 9 # 1 39 # 2 4 # 3 89 # 4 34 # 5 39 # dtype: int64
print(s0 * 2) # 0 20 # 1 80 # 2 10 # 3 180 # 4 70 # 5 80 # dtype: int64
print(s0 / 2) # 对每个值除2 # 0 5.0 # 1 20.0 # 2 2.5 # 3 45.0 # 4 17.5 # 5 20.0 # dtype: float64
print(s0 // 2) # 对每个值除2后取整 # 0 5 # 1 20 # 2 2 # 3 45 # 4 17 # 5 20 # dtype: int64
print(s0 % 2) # 取余 # 0 0 # 1 0 # 2 1 # 3 0 # 4 1 # 5 0 # dtype: int64
print(s0 ** 2) # 求平方 # 0 100 # 1 1600 # 2 25 # 3 8100 # 4 1225 # 5 1600 # dtype: int64
print(np.sqrt(s0)) # 求开方 # 0 3.162278 # 1 6.324555 # 2 2.236068 # 3 9.486833 # 4 5.916080 # 5 6.324555 # dtype: float64
print(np.log(s0)) # 求对数 # 0 2.302585 # 1 3.688879 # 2 1.609438 # 3 4.499810 # 4 3.555348 # 5 3.688879 # dtype: float64
4.3 其它运算 由于 Series 可以附加索引,所以两个 Series对象 进行相加的时候,必须满足索引对齐。另外,Series 可以通过to_numpy() 方法转化成 Numpy 的一维数组。 import pandas as pd import numpy as np
s1 = pd.Series({'a': 10, 'b': 40, 'c': 5, 'd': 90, 'e': 35, 'f': 40}, name='数值') s2 = pd.Series({'a': 10, 'b': 20, 'd': 23, 'g': 90, 'h': 35, 'i': 40}, name='数值') s3 = s1 + s2 print(s3) # a 20.0 # b 60.0 # c NaN # d 113.0 # e NaN # f NaN # g NaN # h NaN # i NaN # Name: 数值, dtype: float64 print(s3[s3.isnull()]) # c NaN # e NaN # f NaN # g NaN # h NaN # i NaN # Name: 数值, dtype: float64 print(s3[s3.notnull()]) # a 20.0 # b 60.0 # d 113.0 # Name: 数值, dtype: float64 s4 = s3.fillna(s3.mean()) print(s4) # a 20.000000 # b 60.000000 # c 64.333333 # d 113.000000 # e 64.333333 # f 64.333333 # g 64.333333 # h 64.333333 # i 64.333333 # Name: 数值, dtype: float64
a1 = s1.to_numpy() print(a1) # [10 40 5 90 35 40] a2 = s2.to_numpy() print(a2) # [10 20 23 90 35 40] a3 = s3.to_numpy() print(a3) # [ 20. 60. nan 113. nan nan nan nan nan] print(a3[np.logical_not(np.isnan(a3))]) # [ 20. 60. 113.] m = np.mean(a3[np.logical_not(np.isnan(a3))]) a4 = np.copy(a3) a4[np.argwhere(np.isnan(a4))] = m print(a4) # [ 20. 60. 64.33333333 113. 64.33333333 # 64.33333333 64.33333333 64.33333333 64.33333333]
总结我们通过实例从对象的创建、属性的获取、数据的访问以及常用函数等维度对比了 Numpy 的一维数组和 Pandas 的 Series 结构。很多知识都是相通的,多对比多总结就会对整个模块有更深入的了解。今天就到这里吧,See You。
|