技术图文:Numpy 一维数组 VS. Pandas Series

背景

Numpy 提供的最重要的数据结构是 ndarray,它是 Python 中 list 的扩展。

Pandas 提供了两种非常重要的数据结构 Series和DataFrame。

Numpy 中的一维数组与 Series 相似,一维数组只是提供了从0开始与位置有关的索引,而Series除了位置索引之外还可以附加额外的索引。本文将从对象的创建、属性的访问、数据的获取以及常用方法等方面来总结这两种结构的异同。

1. 如何创建对象

1.1 创建一维数组对象

  • 通过 list或tuple 创建一维数组。
  • 通过数值范围来创建一维数组,比如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
  • 通过 Numpy 创建Series

另外,Series 可以附加索引,所以可以在创建的时候直接指定需要附加的索引,以及利用字典的key-value键值对 来直接创建。

  • 通过指定index关键字的方式创建带有自定义索引的Series
  • 通过字典dict创建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 中ndimsizeshapdtype属性外,还拥有下列属性:

  • index 附加的索引
  • values 存储的数据
  • name 对象的名称
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 也可以通过附加索引来获取数据。

  • 通过位置获取数据
  • 通过索引获取数据
  • 通过head()tail()获取数据
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.add()函数:按元素相加。
  • numpy.subtract()函数:按元素相减。
  • numpy.multiply()函数:按元素相乘。
  • numpy.divide()函数:返回输入的实际除法(按元素)。
  • numpy.floor_divide()函数:返回小于或等于输入除法的最大整数(地板除)。
  • numpy.power()函数:按元素做幂运算。

在 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()函数:按元素返回数组的非负平方根。
  • numpy.log()函数:按元素取自然对数。
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。


后台回复「搜搜搜」,随机获取电子资源!
欢迎关注,请扫描二维码:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青少年编程备考

感谢您的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值