python数据分析&办公自动化实战(三):数据预处理/数据清洗

#简介#
本篇是数据清洗的一点经验总结,涉及到以下功能:预览、异常值处理、数据类型转换、字符串操作、选取行列、通过定义函数实现规则判断等,依然是代码+注释+总结
任务目标:将开放收入表里的各种数据进行预处理,以满足分析要求。
目标拆解:逢山开路,遇水架桥,直到数据符合可用标准。

#代码展示#
#仅展示思路,代码做了简化

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")
    #注:20年一次更新中,pd.read_excel功能去掉了encoding参数
    df = pd.read_csv(doc)
    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(lambda df:pro(df.始发一级战区),axis=1)
    df[["收入","成本"]].fillna(0)
    df.groupby([["月份","始发一级战区"]]).sum().reset_index()
    df["单均收入"] = df[["收入","单量"]].apply(lambda df:df["收入"]/df["单量"],axis=1)
    df["单公斤收入"] = df[["收入","重量"]].apply(lambda df: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[]某列去重

缺失值处理:
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时会进行报错,此时就需要指定读取列的数据类型。
转换数据类型的方式主要有两种:使用库的函数转换或者通过自定义函数转换

  1. 通过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']])#将年月日进行合并
  1. 通过自定义函数
定义函数法:
def convert(a):
    b = a.replace(r'[^\w\s]+', '')
    return float(b)
   #将列a中的特殊符号去除,然后转换为float浮点数,需要string库支持

快捷方法:利用apply函数等
df["单量"] = df["单量"].str.replace(r'[^\w\s]+', '').astype("int")
df["金额"].apply(lambda x: 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部分

选取行列

读取时加入 usecols="" 参数可以指定读取的列
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范围内的单元格,前为行后为列,只有:表示全选
df.rename(columns={"一级分类":"产品类型","业务类型":"经营指标"},inplace=True)#重命名列

自定义函数规则判断
很简单有效的方法,展示几个例子:

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.列名 设置参数

以上就是本次的分享了,零零散散扯了很多,希望能让大家少走些弯路~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值