作者: Kevin Chen
Series可以理解为一个一维的数组,只是 index 名称可以自己改动。类似于定长的有序字典,有 Index 和 value。
# 创建一个series
import pandas as pd
data1 = (1,2,3,4) # 用元组构建序列
data2 = [5,6,7,8] # 用列表构建序列
s1 = pd.Series(data1)
s2 = pd.Series(data2)
print(s1)
""" 输出: # 第一列为索引; 第二列为值; dtype: int64 标明值的数据类型
0 1 # 虽然显示出来看很像是个二维数组 (4行2列); 但实际上是一维的, 第一列是索引
1 2
2 3
3 4
dtype: int64
"""
print(s2)
""" 输出:
0 5
1 6
2 7
3 8
dtype: int64
"""
# 创建一个series, 并且自定义index (自定义的index常常被称为'标签')
import pandas as pd
# 方法1: 在pd.Series()函数中用index参数用列表给出索引
data = ['nana', 'kk', 'sisi']
s = pd.Series(data, index=['st01', 'st02', 'st03']) # 在函数中使用index参数
print(s)
""" 输出:
st01 nana
st02 kk
st03 sisi
dtype: object
"""
# 方法2: 用字典创建
data = {'s1': 'nana', 's2': 'kk', 's3': 'sisi'} # 以字典创建series时, 默认键既是标签
s = pd.Series(data)
print(s)
"""输出:
s1 nana
s2 kk
s3 sisi
dtype: object
"""
创建随机整数series
import pandas as pd
import numpy as np
# random.randint的参数: low>>区间的下限,high>>区间的上限,size>>个数的多少
# 用random.randint方法随机创建 最小值为0, 最大值为10, 包含5个元素的整数序列
s1 = pd.Series(np.random.randint(low=0,high=10,size=5), index=['s1','s2','s3','s4','s5'])
print(s1)
""" 输出:
s1 7
s2 3
s3 6
s4 2
s5 2
dtype: int32
"""
创建随机小数series
import pandas as pd
import numpy as np
# random.rand函数可以返回一个或一组服从“0~1”均匀分布的随机样本值。随机样本取值范围是[0,1),不包括1
# 用random.rand方法随机创建 最小值为0, 最大值为10, 包含5个元素的小数序列
s = pd.Series(np.random.rand(5)*10, index=['s1','s2','s3','s4','s5'])
# 将随机数乘以10, 使数值随机生成在10以内的小数
print(s)
""" 输出:
s1 1.703992
s2 5.007543
s3 1.370512
s4 0.324551
s5 7.296572
dtype: float64
"""
创建符合状态分布的series
import pandas as pd
import numpy as np
# random.normal函数可以返回一个或一组正态分布的随机样本。参数为:平均值, 方差, 数据数量
# 随机生成5个符合平均值为10,方差为0.5的正态分布数值
s = pd.Series(np.random.normal(10,0.5,5), index=['s1','s2','s3','s4','s5'])
print(s)
""" 输出:
s1 9.798803
s2 10.175873
s3 9.937731
s4 9.837918
s5 10.154241
dtype: float64
"""
series类型数据可以通过索引或标签进行提取单个元素
# 使用索引or标签检索元素 (有坑, 需注意)
# 当自定义标签为 字符串 时, 仍然能用索引查找元素
data = {'s1': 'nana', 's2': 'kk', 's3': 'sisi'}
s = pd.Series(data)
print(s['s1']) # 输出'nana'
print(s[0]) # 输出'nana'
# 当自定义的标签为 int 时,会与index冲突, pandas默认使用标签, 而不是使用索引
s = pd.Series([1,2,3,4,5,6], index=[1, 2, 3, 4, 5, 6])
print(s[1]) # 输出1
print(s[0]) # 会报错...KeyError
series类型数据可以用索引或标签进行切片提取多个元素
# 用索引or标签对元素进行切片 (有坑, 需注意)
data = ['ss', 'kk', 'mm', 'tt']
# 用索引切片时,!!!!包前不包后!!!!
s1 = pd.Series(data)
print(s1[1:3]) # 输出kk, mm
# 用标签切片时,!!!!包前也包后!!!!
s2 = pd.Series(data, index=['1','2','3','4'])
print(s2['1':'3']) # 输出ss, kk, mm
# 若自定义标签为字符串,那索引仍然能正常使用
print(s2[1:3]) # 输出kk, mm (用索引, 包前不包后)
series类型数据可用mask掩码数组进行掩码提取多个元素:
- 掩码来自于numpy库, 是用来处理数组的一种方法 (不导入numpy可用, pandas库中有)
- 掩码数组也是一种数组,它本质上是对目标数组做一种特殊处理
- 掩码通常用来表明被掩数据哪些要处理,哪些不必处理
# 用掩码数组mask获取数据
data = ['ss', 'kk', 'mm', 'tt']
s1 = pd.Series(data, index=['1','2','3','4'])
# 在使用掩码时, 索引&标签 都 !!!!包前也包后!!!!
print(s1[[0, 1, 2]]) # 输出: ss, kk, mm
print(s1[['3', '4']]) # 输出: mm, tt
print(s1[[True, True, False, True]]) # 输出: ss, kk, tt
用head()和tail()方法获取头部/尾部的多个元素
# 创建series
data = ['ss', 'kk', 'mm', 'tt', 'kq', 'ew', 'xs']
s = pd.Series(data, index=['s1','s2','s3','s4', 's5', 's6', 's7'])
# 获取头部3个数据 (若head方法内不写参数,则默认获得头部5个数据)
s.head(3)
""" 输出:
s1 ss
s2 kk
s3 mm
dtype: object
"""
# 获取尾部到数2个数据 (若tail方法内不写参数,则默认获得尾部5个数据)
s.tail(2)
""" 输出:
s6 ew
s7 xs
dtype: object
"""
用for循环遍历series中的标签和元素值 (类似于字典)
data = ['ss', 'kk', 'mm', 'tt']
s2 = pd.Series(data, index=['s1','s2','s3','s4'])
# series有index属性, 可获得series的标签/索引
for i in s2.index:
print(i) # 输出: s1, s2, s3, s4
# series有values属性, 可获得series的元素值
for i in s2.values:
print(i) # 输出: ss, kk, mm, tt
# 直接对series进行遍历获得其值
for i in s2:
print(i) # 输出: ss, kk, mm, tt
# series可以用items()方法返回 标签&元素
for i, v in s2.items():
print(i) # 输出: s1, s2, s3, s4
print(v) # 输出: ss, kk, mm, tt
# 先创建一个series
data = {'s1': 'nana', 's2': 'kk', 's3': 'sisi'}
a = pd.Series(data)
用键值对方法添加单个元素
- 会改变原有的series !!!
a['s4']='lalo'
print(a)
"""输出:
s1 nana
s2 kk
s3 sisi
s4 lalo
dtype: object
"""
用append()方法在series中添加多个元素
使用 append() 方法时, 添加的数据必须与原数据是相同类型的
不会改变原series !!! 产生一个新series
# 向序列中添加新数据{'s5': 'wawa', 's6': 'yoyo'}, 带有自定义标签
b = a.append(pd.Series({'s5': 'wawa', 's6': 'yoyo'})) # 不会修改原series, 而是返回一个新的series
print(a, b)
"""
a: s1 nana
s2 kk # 可见a序列没有变化, append()不会修改原本的a序列
s3 sisi
s4 lalo
dtype: object,
b: s1 nana
s2 kk
s3 sisi # b序列中出现了添加的数据
s4 lalo
s5 wawa
s6 yoyo
dtype: object
"""
# 向序列中添加新数据['wawa', 'yoyo'], 不带自定义标签
c = a.append(pd.Series(['wawa', 'yoyo']))
print(c)
"""
c: s1 nana
s2 kk
s3 sisi
s4 lalo
0 wawa # 由于没有自定义标签, 所以系统默认从0开始添加索引
1 yoyo
dtype: object
"""
print(c[0]) # 输出: wawa
print(c[2]) # 会报错....KeyError
用del删除series中的单个元素
- 会改变原series
print(a)
"""a序列含有以下数据:
s1 nana
s2 kk
s3 sisi
s4 lalo
dtype: object
"""
# 用del输出标签为's1'的元素
del a['s1']
print(a)
"""删除后, a序列输出:
s2 kk
s3 sisi
s4 lalo
dtype: object
"""
用drop()删除series中的多个数据
- 不会改变原series, 而是产生一个新series
print(a)
"""a序列含有以下数据:
s1 nana
s2 kk
s3 sisi
s4 lalo
dtype: object
"""
# 删除a序列中's1'标签的数据 (用drop方法进行单数据删除)
b = a.drop('s1')
print(a, b)
""" 输出:
a: s1 nana
s2 kk
s3 sisi
s4 lalo
dtype: object
b: s2 kk
s3 sisi
s4 lalo
dtype: object
"""
# 删除a序列中's1'和's2'标签的数据 (用drop方法进行多数据删除)
c = a.drop(['s1', 's2'])
print(a, c)
""" 输出:
a: s1 nana
s2 kk
s3 sisi
s4 lalo
dtype: object
c: s3 sisi
s4 lalo
dtype: object
"""
# 用series的索引删除单个数据 (只能用索引, 不能用标签)
d = a.drop(c.index[2])
print(d)
"""
s1 nana
s2 kk
s4 lalo
dtype: object
"""
# 用series的索引删除多个数据 (只能用索引, 不能用标签)
e = a.drop(a.index[[1,2]])
print(e)
"""
s1 nana
s4 lalo
dtype: object
"""
通过标签/索引 修改series内单个元素的值
# 创建一个series
data = ['ss', 'kk', 'mm', 'tt']
s = pd.Series(data, index=['s1','s2','s3','s4'])
# 将标签为s1的值修改为'ww' 修改单个元素值
s['s1'] = 'ww'
print(s)
"""直接修改原series
s1 ww
s2 kk
s3 mm
s4 tt
dtype: object
"""
通过掩码 修改series内多个元素的值
# 将标签为's1'和's3'的值修改为'dd'和'll' 使用的是掩码的原理
s[['s1', 's3']] = 'dd', 'll'
print(s)
"""直接修改原series
s1 dd
s2 kk
s3 ll
s4 tt
dtype: object
"""
# 创建两个series用于测试属性
# s1有自定义标签, 元素为字符串
data1 = ['ss', 'kk', 'mm', 'tt']
s1 = pd.Series(data1, index=['1', '2', '3', '4'], name='s序列')
# s2无自定义标签, 元素为整数
data2 = [1, 2, 3, 4, 5]
s2 = pd.Series(data2)
series的name属性
- 在创建series的时候, 可以添加一个name参数作为series的名字, 创建上方s1序列的创建
print(s1.name) # 输出: 's序列'
series的value属性, 以数组 (ndarray)形式返回series内的元素值
- ndarray: ndarray对象是用于存放同类型元素的多维数组,是numpy中的基本对象之一
# values属性, 返回series元素值 (不是列表, 是ndarray对象)
print(s1.values) # 输出: ['ss' 'kk' 'mm' 'tt']
print(s2.values) # 输出: [1 2 3 4 5]
# 可以用values属性判断series中是否存在某数据
# 例: 判断b序列中是否存在'wawa'
print('wawa'in b.values) # 输出: True
# 用values可以以ndarry形式返回序列中的数据
series的index属性, 以数组 (ndarray)形式返回series内的 索引或标签
# index属性, 返回标签/索引的值,和类型
print(s1.index) # 输出: Index(['1', '2', '3', '4'], dtype='object') 返回标签
print(s2.index) # 输出: RangeIndex(start=0, stop=5, step=1) 返回索引
series的dtype属性, 可以得到元素的数据类型
object数据类型是什么?
- 当一个数组中都是同一个数据类型时, 系统能给出那个数据类型的名称 ( 比如都是整数类型时,会给出inte64 )
- 但是当一个数组中存在不同的数据类型时, 系统会返回object ( 由于字符串的长度不定, 所以字符串被认为是object )
- object这是一种通用的数据类型, 在没有明确的指定类型的情况下, 所有的数据都可以认为是object型
# dtype属性, 返回series数据的类型
print(s1.dtype) # 输出: object
print(s2.dtype) # 输出: int64
series的size属性, 可以得到series含有的元素数量
# size属性, 返回series的长度(元素数量)
print(s1.size) # 输出: 4
print(s2.size) # 输出: 5
series的ndim属性, 返回维度, series永远是一维
# ndim属性, 返回series的维度 (series本身就是个一维的数组,所以没啥用)
print(s1.ndim) # 输出: 1
print(s1.ndim) # 输出: 1
series的shape属性, 可以获得series含有的元素数量
# shape属性, 以元组形式返回各维度的大小(元素数量), (3维: 页,行,列), (2维: 行,列), (1维: 列,)
print(s1.shape) # 输出: (4,)
print(s2.shape) # 输出: (5,)
sum() 方法
- 获取dtype为数字类型的series的所有值的和
- 注意! 如果dtype为object, 会报错
# 数字类型的series求和
s1 = pd.Series(data=[1.1,2,3.0,4,5.2],index=["a","b","c","d","e"])
print(s1.sum()) # 输出 15.3
# 数字类型的object求和
s2 = pd.Series(data=[1.1,2,3.0,4,"5.2"],index=["a","b","c","d","e"])
s2.sum() # 报错...TypeError
Series之间的运算
- 支持Numpy数组运算
- 在运算中自动对齐不同索引的数据
- 如果索引不对应,则补NaN
# 创建两个series
s1 = pd.Series(data=[1,2,3,4,5],index=["a","b","c","d","e"])
s2 = pd.Series(data=[1,2,3,4,5],index=["a","b","c","d","f"])
# 将s1和s2相加
s = s1 + s2
print(s)
"""输出s:
a 2.0
b 4.0
c 6.0
d 8.0
e NaN
f NaN
dtype: float64
"""
# 将s1与s2相乘
s = s1 * s2
print(s)
""" 输出s:
a 1.0
b 4.0
c 9.0
d 16.0
e NaN
f NaN
dtype: float64
"""
# 对s1序列进行取余运算
s = s1 % 2
print(s)
""" 输出s:
a 1
b 0
c 1
d 0
e 1
dtype: int64
"""
# series之间还支持/, // 等运算
apply() 与 map() 方法
- 在series中, apply与map方法的功能相同
- apply()方法, 让函数作用在一维数据的每个元素上
- map()方法, 将函数作用于Series的每一个元素上
# 创建series
s1 = pd.Series(data=[1,2,3,4,5],index=["a","b","d","e","f"])
# 创建一个函数,函数内的传参为series的元素
def func(item):
return 10 * item
# map()函数
s = s1.map(func)
print(s)
""" 输出:
a 10
b 20
d 30
e 40
f 50
dtype: int64
"""
# apply()函数
s = s1.apply(func)
print(s)
""" 输出:
a 10
b 20
d 30
e 40
f 50
dtype: int64
"""
isnull() 与 notnull() 方法, 用于判断元素值是否为空
"""
isnull() # 缺失的数据返回的布尔值为True
notnull() # 缺失的数据返回的布尔值为False
"""
# 创建一个含有2个NaN的series
import pandas as pd
import numpy as np
s1 = pd.Series(data=[1,np.NaN,3,4,np.NaN],index=["a","b","c","d","e"])
# isnull()方法
print(s1.isnull()) # 输出所有数据是否为NaN
""" 输出:
a False
b True
c False
d False
e True
dtype: bool
"""
print(s1.isnull().sum()) # 用sum()方法输出NaN数据的数量
# 输出: 2
# notnull()方法
print(s1.notnull()) # 输出所有数据是否不为NaN
""" 输出:
a True
b False
c True
d True
e False
dtype: bool
"""
print(s1.notnull().sum()) # 用sum()方法输出不为NaN数据的数量
# 输出: 3
用unique()方法对series的值进行去重
# 创建series
data = ['ss', 'kk', 'ss', 'tt', 'kk', 'ew', 'tt']
a = pd.Series(data, index=['s1','s2','s3','s4', 's5', 's6', 's7'])
# 对a序列去除重复值, 不会改变原series, 输出一个类型为ndarray的新对象
b = a.unique()
print(b) #输出: array(['ss', 'kk', 'tt', 'ew'], dtype=object)
argmax() 与 argmin() 方法
- argmax() 返回series中最大值的位置 (第几个位置的值是最大值, 从0开始算)
- argmin() 返回series中最小值的位置 (第几个位置的值是最大值, 从0开始算)
# 创建series
s1 = pd.Series(data=[3,2,1,4,5],index=["a","b","d","e","f"])
print(s1.argmax()) # 输出: 4 >>> 第五个元素的值最大(5)
print(s1.argmin()) # 输出: 2 >>> 第三个元素的值最大(1)
reindex()方法: 用于添加新标签,以及修改标签顺序
- index参数, fill_value参数
# 创建测试序列
s1 = pd.Series(data=[1,2,3,4,5],index=["a","b","d","e","f"])
# index参数: 用于添加新标签,以及修改标签顺序
s = s1.reindex(index=['a','b','c','d','e','f','g','h'])
print(s)
""" 输出:
b 2.0
a 1.0 # 可见标签顺序修改后, 相应值的顺序也改变了
c NaN
d 3.0
e 4.0
f 5.0
g NaN # 新标签对应的值为NaN
h NaN
dtype: float64
"""
# fill_value参数: 用于填充新标签对应的值
s1['e'] = np.NaN # 将e标签对应的值修改为NaN
s = s1.reindex(index=['a','b','c','d','e','f','g','h'], fill_value=6)
print(s)
""" 输出:
a 1.0
b 2.0
c 6.0
d 3.0
e NaN # 可见原本series中的NaN不会被填充掉
f 5.0
g 6.0 # 其他新标签对应的值, 全部被填充为6
h 6.0
dtype: float64
"""
sort_index() 函数
- 将series根据标签/索引的顺序, 重新排序
- 对某些有序object类标签也同样有效
# 创建一个数字类型标签的series
s1 = pd.Series(data=["a","b","d","e","f"],index=[3,2,1,4,5])
# 用倒序进行排序ascending=False, (默认为正序,从小到大)
s = s1.sort_index(ascending=False)
print(s)
""" 输出:
5 f
4 e
3 a
2 b
1 d
dtype: object
"""
# 创建一个字符串类型标签的series
s1 = pd.Series(data=["a","b","d","e","f"],index=['cc', 'bb', 'aa','dd','ee'])
# 用正序进行排序ascending=True, (默认为正序,从小到大)
s = s1.sort_index(ascending=True)
print(s)
""" 输出:
aa d
bb b
cc a
dd e
ee f
dtype: object
"""
sort_value() 函数
- 将series根据元素的值的顺序, 重新排序
- 对某些有序object类值也同样有效
# 创建索引
s1 = pd.Series(data=[4,3,2,1,5],index=['cc', 'bb', 'aa','dd','ee'])
# 根据元素的值,将series排序
s = s1.sort_values(ascending=True)
print(s)
""" 输出:
dd 1
aa 2
bb 3
cc 4
ee 5
dtype: int64
"""
rank() 方法
- 输出series的每个元素的值的排列名次
- 对某些有序object类值也同样有效
# 创建序列
s1 = pd.Series(data=['c','c','a','d','e'],index=['s1','s2','s3','s4','s5'])
# 输出序列中每个元素的名次, 根据从大到小排列, 排列同名次的按平均值输出
s = s1.rank(ascending=False, method='average')
print(s)
""" 输出:
s1 3.5 # 有两个'c', 并列排名第三第四名, 平均后就是3.5
s2 3.5 # 有两个'c', 并列排名第三第四名, 平均后就是3.5
s3 5.0
s4 2.0
s5 1.0 # 'e'最大, 所以排名为1
dtype: float64
"""
# 创建序列
s1 = pd.Series(data=[4,3,3,1,5],index=['s1','s2','s3','s4','s5'])
# 输出序列中每个元素的名次, 根据从小到大排列, 排列名次相同的按最小数字输出
s = s1.rank(method='min')
print(s)
""" 输出:
s1 4.0
s2 2.0 # 有两个3, 并列派第二第三名, 按最小数字输出, 既是2
s3 2.0 # 有两个3, 并列派第二第三名, 按最小数字输出, 既是2
s4 1.0 # 1最小, 所以排第一名
s5 5.0
dtype: float64
"""
# method参数有: min, max, average, first, last
copy() 方法, 复制一个Series
# 先创建一个series
s1 = pd.Series(data=[1,2,3,4,5],index=["a","b","c","d","e"])
# 复制
s = s1.copy()
print(s)
"""
a 1
b 2
c 3
d 4
e 5
dtype: int64
"""