#简介#
本篇是数据清洗的一点经验总结,涉及到以下功能:预览、异常值处理、数据类型转换、字符串操作、选取行列、通过定义函数实现规则判断等,依然是代码+注释+总结。
任务目标:将开放收入表里的各种数据进行预处理,以满足分析要求。
目标拆解:逢山开路,遇水架桥,直到数据符合可用标准。
#代码展示#
#仅展示思路,代码做了简化
import os,sys
import numpy as np
import pandas as pd
import openpyxl
import csv
import xlwt
#遍历文件夹,输出文件夹下所有的文件路径及名称
def walk(path):
if not os.path.exists(path):
return -1
for root,dirs,names in os.walk(path):
for filename in names:
if os.path.splitext(filename)[1]=='.csv':
docs=os.path.join(root,filename)
print(docs)
csvlist.append(docs)
#定义函数实现规则判断
def pro(a):
if "内蒙古" in a or "山西" in a:
return "晋蒙战区"
elif a in list1:
return a
else:
return "其他"
csvlist=[]
cur_path=os.getcwd()
walk(cur_path)
list1=["北京战区","河北战区","山东战区","天津战区","晋蒙战区","其他"]
for doc in csvlist:
df=pd.read_csv(doc,encoding="gbk")
df=df[df["自营外单"].isin([0])][["月份","客户名称","始发一级战区","商家渠道名称","自营外单","外单内部B商家","单量","重量","收入","成本"]]
df.head(10)
df.dtypes()
df.info()
df["商家渠道名称"]=df["商家渠道名称"].astype(str)
df=df[~df["商家渠道名称"].str.contains("冷链|生鲜|医药")]
df["归属战区"]=df.apply(lambdadf:pro(df.始发一级战区),axis=1)
df[["收入","成本"]].fillna(0)
df.groupby([["月份","始发一级战区"]]).sum().reset_index()
df["单均收入"]=df[["收入","单量"]].apply(lambdadf:df["收入"]/df["单量"],axis=1)
df["单公斤收入"]=df[["收入","重量"]].apply(lambdadf:df["收入"]/df["重量"],axis=1)
columns=["月份","始发一级战区","单量","重量","收入","单均收入","单公斤收入"]
df.to_csv("汇总数据.csv",columns=columns,encoding="gbk")
#代码拆解#
遍历文件夹、读取csv部分与上一篇相同,此处不做赘述。
数据预览
df.head(10) #预览前10行数据
df.dtypes() #显示每个字段的数据类型
df.info() #显示每个字段的信息,包含位数、数据类型等
df.shape() #显示数据文件的行列形状;另,numpy创建数组时支持reshape()改变行列结构
异常值处理
重复值去重,缺失值填充,偏离值调整
重复值去重:
df.drop_duplicates(subset=[],keep='first',inplace=False)
#subset参数为选定的列,keep参数决定保留的值,inplace决定是否替代
缺失值处理:
df[].isnull()#判断是否为缺失值,输出一列True or False布尔型
df.dropna()#去除缺失值,此时去除的是数据表中的整行,可通过调整参数实现其他功能
df.dropna(how="all",axis=1)#去除所有值为空的列,axis参数决定行列
df.fillna(0)#以0填充缺失值
关于fillna()函数的各参数,@Denver_Liao 的这篇文章写的很详细:https://blog.csdn.net/weixin_39549734/article/details/81221276
如何处理缺失值更合理的问题需要具体情况具体分析;偏离值的调整涉及到更深层次的统计学知识,限于所知不做讨论;
数据类型转换
对行列的值进行操作时,会对列的数据类型有要求。比如如果某一列有多种数据类型,pandas读取csv时会进行报错,此时就需要指定读取列的数据类型。
转换数据类型的方式主要有两种:使用库的函数转换或者通过自定义函数转换
通过astype函数和pandas自带函数
df.dtypes()#查看字段数据类型
df[].astype(str)#转换为字符串
df[].astype(float)#转换为浮点数(要求为全数字的字符串,不能包含特殊字符)
df[].astype(int)#转换为整数
pd.to_numeric(df["收入"],errors="coerce").fillna(0)#转换为数字型,无法识别字符串;errors参数可选填"coerce"(填充为空值NaN)、"ignore"(忽略,输出原值)或"raise"(报错)
pd.to_datetime(df[['Month','Day','Year']])#将年月日进行合并
通过自定义函数
定义函数法:
def convert(a):
b=a.replace(r'[^\w\s]+','')
returnfloat(b)#将列a中的特殊符号去除,然后转换为float浮点数,需要string库支持
快捷方法:利用apply函数等
df["单量"]=df["单量"].str.replace(r'[^\w\s]+','').astype("int")
df["金额"].apply(lambdax:x.replace("¥","")).astype("float64")
关于数据类型转换,这篇博客写的不错:https://www.cnblogs.com/onemorepoint/p/9404753.html
本文未对时间日期类数据类型的转换进行讨论,日后有机会再补一篇
字符串操作
对字符串的拆分合并、调整替换等
val.split(',')对val按,拆分;
pieces = [x.strip() for x in val.split(',')]split和strip用于清除空格;
字符串替换见数据类型转换replace部分
选取行列
df=df[df["自营外单"].isin([0])][["月份","客户名称","收入","成本"]]
#后半段为筛选条件,选取"自营外单"字段值为0、特定列名的部分;将其赋值给df实现替换;
#bool判断条件部分暂时只能写一个,如果写两个,如df[df["自营外单"].isin([0])][df["外单内部B商家"].isin([0])]会报逻辑错误
df[].isin(["a","b"])#函数用于选择特定列值中包含a或者b的行
df=df[~df["商家渠道名称"].str.contains("冷链|生鲜|医药")]#通过str.contains()函数筛选包含关键字字符串的行,“或”以“|”符号表示;
df=df[df["自营外单"]=="0"]#以布尔值进行判断;
df.iloc[[0:5],[0:5]]#选取6×6范围内的单元格,前为行后为列,只有:表示全选
自定义函数规则判断
很简单有效的方法,展示几个例子:
list1=["北京战区","河北战区","山东战区","天津战区","晋蒙战区","其他"]
def pro(a):
if "内蒙古" in a or "山西" in a:
return "晋蒙战区"
elif a in list1:
return a
else:
return "其他"
#用于规避0/0的bug:
def div(a,b):
if b==0 or a==0:
return 0
else:
return a/b
自定义函数实现规则是个很有效的手段,应用起来也很简单方便,通过apply&lambda函数就可以实现;如df["归属战区"] = df.apply(lambda df:pro(df.始发一级战区),axis=1),如果参数为某一列,需要以 df.列名 设置参数
以上就是本次的分享了,零零散散扯了很多,希望能让大家少走些弯路~
CSDN同作者,博文连接https://blog.csdn.net/z1272578750/article/details/104008047