2-python数据分析-基于pandas的数据清洗、DataFrame的级联与合并操作
基于pandas的数据清洗
处理丢失数据
- 有两种丢失数据:
- None
- np.nan(NaN)
- 两种丢失数据的区别
- None 是对象类型
- np.nan 是浮点类型
type(None) # NoneType 对象类型 type(np.nan) # float 浮点类型
为什么在数据分析中需要用到的是浮点类型的空而不是对象类型?
- 数据分析中会常常使用某些形式的运算来处理原始数据,如果原数数据中的空值为NAN的形式,则不会干扰或者中断运算。
- NAN可以参与运算的
- None是不可以参与运算
在pandas中如果遇到了None形式的空值则pandas会将其强转成NAN的形式。pandas中,None=nan
pandas处理空值操作
- 对空值进行删除
- 删除我们一般只删除行
- 对空值进行填充
主要用的技术点
- isnull
- notnull
- any
- all
- dropna
- fillna
首先创建一组带有空值的数据
df = DataFrame(data=np.random.randint(0,100,size=(7,5))) df.iloc[2,3] = None df.iloc[4,2] = np.nan df.iloc[5,4]= None df
过滤方式1:对空值进行过滤(删除空所在的行数据)
技术点
- isnull,any
- notnull,all
df.isnull()
# 哪些行中有空值 # any(axis=1)检测哪些行中存有空值 df.isnull().any(axis=1) # any会作用isnull返回结果的每一行 # True对应的行就是存有缺失数据的行 0 False 1 False 2 True 3 False 4 True 5 True 6 False dtype: bool
df.notnull()
df.notnull().all(axis=1)
0 True
1 True
2 False
3 True
4 False
5 False
6 True
dtype: bool
对空值进行过滤
# 将布尔值作为源数据的行索引,只保留True对应的行数据 # 用notnull过滤 df.loc[df.notnull().all(axis=1)] # 直接保留非Nan的数据
# 用istnull过滤 df.loc[df.isnull().any(axis=1)] # 保留是Nan的数据,不是想要的结果
# 先得到是Nan的索引然后,在所有数据中将他们删除 nan_index = df.loc[df.isnull().any(axis=1)].index df.drop(labels=nan_index, axis=0)
过滤方式2:dropna:可以直接将缺失的行或者列进行删除
df.dropna(axis=0) # 只要是drop打头,axis所代表的意思一样
对缺失值进行覆盖
-
fillna
# 使用指定值将源数据中所有的空值进行填充 # 通常我们不会这么干,会填充一个有意义的值 df.fillna(value=999)
# 使用空的近邻值进行填充 # method=ffill向前填充,bfill向后填充 df.fillna(axis=0, method='ffill')
什么时候用dropna,什么时候用fillna
- 尽量使用dropna,如果删除成本比较高,则使用fillna
使用空值对应列的均值对空值进行填充
for col in df.columns: # 检测哪些列中存有空值 # df[col].isnull()得到所在列的布尔值,布尔值相加False为0,True为1 # 若相加后的结果大于0则其中存在True,有空值 if df[col].isnull().sum() > 0: mean_value = df[col].mean() df[col] = df[col].fillna(value=mean_value)
面试题
-
数据说明:
- 数据是1个冷库的温度数据,1-7对应7个温度采集设备,1分钟采集一次。
-
数据处理目标:
- 用1-4对应的4个必须设备,通过建立冷库的温度场关系模型,预估出5-7对应的数据。
- 最后每个冷库中仅需放置4个设备,取代放置7个设备。
- f(1-4) --> y(5-7)
-
数据处理过程:
- 1、原始数据中有丢帧现象,需要做预处理;
- 2、matplotlib 绘图;
- 3、建立逻辑回归模型。
-
无标准答案,按个人理解操作即可,请把自己的操作过程以文字形式简单描述一下,谢谢配合。
-
测试数据为testData.xlsx
df = pd.read_excel('./testData.xlsx')
df.drop(labels=['none', 'none1']) # 删掉没用的俩列
df.shape # (1060, 8) # 删除空对应的行数据 df.dropna(axis=0).shape # (927, 8) # 对空值进行填充,这样保证空值被填充 df.fillna(method='ffill',axio=0).fillna(method='bfill',axis=0)
处理重复数据
df = DataFrame(data=np.random.randint(0,100,size=(8,6))) df.iloc[1] = [1,1,1,1,1,1] df.iloc[3] = [1,1,1,1,1,1] df.iloc[5] = [1,1,1,1,1,1]
#检测哪些行存有重复的数据 df.duplicated(keep='first') # 保留一行 0 False 1 False 2 False 3 True 4 False 5 True 6 False 7 False dtype: bool # 用检查到的布尔值取反做索引取值,得到没有重复的数据 df.loc[~df.duplicated(keep='first')]
一步到位删除重复值
df.drop_duplicates(keep='first') # first是保留第一行重复值
df.drop_duplicates(keep='last') # last是保留最后一行重复值
df.drop_duplicates(keep=False) # False是删除全部重复值
处理异常数据(不符合常规的数据)
- 自定义一个1000行3列(A,B,C)取值范围为0-1的数据源,然后将C列中的值大于其两倍标准差的异常值进行清洗
df = DataFrame(data=np.random.random(size=(1000,3)),columns=['A','B','C']) df.head()
# 制定判定异常值的条件 twice_std = df['C'].std() * 2 # 0.5809877730044463 df.loc[~(df['C'] > twice_std)].head()
级联操作
- pd.concat, pd.append
pandas使用pd.concat函数进行级联操作,与numpy中的np.concatenate函数类似,只是多了一些参数
匹配级联
行列索引都一致的级联叫做匹配级联
df1 = pd.DataFrame(data=np.random.randint(0,100,size=(5,3)),columns=['A','B','C']) df2 = pd.DataFrame(data=np.random.randint(0,100,size=(5,3)),columns=['A','D','C']) pd.concat((df1,df1), axis=1) # axis=0 轴向 列与列级联 , axis=1 横向级联 行和行级联
不匹配级联
- 不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致
- 有2种连接方式:
- 外连接 outer:补NaN(默认模式),如果想要保留数据的完整性必须使用outer(外连接)
- 内连接 innter:只连接匹配的项
pd.concat((df1,df2), axis=1) # 横向级联,没有毛病
# concat()中join参数默认是 outer, 会把不能匹配的补Nan pd.concat((df1,df2),axis=0)
# inner 可以把能匹配的匹配,不能匹配的直接不要 pd.concat((df1,df2), axis=0, join='inner')
append函数的使用
append函数只能轴向级联
df1.append(df1)
df1.append(df1)
合并操作
-
merge与concat的区别在于,merge需要依据某一共同列来进行合并
-
使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。
-
注意每一列元素的顺序不要求一致
一对一合并
df1 = DataFrame({'employee':['Bob','Jake','Lisa'], 'group':['Accounting','Engineering','Engineering'], })
df2 = DataFrame({'employee':['Lisa','Bob','Jake'], 'hire_date':[2004,2008,2012], })
pd.merge(df1, df2, on='employee') # 参数1:左表,参数2:右边,参数3:on合并条件
一对多合并
df3 = DataFrame({ 'employee':['Lisa','Jake'], 'group':['Accounting','Engineering'], 'hire_date':[2004,2016]})
df4 = DataFrame({'group':['Accounting','Engineering','Engineering'], 'supervisor':['Carly','Guido','Steve'] })
pd.merge(df3, df4) # on如果不写,默认情况下使用两表中共有的列作为合并条件
多对多合并
df5 = DataFrame({'employee':['Bob','Jake','Lisa'], 'group':['Accounting','Engineering','Engineering']})
df6 = DataFrame({'group':['Engineering','Engineering','HR'], 'supervisor':['Carly','Guido','Steve'] })
pd.merge(df5, df6) # 不指定的话how默认是inner 只将能匹配的合并
# 内合并与外合并:outer取并集 inner取交集 pd.merge(df5, df6, how='inner') # inner是只将能匹配的合并
pd.merge(df5, df6, how='outer') # outer是能匹配不能匹配的都合并
pd.merge(df5, df6, how='right') # right右合并 保留右表数据
pd.merge(df5, df6, how='left') # left左合并 保留左表数据
key的规范化(两张表没有可进行连接的列)
- 当两张表没有可进行连接的列时,可使用left_on和right_on手动指定merge中左右两边的哪一列列作为连接的列
df7 = DataFrame({'employee':['Bobs','Linda','Bill'], 'group':['Accounting','Product','Marketing'], 'hire_date':[1998,2017,2018]})
df8 = DataFrame({'name':['Lisa','Bobs','Bill'], 'hire_dates':[1998,2016,2007]})
pd.merge(df7, df8, left_on='employee', right_on='name')