前言
阅读文本前要求读者了解jupyter如何使用,以及python的基础语法,同时还要求读者了解基本的numpy和matplotlib函数.如果不了解两个包的语法,可以大致学习一下.
Series
Series结构
Series结构,也称Series序列,是Pandas常用的数据结构之一,它是一种类似于一维数组的结构,由一组数据值(value)和一组标签组成,其中标签与数据值具有对应关系。
标签不必是唯一的,但必须是可哈希类型。该对象既支持基于整数的索引,也支持基于标签的索引,并提供了许多方法来执行涉及索引的操作。ndarray的统计方法已被覆盖,以自动排除缺失的数据(目前表示为NaN)
Series 可以保存任何数据类型,比如整数、字符串、浮点数、Python对象等,它的标签默认为整数,从0开始依次递增。Series的结构图,如下所示:
pd.Series(data=None,index=None,dtype=None,name=None,copy=False)
- data输入的数据,可以是列表、常量、ndarray数组等,如果是字典,则保持参数顺序
- index索引值,必须是可散列的(不可变数据类型(str, bytes和数值类型)),并且与数据具有相同的长度.允许使用非唯一索引值。如果未提供,将默认为Rangelndex (0,1,2…,n)
- dtype输出系列的数据类型。如果未指定,将从数据中推断.
- name为Series定义一个名称
- copy表示对data进行拷贝,默认为False,仅影响Series和ndarray数组
先简单的创建一个Series
list = [1,2,True,'str',1.0] index = [0,1,4,2,3] # 设定对应的数组位置的数据索引为该索引 例如本来True索引为2,这里变为4 s=pd.Series(list,index=index)# 使用index并不会修改原series中数据的顺序 print(s[4]) # 只是使用下标访问的时候数据顺序与放进去的list集合不一样而已 print(s.values) print(s.index) # 获取元素对应索引 s[0]=10 print(s) # print(s[-1]) # 会报错,Series默认找的是标签,而不是下表,因此不能使用负值,他不能从后往前走 s[-1]=100 # 但是如果向里面添加-1这个标签,那么下次就可以访问-1并且不会报错 s['a']='abcde' print('s[a]====',s['a']) print(s)
Series的数据可以使用标签进行访问,如果标签为非全数字,那么也可以使用标签对应的索引进行访问
list = {'a': 1,'b':2,'c':3} # 直接传入一个字典变为Series s = pd.Series(list) print(s) print(s.index) print(s.values) print(s['a']) s['d']=4 # 添加一个标签d-->4 print(s[3]) # 可以使用标签对应的下标去取对应的数据
data = ['a','b','c','d'] s = pd.Series(data,index=[1,2,3,4]) print(s) # print(s[-1]) # 因为index索引为全数字,那么此时的检索方法为标签检索,因此无法使用下标进行检索 s[-1]=-1 # 但是你还是可以继续添加元素' s = pd.Series(data,index=['a','b','c',4]) print(s) print(s[-1]) # 此时索引为非全数字,那么就可以使用索引进行访问
现在来介绍一下name这个属性
data = { "one":1, "two":2, "three":3 } num = pd.Series(data) num.name = 'num_data' num.index.name = 'num_name' print(num) print('----------') df = pd.DataFrame(num) print(df,type(df)) print('----------') print(df['num_data'],type(df['num_data']))
现在来介绍copy这个参数
# copy表示队data进行拷贝,默认为False,仅影响Series和ndarray数组 # 也就是如果你的data来自于ndarray,那么你对Series数据的修改也会修改对应的ndarray数组 data = np.arange(1,6) s = pd.Series(data) s[1]=10 # 修改Series的值 print(s) print(data)# 可以发现data的值居然也被修改了
# 如果数据源来自于非Series和ndarray类型 list = [1,2,3,4] s = pd.Series(list) s[1]=10 print(s) print(list) # 可以发现list并没有杯修改
Series的索引与切片
这里应该自己多编写代码进行测试来帮助自己了解索引和切片
s = pd.Series(np.random.rand(5),index=['h','x','s','b','n']) # 进行切片运算 print(s[1:3]) # 使用索引不包含end print(s[-3:]) # 从-3开始向后切片 print(s[-3::-1]) # 从-3开始向前切片 print(s[::]) print(s['s':'n']) # 甚至可以使用标签进行切片 包含end 从s开始知道找到标签n
# 如果数据源来自于非Series和ndarray类型 list = [1,2,3,4] s = pd.Series(list,index=[1,2,3,4]) s[1]=10 print(s[-1])#索引类型为数字的时候,此时位置索引失效,使用的为标签索引 # 如果没有找到-1这个标签,那么就报错 print(list) # 可以发现list并没有杯修改
注意:
在上面的索引方式,我们知道了位置索引和标签索引在index为数值类型时候的不同,
- 当index为数值类型的时候,使用位置索引会抛出keyerror的异常,也就是说当index为数值类型的时候,索引使用的是名称索引。
- 但是在切片的时候,有很大的不同,如果index为数值类型的时候,切片使用的是位置切片。总的来说,当index为数值类型的时候:
- 进行索引的时候,相当于使用的是名称索引;
- 进行切片的时候,相当于使用的是位置切片;
head/tail
这两个方法用于查看Series头尾数据,默认都是5条
s = pd.Series(np.random.rand(10)) print(s.head()) # 默认查看头5条数据 print(s.head(1)) # 查看头1条数据 print(s.tail()) # 默认查看尾5条数据 print(s.tail(1)) # 查看尾1条数据
reindex
用于重新设定Series的index索引
s = pd.Series(np.random.rand(5),index=['h','x','s','b','n']) print(s) s1 = s.reindex(['a','b','c','d','e']) # 以返回一个新的Series的形式新建index,因为这样效率更高 # 同时只有原索引和新索引中拥有重复的索引名称的时候对应的值才会被赋予,否则为NaN print(s1) s2=s1.reindex(['g','e','f'],fill_value=0) # 重定义索引之后如果被赋予了NaN,那么fill_value可以填充其为对应的值 # 例如这里由于s1和s2中都有e,但是原来的s1中的e本来就为NaN所以并不会被赋予0.0 # 而g和f都是s1原来没有的,因此他们的NaN会变为0.0 print(s2)
对齐运算
是数据清洗的重要过程,可以按索引/标签对齐进行运算,如果没对齐的位置则补NaN,最后也可以填充NaN.
s1 = pd.Series(np.random.rand(3),index=['a','b','c']) s2 = pd.Series(np.random.rand(3),index=['b','a','h']) print(s1) print(s2) print(s1+s2) # 可以发现没有对齐的数据直接被赋予了NaN
添加删除
s = pd.Series(np.random.rand(5),index=['a','b','c','d','e']) print(s) s1 = s.drop('c',inplace=True) # 在原值上发送变化,返回None s['f']=100 # 进行添加 如果没有标签f 那么就添加 有就修改 print(s1) print(s)
DataFrame
DataFrame是Pandas 的重要数据结构之一,也是在使用Pandas进行数据分析过程中最常用的结构之一,可以这么说,掌握了DataFrame 的用法,你就拥有了学习数据分析的基本能力。|
DataFrame是一个表格型的数据结构,既有行标签(index),又有列标签(columns),它也被称异构数据表,所谓异构,指的是表格中每列的数据类型可以不同。比如可以是字符串、整型或者浮点型等。其结构图示意图,如下所示:
DataFrame的每一列数据都可以看成一个Series结构,只不过,DataFrame为每列数据值增加了一个列标签。因此DataFrame其实是从 Series的基础上演变而来,并且他们有相同的标签,在数据分析任务中 DataFrame的应用非常广泛,因为它描述数据的更为清晰、直观。
同Series一样,DataFrame自带行标签索引,默认为“隐式索引"即从0开始依次递增,行标签与DataFrame 中的数据项一 一对应。当然你也可以用"显式索引的方式来设置行标签。
下面对 DataFrame数据结构的特点做简单地总结,如下所示:
- DataFrame每—列的标签值允许使用不同的数据类型;
- DataFrame是表格型的数据结构,具有行和列;
- DataFrame 中的每个数据值都可以被修改。
- DataFrame结构的行数、列数允许增加或者删除;
- DataFrame有两个方向的标签轴,分别是行标签和列标签;
- DataFrame可以对行和列执行算术运算。
pandas. DataFrame (data=None,index=None,columns=None,dtype=None,copy=None)
- data:输入的数据,可以是ndarray,series, list,dict,标量以及一个 DataFrame
- index:行标签,如果没有传递 index值,则默认行标签是RangeIndex(0,1,2… n),n代表data的元素个数。
- columns:列标签,如果没有传递columns值,则默认列标签是RangeIndex(0,1,2,… n)。
- dtype:要强制的数据类型。只允许使用一种数据类型。如果没有,自行推断
- copy:从输入复制数据。对于dict数据,copy=True,重新复制一份。对于DataFrame或ndarray输入,类似于copy=False,使用的是视图
最基本的,使用列表嵌套列表创建DataFrame
df = pd.DataFrame([[1,'大少',12],[2,'太君',16]],index=[1,2],columns=['学号','名字','年龄']) print(df)
之后就是使用列表掏钱字典创建
df = pd.DataFrame(data=[{'a':1,'c':3},{'a':2,'b':3}],index=['one','two']) print(df) # 取交集进行显示 df = pd.DataFrame(data=[{'a':1,'c':3},{'a':2,'b':3}],index=['one','two'],columns=['a','b','d']) # 因为d这一列压根就没有对应的元素,所以直接全为NaN print(df) # 取交集进行显示
使用字典嵌套列表的方式进行创建
data={ 'Name':['a','b','c','d'] , 'Age':[1,2,3,4] } df = pd.DataFrame(data,index=['one','two','three','four']) print(df) print(df.index) print(df.columns)
也可以使用Series创建DataFrame对象
# 如果使用这种形式,其实是吧name对应的索引名字改为了1 2 3 # 而其他的几个属性的索引还是 0 1 2 因此就会导致数据不对应 # d = {'name':pd.Series(['zhang','wang','li'],index=[1,2,3]), d = {'name':pd.Series(['zhang','wang','li']), 'age':pd.Series([20,30,40],dtype=float), 'sex':pd.Series(['nan','nv','nan']), 'money':pd.Series([10,20,30],dtype=float)} df = pd.DataFrame(d) # 你可以试着在不同的属性上添加上index print(df) # 这里one虽然显示了对应的索引d,但是由于没给数据,因此直接NaN
了解了如何创建DataFrame,之后就要了解如何增删改查DataFrame了
首先进行对DataFrame列的操作
下面先进行的是列的选取操作
# 选取对应数据列 data={ 'Name':['a','b','c','d'] , 'Age':[1,2,3,4] } df = pd.DataFrame(data,index=['one','two','three','four']) print(df) print('---获取Name列-----') print(df['Name']) print('---获取Age列-----') print(df['Age']) print('---获取Name和Age列-----') print(df[['Name','Age']]) print('---获取某一列数据------') print(df['Name']['one']) print('---遍历某一列数据------') for i in df['Name']: print(i)
接下来是添加操作
d = {'one':pd.Series([2,3,4,5],index=['a','b','c','d']), 'two':pd.Series([20,30,40],index=['a','b','c'])} df = pd.DataFrame(d) # 你可以试着在不同的属性上添加上index print(df) print('---获取某一列数据------') df['three']=pd.Series([5,6,7],index=['a','b','c']) print(df) print('---获取某一列数据------') df['four']=df['one']+df['three'] print(df)
d = {'one':pd.Series([2,3,4,5],index=['a','b','c','d']), 'two':pd.Series([20,30,40],index=['a','b','c'])} df = pd.DataFrame(d) # 你可以试着在不同的属性上添加上index print(df) print('---获取某一列数据------') # 使用insert添加,第一个参数表示要插入到的位置,0<=loc<=len(列) # 第二个参数为添加后的列名标签 # 第三个表示要插入到该列的值 # 第四个表示是否允许列名重复 df.insert(2,column='three',value=[1,2,3,4]) print(df)
最后是删除操作
d = {'one':pd.Series([2,3,4,5],index=['a','b','c','d']), 'two':pd.Series([20,30,40],index=['a','b','c'])} df = pd.DataFrame(d) df.insert(2,column='three',value=[1,2,3,4]) print(df) print('---获取某一列数据------') del df['one'] # 使用del删除某一列 print(df) print('---获取某一列数据------') del_data=df.pop('two') # 使用pop删除某一列数据 print(df) print('---pop删除会返回被删除的数据------') print(del_data)
列操作结束之后,来进行DataFrame的行操作
行操作相对于列操作,就不能直接使用[]进行访问,而需要使用loc进行访问
loc使用的是标签名称进行访问,他的访问方式很类似与numpy中的一些语法,但是又有所不同
例如df.loc[[‘a’,‘b’],[‘c’,‘d’]]他访问的是行标签名称为a和b的两行,且列标签为c和d的两列,也就是最后会返回2*2个数据
而np[[0,1],[1,2]]访问的则是索引为(0,1)和(1,2)的,也就是他遵循的是一一对应原则,而不是loc中的一行对一列原则.
d = {'one':pd.Series([2,3,4,5],index=['a','b','c','d']), 'two':pd.Series([20,30,40],index=['a','b','c'])} df = pd.DataFrame(d) print(df) print('显示行b上的所有数据') print(df.loc['b']) print('注意loc的两个参数分别是行和列') print(df.loc['b','one']) print('行和列还可以使用切片') print(df.loc['b':'d','one':'two']) # 行截取b--d 列选取one与two print('第一个参数代表代表行,第二个参数代表列') print(df.loc[['a','b'],['one','two']])# 获得行索引为a和b且列索引为one和two的数据 展示的数据量为rows*cols # DataFrame和numpy数组是有区别的 s=np.arange(12).reshape((3,4)) print(s) print(s[[0,1],[1,2]]) # 获取(0,1),(1,2)
如果不想使用标签进行访问,那么可以使用iloc方法,iloc方法直接使用索引,会优先查找的是行标签,如果找不到就会报错.
特别注意:
loc只能使用标签进行搜索,使用索引会报错
iloc只能使用索引来进行搜索,使用标签就会报错
d = {'one':pd.Series([2,3,4,5],index=['a','b','c','d']), 'two':pd.Series([20,30,40],index=['a','b','c'])} df = pd.DataFrame(d) print(df) print('-------') print(df.iloc[2]) # 查找第二行上的数据 print('-------') print(df.iloc[[1,2,3]])# 查找索引为1,2,3行上的数 print('-------') print(df.iloc[0,1]) # 查找第0行第1列上的数据 # 这里等同于 print(df.loc['a']['two']) # print(df.iloc['a']['two']) # iloc只能使用数值 因此使用标签查找会报错 # print(df.loc[0,1]) # loc只能使用标签,使用数值会报错 print(df.loc['a','two']) print('-------') print(df.iloc[1:3]) # iloc可以使用索引进行切片 print('-------') print(df.loc['a':'c']) # loc只能使用标签进行切片