pandas基础
1、pandas
pandas是基于Numpy的一种工具,该工具是为解决数据分析任务而创建的,Pandas提供了大量能使我们快速便捷处理数据的功能。
pandas的主要数据结构是Series(一维数据)和DataFrame(二维数据),这两种数据结构足以处理金融、统计、社会科学、工程等领域的大多数案例。
pip install pandas
工具安装pandas
2、Series
类似于一维数组的对象
Python容器数据
有序的:tuple(元组)、list(列表)
无序的:dict(字典) 、set(集合)
有键值对的:dict
没有键值对的:tuple、list、set
能用键取值的,就不能用索引,能用索引的就不能用键
Series对象既可以通过索引访问数据,也可以通过键访问数据,既类似于列表,又类似于字典。
为什么要使用键进行访问?——使用键访问,提高数据的可读性。
比如成绩,75,80,70,90,如果使用列表来存储,list_score=[75,80,70,90],想要取出成绩80,得通过索引list_score[1]来取,如果使用字典来存储,dict_score={“张三”:75,"李四":80,"王五":70,"韩梅":90},通过键dict_score["李四"]来取,
Series的数据结构:
索引 数据 键
0 75 张三
1 80 李四
2 70 王五
3 90 韩梅
2.1 Series的创建
Series数据是包含两部分的一维数据,一部分是索引(键)标签——显示索引,两一部分是下标——隐式索引,是在给定数据的时候,下标就已经设置好了。
Series创建有两种方式:一种是通过列表或者一维数组进行创建,另一种通过字典进行创建。
通过列表或者一维数组创建
list_score=[75,80,70,90]
#data——设置的一维数据
#index——设置显示索引,如果没有设置,默认使用的是隐式索引当作显示索引
seires_score = pd.Series(data=list_score)
print(seires_score)
arr = np.random.randint(1,10,size=5)#通过numpy创建一个长度是5的随机数组
series_arr = pd.Series(data=arr)
print(series_arr)
#设置显示索引
arr_1 = np.random.randint(1,100,size=4)
index_1 = ["张三","李四","王五","韩梅"]
series_1 = pd.Series(data=arr_1,index=index_1)
通过字典进行创建
dict_score={"张三":75,"李四":80,"王五":70,"韩梅":90}
#字典的键会被自动设置为显示索引
series_2 = pd.Series(data=dict_score)
print(series_2)
#也可以设置显示索引,设置显示索引的时候,是根据显示索引去字典中查找对应的值,如果没有,,值就为NaN
series_3 = pd.Series(data=dict_score,index=['Tom',"李四",'Jack','Ann'])
print(series_3)
#NaN,not a number,就是空值的意思
2.2索引和切片
索引分为隐式索引和显示索引
显示索引取值
s=pd.Series([10,20,30,40],index=['a','b','c','d'])
#通过显示索引取值,类似字典中的键取值
s['a']
#Series自带的,把显示索引当作属性,类似属性的取值形式
s.a
#.loc的形式(推荐),可以访问多个或者单个
s.loc['a']#取单个
s.loc[['a','d']]#取多个
#还可以使用布尔列表取值,列表中数据的个数与数组中元素的个数一致
bl=np.random.choice([False,True],size=s.size)
s.loc[bl]
隐式索引取值
s=pd.Series([10,20,30,40],index=['a','b','c','d'])
#通过隐式索引取值
#整数作为索引值
s[0]
#.iloc获取(推荐)
s.iloc[0]#取单个
s.iloc[[1,3,2,0]]#取多个
显示索引切片
s=pd.Series([10,20,30,40],index=['a','b','c','d'])
#显示索引切片包头和包尾
s.loc['a':'c']
#当我们不设置显示索引的时候,显示索引和隐式索引是一样的,怎么区分是用显示索引还是隐式索引?
#loc使用的就是显示索引,iloc使用的是隐式索引(包头,不包尾)
s=pd.Series([10,20,30,40])
s.loc[1:3]
s.iloc[1:3]
#切片也支持步长式切片
s1=s.loc[::-1]
s1.iloc[0]
#隐式索引——就是数组的下标,下标的顺序都是从0开始
#显示索引——数据的标记,跟着数据走
2.3 Series的属性和方法
Series的属性:shape(形状),size(元素个数),index(显示索引),values(数据)
s=pd.Series([10,20,30,40],index=['a','b','c','d'])
s.shape#(4,),得到的是一个元组,元组里面只有一个数据,就是列数,因为Series是一维的
s.size#4,元素的个数
s.index#Index(['a', 'b', 'c', 'd'], dtype='object'),获取的是显示索引
s.values#[10 20 30 40] 所有的数据
Series的方法:head(),tail()指定个数的数据,默认是前5个和后五个
s=pd.Series([10,20,30,40,50,60,70,80],index=['a','b','c','d','e','f','g','h'])
s.head()#得到前5个数据
s.head(2)#得到前2个数据
s.tail()#得到后5个数据
s.tail(2)#得到后2个数据
#isnull(),判断数据是否是空值,notnull(),判断数据是否不是空值,pandas中有,Series也自带有的两个方法
s.isnull()
s.notnull()
#或者
pd.isnull(s)
pd.notnull(s)
#使用判断是否有空值的方法,既可以判断数据中是否有空值,也可以提取数据中非空的数据
dict_score={"张三":75,"李四":80,"王五":70,"韩梅":90}
series_3 = pd.Series(data=dict_score,index=['Tom',"李四",'Jack','Ann'])
s3=series_3[series_3.notnull()]
#当数据量很大的时候,使用isnull()得到的数组很大的时候,如何查找判断数组中有没有空值
s.isnull().any()#any的意思就是有一个True,结果就是True
Series的其他方法:sort_index(),根据显示索引排序,sort_values(),根据值排序,value_counts()统计值出现的次数(使用较多的方法),add()
2.4 Series 运算
+,-,*,/
arr = np.random.randint(1,100,size=5)#通过numpy创建一个长度是5的随机数组
s1=pd.Series(arr,index=list('ABCDE'))
print(s+1)
s2=pd.Series(np.random.randint(1,100,size=5),index=list('CDEAB'))
print(s1+s2)#找相同的显示索引进行相加,而不是按顺序进行相加,如果显示索引都没有一样的,结果是什么?
s3=pd.Series(np.random.randint(1,100,size=5),index=list('CDEFB'))
print(s1+s3)#显示索引在另一个数组中没有,会自动补齐NaN,NaN和任何数据相加,结果都是NaN
print(np.nan+10)#nan跟任何数据操作都得nan
#如果不想出现NaN,怎么办呢?
#可以使用add()方法
print(s1.add(s3, fill_value=0))#去除NaN,使用fill_value设置指定数据替换NaN
2.5 Series作业
1.使用多种方法创建以下Series,命名为s1:
语文 150
数学 150
英语 150
理综 300
2.使用多种方法对练习1创建的Series s1进行索引和切片:
索引:数学150
切片:语文150 数学150 英语150
3.随机生成两组学生成绩,一组数据预处理 s2,一组数据挖掘 s3,,学生包括lucy、mery、tom、jack:
找出数据预处理不及格的学生姓名
找出数据挖掘不及格的学生姓名
如果需要给mery的数据预处理成绩加10分,如何实现
#1.
s1=pd.Series({'语文':150,'数学':150,'英语':150,'理综': 300})
s1=pd.Series([150,150,150,300],index=['语文','数学','英语','理综'])
#2.索引
s1['数学']
s1.loc['数学']
s1.iloc[1]
#2.切片
s1.loc['语文':'英语']
s1.iloc[:3]
#3.
s2=pd.Series(np.random.randint(1,100,size=4), index=['lucy','mery','tom','jack'])
s3=pd.Series(np.random.randint(1,100,size=4), index=['lucy','mery','tom','jack'])
s2[s2 < 60]
s3[s3 < 60]
s2['mery'] = s2['mery']+10
3、DataFrame
Series是一维的,一般的业务处理都是多维的,所以出现了DataFrame,它是基于Series,可以看成是Series的字典,键是Series的name属性,值是Series包含的数据。
DataFrame是一个表格型的结构,列标题就是Series的name属性,每一行数据就是Series中的数据
DataFrame中的数据结构是有行有列的,行是有行标题,列是有列标题的,行标题称为行所引,列标题称为列索引。
3.1 DataFrame的创建
1.使用行索引、列索引创建
2.可以使用字典创建
3.从指定的文件中读
4.Series创建
3.1.1使用行、列索引创建
#使用行索引、列索引创建,
#data:数据区是有行有列的,所以是一个二维数组
#index:行标题,一个列表
#columns:列标题,一个列表
data=np.random.randint(20,100,size=(4,2))
index=['lucy','mery','tom','jack']
columns=["数据预处理","数据挖掘"]
df = pd.DataFrame(data=data, index=index,columns=columns)
print(df)
3.1.2 使用字典创建,行索引默认是数组的下标,字典的键会被当做列索引
#使用字典创建,行索引默认是数组的下标,字典的键会被当做列索引
dic={
"数据预处理":[60,90,50,40],
"数据挖掘":[70,87,60,40]
}
df1 = pd.DataFrame(data=dic)
print(df1)
dic2={
"数据预处理":[60,90,50,40],
"数据挖掘":[70,87,60,40],
"姓名":['lucy','mery','tom','jack']
}
df2 = pd.DataFrame(data=dic2)
print(df2)
3.1.3 从文件中读取
#从文件中读取,excel读取需要组件 xlrd pip install xlrd,向文件中写入数据的话 pip install xlwt
df3=pd.read_excel("D:\work\school\课件\大数据预处理\教材案例\第7章\成绩单.xlsx")
print(df3)
#如果读取不是第一个表格,则需要设置sheet_name参数,sheet_name参数可以设置下标(下标从0开始),也可以设置名字
df4=pd.read_excel("D:\work\school\课件\大数据预处理\教材案例\第7章\成绩单.xlsx",sheet_name=1)
print(df4)
df5=pd.read_excel("D:\work\school\课件\大数据预处理\教材案例\第7章\成绩单.xlsx",sheet_name=1)
print(df4)
df5 = pd.read_excel("D:\work\school\课件\大数据预处理\教材案例\第7章\成绩单.xlsx",sheet_name='Sheet2')
print(df5)
#从csv中读取,第一个参数是csv文件所在路径,sep:分隔符(默认是,),encoding:编码(默认是UTF-8)
df6 = pd.read_csv("D:\work\school\课件\大数据预处理\教材案例\第7章\成绩单1.csv", encoding='GB2312')
print(df6)
df7 = pd.read_csv("D:\work\school\课件\大数据预处理\教材案例\第7章\成绩单2.csv", sep=";")
print(df7)
#从mysql中读取
from sqlalchemy import create_engine
#创建数据库连接对象,数据库地址、用户名、密码、数据库、编码
con = create_engine('mysql+pymysql://root:123456@localhost/kettle?charset=utf8')
sqlstr = "select * from student"
df1 = pd.read_sql(sql=sqlstr, con=con)
print(df1)
可以从excel和csv中获取DataFrame数据,那么DataFrame也可以导出一个excel和csv文件
dic3={
"期末数据预处理":np.random.randint(40,90,size=4),
"期末数据挖掘":np.random.randint(40,90,size=4),
"学生姓名":['lucy','mery','tom','jack']
}
df8 = pd.DataFrame(data=dic3)
print(df8)
#将DataFrame数据导出到一个csv文件,sep:分隔符(默认是逗号),index:是否输出行索引(False:不输出,True:输出),header:是否输出列标题(False:不输出,True:输出)
df8.to_csv("D:\work\school\课件\大数据预处理\教材案例\第7章\期末成绩单.csv", index=False)
#将DataFrame数据导出一个excel文件,index:是否输出行索引(False:不输出,True:输出),header:是否输出列标题(False:不输出,True:输出),sheet_name:工作表名字
df8.to_excel("D:\work\school\课件\大数据预处理\教材案例\第7章\期末成绩单.xlsx", index=False, sheet_name="期末成绩")
#将DataFrame数据导出到mysql表中,参考第三章基于触发器CDC的导入与导出.py
3.1.4 Series创建
s2=pd.Series(np.random.randint(30,100,size=4), index=['lucy','mery','tom','jack'],name="数据预处理")
df2 = pd.DataFrame(s2)#Series的name属性就是列标题,index就是行标题
print(df2)
#只把预处理数据添加了,还有数据挖掘的数据没有添加,怎么添加呢?
s3=np.random.randint(30,100,size=4)
df2['数据挖掘']=s3#类似字典添加键值对的方式
print(df2)
3.1.5 DataFrame练习
1、创建一个DataFrame,变量名为df1,成绩数据使用随机数,打印数据结构如下(成绩值不一定一样):
张三 李四
数据挖掘 67 53
数据预处理 47 49
nosql 63 73
JavaWeb 54 31
2、创建一个形状为4*6的 DataFrame 并命名为 df2,并指定行索引为[“a”,“b”,“c”,"d"]、列索引为[“A",“B”,“C”,“D”,“E”,“F”],元素的取值为 1-100 之间的随机数。
3、从期末成绩.csv创建DataFrame并命名为df3,分隔符为;,编码格式为gbk。
#第一题
s2=pd.Series(np.random.randint(30,100,size=4), index=['数据挖掘','数据预处理','nosql','JavaWeb'],name="张三")
df1 = pd.DataFrame(s2)
df1['李四'] = np.random.randint(30,100,size=4)
#第二题
data1 = np.random.RandomState(16).randint(0,100,24)
df1 = pd.DataFrame(data=data1.reshape(4,6),index=["a","b","c","d"],columns=["A","B","C","D","E","F"])
df1
#第三题
df1=pd.read_csv("D:\work\school\课件\大数据预处理\教材案例\第7章\期末成绩.csv",sep=";")
df1
3.2 DataFrame 索引
有列索引,行索引(Series的显示索引),隐式索引(数组的下标)
3.2.1 列索引
#通过列索引访问数据——获取的是一列数据
#df[列标题] 获取多个df[[列标题1,列标题2]]
print(df2['数据挖掘']) #Series类型数据
print(df2[['数据预处理','数据挖掘']])#DataFrame类型
3.2.2 行索引(显示索引获取)
.loc[行索引],.loc[[行索引1,行索引2]]
print(df2.loc['mery'])#Series类型数据
print(df2.loc[['mery','tom']])#DataFrame类型
#也可以通过布尔类型来访问
print(df2.loc[df.数据预处理 > 60])#取数据预处理大于60分的数据
print(df2.loc[[True, False,True,False]])
#注意访问列的时候不能直接用布尔类型df2[[True,False]],可以使用.loc和切片的方式
print(df2.loc[:,[True,False]])#
#访问元素,先行后列
print(df2.loc['tom','数据预处理'])
#修改元素,比如给jack的数据挖掘加10分
df2.loc['jack','数据挖掘'] += 10
print(df2.loc['jack','数据挖掘'])
3.2.3 隐式索引获取数据
print(df2.iloc[-1])#获取1个,-1是最后一个
#获取多个,将索引放到一个列表中
print(df2.iloc[[0,-1]])#获取第一个和最后一个
#根据隐式索引获取列
print(df2.iloc[:,0])#获取第一列数据
#获取多列
print(df2.iloc[:,[0,-1]])
#隐式索引访问元素
print(df2.iloc[1,0])#第1行,第0列
#显示索引可以通过布尔类型访问
print(df2.loc[df.数据预处理 > 60])#取数据预处理大于60分的数据
#隐式索引是不是也可以这样用?
print(df2.iloc[df.数据预处理 > 60])#报错了,因为隐式索引对应的是下标,df.数据预处理>60是一个Series数据类型,它的结果中有显示索引,跟隐式索引的下标是匹配不上的,所以报错了。那应该怎么取呢?
#是不是可以取df.数据预处理 >60的values值
print((df2.数据预处理>60).values)#得到的是一个数组
print(df2.iloc[(df2.数据预处理>60).values])
####注意,隐式索引使用布尔列表筛选数据时,筛选条件中需要是列表或者一维数组包含布尔值
3.3 DataFrame切片
1.行切片
#显示索引,包头包尾
print(df2.loc['lucy':'tom'])
#隐式索引,包头不包尾
df2.iloc[:-1]
#切片也支持步长
print(df2.loc['lucy':'tom':2])
print(df2.iloc[:-1:2])
print(df2.loc[::2])#结果是?
print(df2.iloc[::2])#结果是?
print(df2.loc[::-1])#把结果反转
2.列切片
#不支持:的方式切片 df.loc['数据挖掘']不支持
#需要通过二维数组的思维对其进行切片
#显示切片,先对行进行切片,再对列进行切片
df.loc[:,:'数据挖掘']
#如果想取某一列的值,则可以通过以下方式获取
df['数据挖掘']
df.数据挖掘
df.loc[:,'数据挖掘']
3.运算
(1)跟一个数值或者跟一个数组(跟原矩阵同列)进行运算
(2)跟Series运算
(3)跟DataFrame运算
df=DataFrame(data=np.random.randint(1,100,size=(4,3)), index=list('ABCD'),columns=list('甲乙丙'))
df
#跟一个数值进行运算
df+1
#跟一个数组进行运算
arr = np.array([1,2,3])
df+arr
#跟Series运算
#Series有显示索引,默认是跟DataFrame的列索引对应,df的列是甲乙丙,s的索引是abc,两者没有共同的列,自动填充NaN,NaN加任何数据都得NaN
s=Series(data=[2,2,2], index=list('abc'))
s
df+s
#跟DataFrame运算
df1=DataFrame(data=np.random.randint(1,100,size=(4,4)), index=list('ABCD'),columns=list('甲乙丙丁'))
df+df1#丁这列的数据会为NaN
#如果想保留丁这一列的原值
df.add(df1, fill_value=0)
4.聚合函数
最大值max、最小值min、求和sum、求平均值mean
df=DataFrame(data=np.random.randint(1,100,size=(4,3)), index=list('ABCD'),columns=list('甲乙丙'))
df.sum()#默认是按列求和
df.sum(axis=1)#按行求和
#求总体的和
df.sum().sum()
#获取B这行的数据和
df.loc['B'].sum()
df.sum(axis=1).loc['B']
3.4 常用的属性和方法
3.4.1 属性
df.values获取所有数据,df.index获取行索引,df.columns获取列索引
df=DataFrame(data=np.random.randint(1,100,size=(4,3)), index=list('ABCD'),columns=list('甲乙丙'))
#获取所有的值
df.values
#行索引
df.index
#列索引
df.columns
3.4.2 方法
df.describe()查看个数、平均值、标准差、中位数等
df.info()查看每一列的数据信息
df.head()查看前几行,默认是前5行
df.tail()查看后几行,默认是后5行
3.5 作业
1、使用numpy的一维数组创建不指定索引的Series,命名s1,要求数组长度为10,随机数为60~100,包含60和100。
2、使用字典创建Series,命名s2,字典内容为:{"lucy":80,"jack":78,"tom":89,"john":90,"lili":87}
3、从字典对象data创建DataFrame,命名df1,设置行索引为labels。
data = {
'animal': ['cat', 'cat', 'snake', 'dog', 'dog', 'cat', 'snake', 'cat', 'dog', 'dog'],
'age': [2.5, 3, 0.5, np.nan, 5, 2, 4.5, np.nan, 7, 3],
'visits': [1, 3, 2, 3, 2, 3, 1, 1, 2, 1],
'priority': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'no', 'no']
}
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
4、显示df1的基础信息,包括行的数量,列名,列的数量,每一列值的非空数量、数据类型
5、展示df1的前3行
6、取出df1的animal和age列
7、取出行索引为[3, 4, 8]行的animal和age列
8、取出age值大于3的行
9、取出age值缺失的行
10、取出age在2,4间的行(包含2和4)
11、f行的age改为1.5
12、计算visits的总和
13、在df1中插入新行k,值为['dog',5.5, 2, 'no']
14、计算df1中每个种类animal的数量
#1
s1=pd.Series(np.random.randint(60,101, size=10))
#2
dic={"lucy":80,"jack":78,"tom":89,"john":90,"lili":87}
s2=pd.Series(dic)
#3
data = {'animal': ['cat', 'cat', 'snake', 'dog', 'dog', 'cat', 'snake', 'cat', 'dog', 'dog'],
'age': [2.5, 3, 0.5, np.nan, 5, 2, 4.5, np.nan, 7, 3],
'visits': [1, 3, 2, 3, 2, 3, 1, 1, 2, 1],
'priority': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'no', 'no']}
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
df1 = pd.DataFrame(data, index=labels)
#4
df1.info()
#5
df1.iloc[:3]#df1.head(3),df1.loc[:'c']
#6
df1.loc[:, ['animal', 'age']]#df1[['animal', 'age']],df1.iloc[0:-1,[0,1]]
#7
df1.loc[['d','e','i'], ['animal', 'age']]
#df1.loc[df1.index[[3, 4, 8]], ['animal', 'age']]
#df1.iloc[[3,4,8],[0,1]]
#8
df1[df1['age'] > 3]
#9
df1[df1['age'].isnull()]
#10
df1[(df1['age']>=2) & (df1['age']<=4)]
#df1[df1['age'].between(2, 4)]
#11
df1.loc['f', 'age'] = 1.5
#12
df1['visits'].sum()
#13
df1.loc['k'] = ['dog',5.5, 2, 'no']
#14
df1['animal'].value_counts()