目录
Pandas是一个开放源码的Python库,它使用强大的数据结构提供高性能的数据操作。Pandas最初被作为金融数据分析工具而开发出来,因此,pandas为时间序列分析提供了很好的支持。 Pandas的名称来自于面板数据(panel data)和python数据分析(data analysis)。panel data是经济学中关于多维数据集的一个术语,在Pandas中也提供了panel的数据类型。
Pandas 数据结构
Series:一维数组,与Numpy中的一维array类似,二者与Python基本的数据结构List也很相近。Series如今能保存不同种数据类型,字符串、boolean值、数字等。
Time-Series:以时间为索引的Series。
DataFrame:二维的表格型数据结构,很多功能与R中的data.frame类似,可以将DataFrame理解为Series的容器。
Panel :三维数组,可以理解为DataFrame的容器。
series结构
也称Series序列,是Pandas常用数据结构之一,类似于一维数组,由一组数据值和一组标签组成,其中标签与数据值具有对应关系。
标签不必是唯一的,但必须是可哈希类型,该对象即支持基于整数的索引,也支持基于标签的索引,并提供了许多方法来执行涉及索引的操作。ndarray的统计方法已被覆盖,自动排除缺失的数据(目前表示为NaN)。
Series可以保存任何数据类型,比如整数、字符串、浮点数、Python对象等,它的标签默认为整数,从0开始依次递增,Series结构图:
import pandas as pd
一、数据结构Series创建
pd.Series(data=None, index=None, dtype=None, name=None, copy=False)
data:输入的数据,可以是列表、常量、ndarray数组等。如果是字典,则保持参数顺序。
index:索引值,必须是可散列的(不可变数据类型(str,bytes和数据类型)),并且与数据具有相同的长度,允许使用非唯一索引值。如果未提供,将默认为RangeIndex(0,1,2,...,n)
dtype:输出系列的数据类型,如果未指定,将从数据中推断
copy:表示对data进行拷贝,默认为False,仅影响Series和ndarray数组。
创建
1.列表、数组作为数据源创建Series
列表作为数据源创建Series
ar_list = [3,10,3,4,5]
print(type(ar_list))
#使用列表创建Series
s1 = pd.Series(ar_list)
print(s1)
print(type(s1))
输出:
数组作为数据源:
#数组作为数据源
np_rand = np.arange(1,6)
# 使用数组创建Series
s1 = pd.Series(np_rand)
s1
输出:
通过index和values属性取得对应的标签和值
#默认为Range Index(0,1,2,...n)
s1.index
输出:
RangeIndex(start=0, stop=5, step=1)
可以强制转化为列表输出
list(s1.index)
输出:
[0, 1, 2, 3, 4]
返回Series所有值,数据类型为ndarray:
#返回Series所有值,数据类型为ndarray
print(s1.values,type(s1.values))
输出:
[1 2 3 4 5] <class 'numpy.ndarray'>
通过索引取得对应的值,或者修改对应的值:s1[1]
输出:2
s1[2]= 50
s1
输出:
0 1
1 2
2 50
3 4
4 5
dtype: int32
Series不能通过-1索引:s1[-1]
报错:-1 is not in range
总结Series结构索引和列表结构索引的区别:
默认的索引RangeIndex,不能使用负值来表示从后往前找元素
获取不存在的索引值对应数据,会报错,但是可以赋值,相当于新增数据
可以新增不同类型索引的数据,新增后索引的类型会自动发生变化
不能索引s[-1],但可以新增s[-1]:
s1[-1]=20
print(s1)
print(s1.index)
输出:
0 1
1 2
2 50
3 4
4 5
-1 20
dtype: int64 #类型由int32-->int64
Int64Index([0, 1, 2, 3, 4, -1], dtype='int64')
新增不同类型索引的数据:
s1["a"] = 40
s1
输出:
0 1
1 2
2 50
3 4
4 5
-1 20
a 40
dtype: int64
2.字典作为数据源创建Series
d = {'a':1, 'b':2, 'c':3}
ser = pd.Series(data=d)
ser
输出:
a 1
b 2
c 3
dtype: int64
查看标签:
ser.index
输出:Index(['a', 'b', 'c'], dtype='object')
查看值:
ser.values
输出:array([1, 2, 3], dtype=int64)
查看某一标签对应的值:ser['a']
输出:1
修改值:
ser['s'] = 50
ser
输出:
a 1
b 2
c 3
s 50
dtype: int64
如果标签非数值型,可以用标签取数据,也可以用下标取数据:ser[1]
输出:2 (和ser[‘b’]获取的数据一样)
标签如果存在数值型的数据,就不能使用标签的下标获取值:
如
d = {'a':1,0:2,'c':3} #标签含有数值型
ser1 = pd.Series(data=d)
ser1
d = {'a':1,0:2,'c':3}
ser1 = pd.Series(data=d)
ser1
d = {'a':1,0:2,'c':3}
ser1 = pd.Series(data=d)
ser1
a 1
0 2
c 3
dtype: int64
使用ser1[1]
报错:
index参数
索引值,必须是可散列的(不可变数据类型(str,bytes和数值类型)),并且与数据具有相同的长度,允许使用非唯一索引值。如果未提供,将默认为RangeIndex(0,1,2,…,n)
使用”显示索引“的方法定义索引标签:
data = np.array(['a','b','c','d'])
#自定义索引标签(即显式索引),需要和数据长度一致
s = pd.Series(data,index=[100,101,102,103])
s
输出:
100 a
101 b
102 c
103 d
dtype: object
从指定索引的字典构造序列:
d = {'a':1, 'b':2, 'c':3}
ser = pd.Series(d, index=['a','b','c'])
ser
输出:
a 1
b 2
c 3
dtype: int64
当传递的索引值未匹配对应的字典键时,使用NaN(非数字)填充
d = {'a':1, 'b':2, 'c':3}
ser = pd.Series(data=d, index=['x','b','z'])
ser
输出:
x NaN
b 2.0
z NaN
dtype: float64
通过匹配的索引值,改变创建Series数据的顺序
d = {'a':1, 'b':2, 'c':3}
ser = pd.Series(data=d, index=['c','b','a'])
ser
输出:
c 3
b 2
a 1
dtype: int64
name参数
我们可以给一个Series对象命名,也可以给一个Series数组中的索引列起一个名字,pandas为我们设计好了对象的属性,并设置了name属性值用来进行名字的设定。
dict_data1 = {
"Beijing":2200,
"Shanghai":2500,
"shenzhen":1700
}
data1 = pd.Series(dict_data1)
data1
输出:
Beijing 2200
Shanghai 2500
shenzhen 1700
dtype: int64
命名:
data1 = pd.Series(dict_data1)
data1.name = "City_Data"
data1.index.name = "City_name"
print(data1)
输出:
City_name#'City_name'是索引的name
Beijing 2200
Shanghai 2500
shenzhen 1700
Name: City_Data, dtype: int64 #'City_Data'是data1的name
DataFrame类型
序列的名称,如果是DataFrame的一部分,还包括列名
如果用于形成数据帧,序列的名称将成为其索引或列名,每当使用解释器显示序列时,也会是用它。
使用Series创建dataFrame类型:
df = pd.DataFrame(data1)
print(df,type(df))
print("="*20)
#输出City_Data列的数据和类型
print(df['City_Data'])
print(type(df['City_Data']))
输出:
City_Data
City_name
Beijing 2200
Shanghai 2500
shenzhen 1700 <class 'pandas.core.frame.DataFrame'>
====================
City_name
Beijing 2200
Shanghai 2500
shenzhen 1700
Name: City_Data, dtype: int64
<class 'pandas.core.series.Series'>
copy参数
copy表示对data进行拷贝,默认为False,仅影响Series和ndarry数组
使用数组创建Series,改变改变Series标签为1的值:
#数组作为数据源
np_rand = np.arange(1,6)
s1 = pd.Series(np_rand)
s1[1] = 50
#输出Series对象s1
print("s1:\n",s1)
#输出数组对象为np_rand
print("np_rand:",np_rand)
输出:
s1:
0 1
1 50
2 3
3 4
4 5
dtype: int32
np_rand: [ 1 50 3 4 5]#改变了
当源数据非Series和ndarray类型时,将列表作为数据源,改变Series标签为1的值:
my_list = [1,2,3,4,5,6]
s2 = pd.Series(my_list)
s2[1] = 50
print("s2:",s2)
print("my_list:",my_list)
输出:
s2: 0 1
1 50
2 3
3 4
4 5
5 6
dtype: int64
my_list: [1, 2, 3, 4, 5, 6]#未改变
二、Series的索引/切片
1.下标索引
位置索引和标签索引刚好一致,会使用标签索引:
s = pd.Series(np.random.rand(5))
print(s)
print(s[3], type(s[3]), s[3].dtype)
输出:
0 0.681156
1 0.209843
2 0.617324
3 0.374747
4 0.968413
dtype: float64
0.37474695269005986 <class 'numpy.float64'> float64
使用负值时,实际上并不存在负数的标签索引
当索引对象为object类型时,既可以使用标签索引,也可以使用位置索引
Series类似于固定大小的dict,把Index中的标签索引当作key,而把Series中的序列值当作value,然后通过index索引标签来访问或修改元素值。
使用索标签访问单个元素值:
s = pd.Series(np.random.rand(5), index=list("abcde"))
print(s["b"],type(s["b"]), s["b"].dtype)
输出:
0.9686922887415305 <class 'numpy.float64'> float64
使用索引标签访问多个元素值:
s = pd.Series([6,7,8,9,10],index = ['a','b','c','d','e'])
print(s)
#注意需要选择多个标签的值,用[[]]来表示(相当于[]中包含一个列表)
print(s[['a','c','d']])
输出:
a 6
b 7
c 8
d 9
e 10
dtype: int64
a 6
c 8
d 9
dtype: int64
多标签会创建一个新的数组:
s1 = s[['b','a','e']]
s1["b"] = 2
print("s1:\n",s1)
print("s源数据:\n",s)
输出:
s1:
b 2
a 6
e 10
dtype: int64
s源数据:
a 6
b 7
c 8
d 9
e 10
dtype: int64
3.切片
Series使用标签切片运算和普通的Python切片运算不同:
Series使用标签切片时,其末端是包含的。
Series使用Python切片运算即使用位置数值切片,其末端不包含。
通过下标切片的方式访问Series序列中的数据:
s = pd.Series(np.random.rand(10))
s[1:5]
输出:
1 0.023120
2 0.281411
3 0.883626
4 0.477901
dtype: float64
位置索引和标签索引刚好一致,使用切片时,如果是数值会认为是python切片运算,不包含末端
s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e'])
print(s)
print(s[1:4])
输出:
a 1
b 2
c 3
d 4
e 5
dtype: int64
b 2
c 3
d 4
dtype: int64
如果想要获取最后三个元素,可以使用下面方式:
s = pd.Series([1,2,3,4,5], index = ['a','b','c','d','e'])
print(s[-3:])
输出:
c 3
d 4
e 5
dtype: int64
通过标签切片的方式访问Series序列中的数据:
s1 = pd.Series([6,7,8,9,10],index = ['a','b','c','d','e'])
s1["b":"d"]
末端包含:
b 7
c 8
d 9
dtype: int64
s1["c":"c"]
输出:
c 8
dtype: int64
注意:
当index为数值类型的时候:
进行索引的时候,相当于使用的是名称索引(使用位置索引会报错)
进行切片的时候,相当于使用的是位置切片
三、Series数据结构 基本技巧
1.查看前几条和后几条数据
s = pd.Series(np.random.rand(15))
s
输出:
0 0.609290
1 0.162900
2 0.751565
3 0.886997
4 0.263947
5 0.984391
6 0.829509
7 0.095259
8 0.966457
9 0.447003
10 0.746117
11 0.587411
12 0.350907
13 0.849317
14 0.016918
dtype: float64
s.head()的使用
print(s.head())#默认查看前5条数据
print(s.head(1))#默认查看前1条数据
输出:
print(s.head())#默认查看前5条数据
print(s.head(1))#默认查看前1条数据
print(s.head())#默认查看前5条数据
print(s.head(1))#默认查看前1条数据
0 0.609290
1 0.162900
2 0.751565
3 0.886997
4 0.263947
dtype: float64
0 0.60929
dtype: float64
s.tail()的使用:
print(s.tail())# 默认查看后5条数据
输出:
10 0.746117
11 0.587411
12 0.350907
13 0.849317
14 0.016918
dtype: float64
2.重新索引 reindex
使用可选填充逻辑,使Series符合新索引
将NaN放在上一个索引中没有值得位置,除非新索引等同于当前索引,并且生成新对象。
s = pd.Series(np.random.rand(5),index=list("abcde"))
print("+++++++++++s+++++++++")
print(s)
#新索引在上一个索引中不存在,生成新对象时,对应的值,设置为NaN
s1 = s.reindex(list("cde12"))
print("+++++++++++s+++++++++")
print(s1)
输出:
+++++++++++s+++++++++
a 0.790252
b 0.490827
c 0.439055
d 0.425065
e 0.597086
dtype: float64
+++++++++++s+++++++++
c 0.439055
d 0.425065
e 0.597086
1 NaN
2 NaN
dtype: float64
设置填充值:
s2 = s.reindex(list("cde12"), fill_value=0)
print(s2)
输出:
c 0.439055
d 0.425065
e 0.597086
1 0.000000
2 0.000000
dtype: float64
3.对齐运算
是数据清洗的重要过程,可以按索引对齐进行计算,如果没对齐得位置则补NaN,最后也可以填充NaN
s1 = pd.Series(np.random.rand(3),index=["kelly","Anne","T-C"])
s2 = pd.Series(np.random.rand(3), index=["Anne", "Kelly", "Lily"])
print("========s1========")
print(s1)
print("========s2========")
print(s2)
print("========s1+s2========")
print(s1+s2)
输出:
========s1========
kelly 0.002373
Anne 0.070553
T-C 0.756331
dtype: float64
========s2========
Anne 0.950720
Kelly 0.240003
Lily 0.607813
dtype: float64
========s1+s2========
Anne 1.021272
Kelly NaN
Lily NaN
T-C NaN
kelly NaN
dtype: float64
4.删除和添加
删除:
返回删除后的值,原值不改变,默认Inplace=False:
s = pd.Series(np.random.rand(5),index=list("abcde"))
print(s)
s1 = s.drop("a") #返回删除后的值,原值不改变,默认Inplace=False
print(s1)
print(s)
输出:
a 0.325819
b 0.338770
c 0.580162
d 0.377663
e 0.248908
dtype: float64
b 0.338770
c 0.580162
d 0.377663
e 0.248908
dtype: float64
a 0.325819
b 0.338770
c 0.580162
d 0.377663
e 0.248908
dtype: float64
将inplace置为True
s = pd.Series(np.random.rand(5),index=list("abcde"))
s1 = s.drop("a",inplace=True) #原值发生变化,返回None
print(s1)
print("========")
print(s)
输出:
None
========
b 0.994583
c 0.877292
d 0.756831
e 0.670073
dtype: float64
添加
s1 = pd.Series(np.random.rand(5),index=list("abcde"))
print(s1)
s1["s"] = 100
print(s1)
输出:
a 0.713630
b 0.142949
c 0.285360
d 0.422420
e 0.117981
dtype: float64
a 0.713630
b 0.142949
c 0.285360
d 0.422420
e 0.117981
s 100.000000
dtype: float64