about
有了numpy,为啥还要学习pandas?
numpy已经可以帮助我们进行数据的处理了,那么学习pandas的目的是什么呢?
numpy能够帮助我们处理的是数值型的数据,当然在数据分析中除了数值型的数据还有好多其他类型的数据(字符串,时间序列),那么pandas就可以帮我们很好的处理除了数值型的其他数据!
什么是pandas?
学习pandas的重点
主要学习pandas中两个常用的类:
- Series:是一种类似于一维数组的对象,由两个部分组成:
- values:一组数据(ndarray类型)。
- index:相关数据索引标签。
- DataFrame:由Series组成的更复杂的数据结构。
Series
我们可以暂时将Series理解为是一种类似于一维(不能是多维)数组的对象,由两个部分组成:
- values:一组数据(ndarray类型)。
- index:相关数据索引标签。
Series的创建
列表/数组充当数据源创建Series
# 用前先导入
from pandas import Series
import numpy as np
# 使用列表充当数据源
s1 = Series(data=[1,2,3,'a', 'b', 'c'])
s1
"""
0 1
1 2
2 3
3 a
4 b
5 c
dtype: object
"""
# 使用数组充当数据源
s2 = Series(data=np.random.randint(0, 10, size=(3)))
s2
"""
0 8
1 3
2 6
dtype: int32
"""
# 数组只能是一维的,不能是多维的
s3 = Series(data=np.random.randint(0, 10, size=(3, 3)))
# ValueError: Data must be 1-dimensional, got ndarray of shape (3, 3) instead
显式索引和隐式索引
注意,就算有了显式的索引,但隐式索引仍然存在。
# 隐式索引不在多表,从索引0开始的
s1 = Series(data=[1,2,3,'a', 'b', 'c'])
s1
"""
0 1
1 2
2 3
3 a
4 b
5 c
dtype: object
"""
# 显示索引可以增强Series的可读性
# 使用index参数添加显式索引
s2 = Series(data=[1, 2, 3],index=['a','b','c'])
s2
"""
a 1
b 2
c 3
dtype: int64
"""
字典充当数据源创建Series
dic = {
'语文':100,
'数学':99,
'理综':250
}
s = Series(data=dic)
s
"""
语文 100
数学 99
理综 250
dtype: int64
"""
Series的索引和切片
因为Serise的数据源是一维数组,所以,其索引和切片跟一维数组差不多,非常好理解。
s1 = Series(data=[1, 2, 3], index=['a','b','c'])
# 按照索引取值
# s1[0] # 1
# 最后一个
# s1[2] # 'c'
# s1[4] # IndexError: index 4 is out of bounds for axis 0 with size 3
# 倒着取
# s1[-1], s1[-2] # (3, 2)
# 上面这几种方式都可以,但如果你的pandas版本高的话,会有FutureWarning,说这种方式即将弃用
# 你想要索引取值,应该这么来
# s1.iloc[0], s1.iloc[2], s1.iloc[-1] # (1, 3, 3)
# 如果有显式索引的话,也可以通过显式索引来索引取值
# s1.a, s1.b, s1.c # (1, 2, 3)
# 全切
# s1[:]
# 按照范围切
# s1[0:3], s1[1:], s1[:2], s1[:-1]
# 加步长的切
# s1[::-1], s1[::2]
Series的常用属性
注意,如果数据源中的数据类型不统一,Series内部会转为统一类型,这个思想跟numpy一样,都是为了方便运算。
s = Series(data=[1,2,3,'four'],index=['a','b','c','d'])
s.shape # 形状
s.size # 长度
s.index # 返回索引
s.values # 返回值
s.dtype # 元素的类型,数据类型O表示的是Object(字符串类型)
"""
(4,) # 有4个元素的一维数组
4
Index(['a', 'b', 'c', 'd'], dtype='object')
array([1, 2, 3, 'four'], dtype=object)
dtype('O')
"""
Series的常用方法
s = Series(data=np.random.randint(60,100,size=(10,)))
s.head(3) # 显示前n个数据
s.tail(3) # 显示后n个元素
s.unique() # 去重的结果
s = Series(data=np.array([1, 2, np.nan], dtype=np.float32))
s
"""
0 1.0
1 2.0
2 NaN
dtype: float32
"""
s.isnull() #用于判断每一个元素是否为空,为空返回True,否则返回False
"""
0 False
1 False
2 True
dtype: bool
"""
# 用于判断每个元素是否为空,不为空的返回True,否则返回False
s.notnull()
"""
0 True
1 True
2 False
dtype: bool
"""
"""
法则:索引一致的元素进行算数运算否则补空
算术运算时,可以使用运算符 + - * /
也可以使用封装好的add() sub() mul() div()这几个方法
"""
s1 = Series(data=[1,2,3],index=['a','b','c'])
s2 = Series(data=[1,2,3],index=['a','d','c'])
# s = s1 + s2
"""
a 2.0
b NaN # 索引不一致,为空
c 6.0
d NaN # 索引不一致,为空
dtype: float64
"""
# s1.add(s2)
# 对于索引位置有空缺的,一律用NaN表示
"""
a 2.0
b NaN
c 6.0
d NaN
dtype: float64
"""
# 对于空值可以通过fill_value进行替换
# 注意,一定是相同索引位置的进行运算
s1.add(s2, fill_value=9)
"""
a 2.0
b 11.0 # 只有s1中有索引b,s2没有索引b,被fill_value替换为9,然后参与与s1的b索引位置的值运算
c 6.0
d 11.0
dtype: float64
"""
# 参考:https://pandas.pydata.org/docs/reference/api/pandas.Series.add.html
DataFrame
DataFrame是一个"表格型"的数据结构。
DataFrame由按一定顺序排列的多列数据组成,每一列的数据可能不同。
设计初衷是将Series的使用场景从一维拓展到多维。
DataFrame既有行索引,也有列索引。
- 行索引:index
- 列索引:columns
- 值:values,numpy的二维数组。
显式索引 | col1 | col2 | col3 | |
---|---|---|---|---|
显式索引 | 隐式索引 | name | age | addr |
r1 | 0 | 张开 | 18 | 北京 |
r2 | 1 | 李开 | 19 | 上海 |
r3 | 2 | 王开 | 29 | 广州 |
r4 | 3 | 赵开 | 30 | 深圳 |
DataFrame的创建
可以通过numpy来创建,也可以通过字典来创建。
df对象的创建
# 行列都使用默认的索引
# df = DataFrame(data=np.random.randint(0, 100, size=(3, 4)))
# df
# 自定义行列索引的,你可以按需指定某一个都行
# df = DataFrame(data=np.random.randint(0, 100, size=(3, 4)), index=['i1', 'i2', 'i3'], columns=["a", "b", "c", "d"])
# df
# 字典作为数据源
dic = {
"name": ["张开", "李开", "赵开"],
"salary": [9999, 9998, 0]
}
# 默认的,字典的key会作为df的列索引,你可以按需指定行索引
df = DataFrame(data=dic, index=["a", "b", "c"])
df
df对象的属性
dic = {
'name':['zhangsan','lisi','wanglaowu'],
'salary':[1000,2000,3000]
}
df = DataFrame(data=dic,index=['a','b','c'])
# df.values
"""
array([['张开', 9999],
['李开', 9998],
['赵开', 0]], dtype=object)
"""
# df.columns # Index(['name', 'salary'], dtype='object')
# df.index # Index(['a', 'b', 'c'], dtype='object')
# df.shape # (3, 2)
小练习来了
"""
根据以下考试成绩表,创建一个DataFrame,命名为df:
张三 李四
语文 150 25
数学 150 20
英语 150 30
理综 300 50
"""
dic = {
'张三':[150,150,150,150],
'李四':[25,20,30,50]
}
df = DataFrame(data=dic,index=['语文','数学','英语','理综'])
df
df对象的索引操作
df = DataFrame(data=np.random.randint(60,100,size=(8,4)),columns=['a','b','c','d'])
df
# 传一个值,默认是取第一列
# 如果df有显式的索引,通过索引机制去行或者列的时候只可以使用显示索引
# df[0] # 这个肯定就报错了,列有显式索引
df["a"] # 这个可以
# 取多列
df[['a','c']]
"""
iloc: 通过隐式索引取行
loc: 通过显示索引取行
无论是索引还是切片的时候,用这俩方法时,一定要注意是隐式还是显式索引,不能瞎用,否则报错
"""
#取单行
df.loc[0]
#取多行
df.iloc[[0,3,5]]
#取单个元素,第几行第几列的元素
df.iloc[0, 2]
# df.iloc[0, "a"] # 报错,因为iloc只能隐式取索引
df.loc[0, 'a']
#取多个元素,取哪几行的第几列的元素
df.iloc[[1,3,5],2]
df = DataFrame(data=np.random.randint(60,100,size=(8,4)),columns=['a','b','c','d'])
df
#切行,切前两行
# df[0:2]
#切行,切后两行
# df[-2:]
#切行,按需切
# df[2:5]
#切列,所有行的前两列
# df.iloc[:,0:2]
#切列,所有行的后两列
# df.iloc[:,-2:]
#切列,所有行,按需切列
# df.iloc[:,1:3]
#切列,指定行,指定列
# df.iloc[1:3,1:3]
df索引和切片操作小结:
索引:
- df[col]:取列
- df.loc[index]:取行
- df.iloc[[0,3,5]]:取多行
- df.iloc[index,col]:取元素
切片:
- df[index1:index3]:切行
- df.iloc[:,col1:col3]:切列
df对象的运算
df对象的运算规则参考Series的运算规则。
这里以算术运算为例:
"""
法则:索引一致的元素进行算数运算否则补空
算术运算时,可以使用运算符 + - * /
也可以使用封装好的add() sub() mul() div()这几个方法
"""
df1 = DataFrame(data=np.random.randint(0,10,size=(8,4)),columns=['a','b','c','d'])
df2 = DataFrame(data=np.random.randint(0,10,size=(8,4)),columns=['a','b','c','d'])
display(df1, df2)
# df1 + df2
df1.add(df2)
------- 继续从这开始搞运算 -------------
小练习来喽
1. 假设midterm是期中考试成绩,final是期末考试成绩,
请自由创建final,并将其与midterm相加,求期中期末平均值。
dic = {
'张三':[52, 52, 15, 46, 22],
'李四':[31, 24, 78, 57, 9],
'王五':[59, 47, 90, 50, 56],
'赵六':[27, 48, 92, 20, 71],
}
midterm = DataFrame(data=dic,index=['语文','数学','英语','理综', "政治"])
midterm
2. 假设张三期中考试数学被发现作弊,要记为0分,如何实现?
3. 李四因为举报张三作弊立功,期中考试所有科目加10分,如何实现?
4. 后来老师发现期中考试中有一道题出错了,
为了安抚学生情绪,给每位学生每个科目都加10分,如何实现?
dic = {
'张三':[52, 52, 15, 46, 22],
'李四':[31, 24, 78, 57, 9],
'王五':[59, 47, 90, 50, 56],
'赵六':[27, 48, 92, 20, 71],
}
dic2 = {
'张三':[0, 88, 19, 37, 38],
'李四':[67, 16, 24, 11, 42],
'王五':[33, 29, 10, 50, 6],
'赵六':[6, 67, 59, 89, 67],
}
midterm = DataFrame(data=dic,index=['语文','数学','英语','理综', "政治"])
midterm
final = DataFrame(data=dic2,index=['语文','数学','英语','理综', "政治"])
# 1. 请自由创建final,并将其与midterm相加,求期中期末平均值。
# 思路就是每个学生的每科的期中期末加一起除以2就行了
medin = (midterm + final) / 2
medin
# 2. 假设张三期中考试数学被发现作弊,要记为0分,如何实现?
# 思路是,先根据索引定位到该数学成绩,再重新赋值
# 因为有显式索引,所以,可以用loc按照显式索引取值
midterm.loc['数学', '张三']
# 隐式方式也行
# midterm.iloc[1, 0]
midterm.loc['数学', '张三'] = 0
midterm
# 3. 李四因为举报张三作弊立功,期中考试所有科目加10分,如何实现?
# 思路就是为李四的所有列加10操作就行了
# midterm["李四"] # 这么着取值也行
midterm.iloc[:, 1]
midterm.iloc[:, 1] += 10
midterm
# 4. 后来老师发现期中考试中有一道题出错了,为了安抚学生情绪,给每位学生每个科目都加10分,如何实现?
# 思路就是df中的所有元素值都加10就完了
midterm += 10
midterm
时间序列
时间序列内容有很多,这里我们只讲用到的。
将字符串转为时间序列:
import numpy as np
import pandas as pd
from pandas import DataFrame
dic = {
'time':['2010-10-10','2011-11-20','2020-01-10'],
'temp':[33,31,30]
}
df = DataFrame(data=dic)
df
# 查看time列的类型
df['time'].dtype
# 将time列的数据类型转换成时间序列类型
df['time'] = pd.to_datetime(df['time'])
df
# 将time列作为源数据的行索引
# inplace参数决定是否将变更应用到原数据中
df.set_index('time')
# df.set_index('time',inplace=True)
数据清洗
Python中空值用None表示,类型是NoneType。 而numpy中空值用np.nan表示,类型是float,为什么是float类型,为了运算时保证类型统一,所以这点和Python不太一样。 np.nan的另一个特点是它和任何数进行算术运算都得空。
在pandas中,遇到None的情况,pandas会自动将None强制转为nan。
pandas处理空值操作
方式1:过滤出来空值的行,然后删除空值所在的行
相关方法:df.isnull, df.notnull, df.any, df.all,df.dropna