代码地址如下:
http://www.demodashi.com/demo/11650.html

看完本篇需要:

10min

作业练习需要:

0.5h~3h(依练习者对python熟悉程度而定)

看完本篇可以学到:

1、用xlrd模块读取Excel文件中的数据

2、用xlsxwriter模块向Excel文件写入数据并保存

3、用time和datetime模块将字符串转换成时间类,并进行时间的比较

本篇目录

  1. 作业需求
  2. 整体思路
  3. 详细实现步骤

    3.1. 读取表格数据

    3.2. 将行数据list按时间先后升序排序

    3.3. 维护一个map并新增数据到行数据

    3.4. 将修改后的行数据list写入Excel表格并保存为xslx格式
  4. 完整代码
  5. 结果展示
  6. 参考
  7. 源码及作业练习文件

作业需求



一个朋友在某运动品牌公司上班,老板给他布置了一个处理客户订单数据的任务。要求是根据订单时间和客户id判断生成四个新的数据:

1、记录该客户是第几次光顾

2、上一次的日期时间是什么时候

3、与上次订单的间隔时间

4、这是一个existing客户还是一个new客户(见定义)

文件说明:

1、第一列是订单日期和时间(乱序)

2、第二列是客户的id

3、第三列不需要使用

相关定义如下:

1、existing:此次下单日期时间与上次日期时间的距离在N天以内,精确到时间(时分秒)

2、new:即超过N天

整体思路

1、读取表格的行数据存储成list,并按照时间列的升序排序。

2、维护一个map(在python里是字典dict),每个用户 id 作为key,一个二元组(第几次下单,上一次的日期时间)作为value。

3、遍历表格行数据的list。判断客户 id 是否已经存在于map中,若首次出现,则置该客户 id 在map中的value为[1,'首次下单'],对应行数据新增的4个数据为[1,'首次下单',该次日期时间与上次日期时间差,'new']。若已经存在,则更新map中对应的value为[原次数+1,该次日期时间],对应行数据新增的4个数据为[原次数+1,上次日期时间,间隔时间,new/existing取决于间隔时间与预设N]。

4、将修改过后的行数据list写入到Excel工作簿并保存。

详细实现步骤

读取表格数据

我们可以用xlrd模块对Excel文件进行读取,以便进一步分析处理数据。示例代码如下:

wb=xlrd.open_workbook('../excel/buyer_day.xlsx')# 打开工作簿,参数为文件地址
sheet=wb.sheets()[0]# 获取工作簿中的第一张工作表
for i in range(100):
if i==0:# 跳过首行的标题
continue
time_str= sheet.row_values(i)[0]# 读取该工作表第i行的第一个单元格数据
print time_str

以上代码成功输出前100行的日期则说明已经成功读取到数据。输出结果如下:



可以看到,这里输出的日期前后有空格,而且最后的时间有小数点,这不便于我们转换成时间类,所以要进行一些处理。用strip函数去掉前后空格,用切片切掉末尾的".0"。将前面的第4行代码更改为:

time_str= sheet.row_values(i)[0].strip()[:-2]

既然读取文件没有问题,进一步浏览整个文件发现存在多余的空行和重复的标题行(如图3),在读取和转存中可以用正则匹配过滤掉这些行。

另外,可以从图2看出时间是乱序的,这不利于后续的逻辑实现,所以将读取的行数据转存到list中,以便进行排序。

list_row=[]# 将行数据存储到list中,便于排序

wb=xlrd.open_workbook('../excel/buyer_day.xlsx')
sheet=wb.sheets()[0]
nrows=sheet.nrows# 工作表的行数 for i in range(nrows):
#用正则匹配过滤掉空行和标题行
str_date=sheet.row_values(i)[0].strip()[:-2]
if re.match('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}', str_date)!=None:
list_row.append(sheet.row_values(i))# 插入到list

将行数据list按时间先后升序排序

这里用到sorted函数,可以对list进行排序。示例代码如下,key指定的函数会作用于list中的每一个元素,其返回值必须为可比较的变量。

list_row=sorted(list_row,key=self.getDatetime)# 将list_row排序,排序是对key进行比较,key指定的函数会作用于list中的每一个元素

行数据的第一格的日期时间字符串不便于直接比较,可以转换成datetime对象,以便直接比较。具体做法是将读取到的日期时间字符串用time模块的strptime转换成时间类,再用datetime模块转换成datetime类。

timeArray=time.strptime(time_str, "%Y-%m-%d %H:%M:%S")# 第二个参数是对应字符串的格式
Y,m,d,H,M,S=timeArray[0:6]
dt=datetime.datetime(Y,m,d,H,M,S)# 转换成datetime对象,可以直接进行比较

datetime之间的比较可以直接用>,<,=符号,而且可以直接相减求间隔时间,间隔时间的类型是timedelta,也可以直接比较。示例代码如下:

dt1=datetime.datetime(2017,5,2,13,23,01)
dt2=datetime.datetime(2017,3,2,12,00,00)
dt3=datetime.datetime(2017,6,19)
dt4=datetime.datetime(2017,5,21) dis1=dt1-dt2# 相减返回的类型是timedelta
dis2=dt3-dt4
print dis1
print dis2
print dis1>dis2
print dis1<datetime.timedelta(days=30)

示例输出:

维护一个map并新增数据到行数据

map={客户 id :[第几次下单,上次日期时间]}

搞清楚了日期时间的比较和时间间隔的比较,我们就可以按之前整体思路的2、3步的逻辑进行map的维护更新和list中行数据的修改了。逻辑之前已经提过了,细节见代码注释。

for row_value in list_rowValues:

    dt_current=self.getDatetime(row_value)# 订单日期时间的datetime类型
mber_id=row_value[1].strip()# 客户id # 维护一个dict,用一个dict保存,客户id作为key,[当前第几次,上次订单日期时间]作为value
# 并且依此写入新数据到list的行数据中
if mber_id in self.dict_mid_data: # 如果存在这个key,说明该顾客之前有订单记录,更新dict,同时插入新数据到row_value self.dict_mid_data[mber_id][0]+=1# 更新下单次数+1
row_value[3]=self.dict_mid_data[mber_id][0]# 插入下单次数 dt_last=self.dict_mid_data[mber_id][1]
row_value[4]=dt_last.strftime("%Y-%m-%d %H:%M:%S")# 插入上次订单日期时间 dis=abs(dt_current-dt_last)# 时间差的绝对值
row_value[5]=str(dis)# 插入与上次订单时间的间隔时间差 # 插入usertype
if dis <= datetime.timedelta(days=N):# 如果间隔在N天内
row_value[6]='existing'
else:
row_value[6]='new' if dt_current>dt_last:# 如果当前时间更近,更新dict里的上次日期时间
self.dict_mid_data[mber_id][1]=dt_current
else:# 不存在这个key,直接保存初始值
self.dict_mid_data[mber_id]=[1,dt_current]
row_value[3]=1 # 当前是第几次订单
row_value[4]=u'首次下单' # 当前日期时间
row_value[5]='-' # 与上次订单间隔时间
row_value[6]='new' # usertype

将修改后的行数据list写入Excel表格并保存为xslx格式

xlrd模块读取的工作簿是不能修改的,也就是只能读,不能写。想要新增数据进原来的工作簿,要用到xlsxwriter模块生成新的Excel工作簿,然后把修改后的list写入到一张新的工作表中,再保存到原路径(或者新的路径),以达到修改的目的。

wb=xlsxwriter.Workbook('../excel/buyer_day_new.xlsx')
sheet=wb.add_worksheet('sheet1')# 新增一张工作表sheet1
# 写入标题
sheet.write(0,0,'order_dt')# 三个参数分别是:单元格横坐标,纵坐标,写入内容
sheet.write(0,1,'member_id')
sheet.write(0,2,'member_type')
sheet.write(0,3,'times')
sheet.write(0,4,'last_order_dt')
sheet.write(0,5,'interval')
sheet.write(0,6,'user_type') # 写入处理后的数据
len_list=len(list_rowValues)
for i in range(len_list):
row_value=list_rowValues[i]
len_row=len(row_value)
for j in range(len_row):
sheet.write(i+1,j,row_value[j]) wb.close()

完整代码

# -*- coding:utf-8 -*-
'''
Created on 2017年5月31日 @author: wycheng
'''
import xlrd
import xlsxwriter
import time,datetime
import re class BuyerManager:
dict_mid_data={}# 维护的一个 map{客户id:[第几次下单,上次日期时间]} # 获取对应行数据的订单时间
def getDatetime(self,row_value):
time_str=row_value[0].strip()[:-2]
timeArray=time.strptime(time_str, "%Y-%m-%d %H:%M:%S")
Y,m,d,H,M,S=timeArray[0:6] dt_current=datetime.datetime(Y,m,d,H,M,S)# 转换成datetime对象,可以直接进行比较
return dt_current # 将所有工作表的行按照订单日期升序排序
def getList_sorted(self,list_xl):# list_xl: Excel文件的地址list list_row=[]# 将行数据存储到list中,便于排序 for exl in list_xl:
print u'正在打开文件 '+exl
wb=xlrd.open_workbook(exl)
sheet=wb.sheets()[0]
nrows=sheet.nrows# 工作表的行数
print u'正在插入文件 '+exl+u'的row_value'
for i in range(nrows):
#用正则匹配过滤掉空行和标题行
str_date=sheet.row_values(i)[0].strip()[:-2]
if re.match('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}', str_date)!=None:
list_row.append(sheet.row_values(i)) print u'正在排序……'
list_row=sorted(list_row,key=self.getDatetime)# 将list_row排序,排序是对key进行比较,key指定的函数会作用于list中的每一个元素
return list_row def process(self,list_rowValues,N):# list_rowValues: 存放所有row_value的list N: 间隔N天内是existing
# 遍历每一行
line=1
for row_value in list_rowValues:
print u'正在处理第'+str(line)+u'行'
line+=1 dt_current=self.getDatetime(row_value)# 订单日期时间的datetime类型
mber_id=row_value[1].strip()# 客户id # 维护一个dict,用一个dict保存,客户id作为key,[当前第几次,上次订单日期时间]作为value
# 并且依此写入新数据到EXcel
if mber_id in self.dict_mid_data: # 如果存在这个key,说明该顾客之前有订单记录,更新dict,同时插入新数据到row_value self.dict_mid_data[mber_id][0]+=1# 更新下单次数+1
row_value[3]=self.dict_mid_data[mber_id][0]# 插入下单次数 dt_last=self.dict_mid_data[mber_id][1]
row_value[4]=dt_last.strftime("%Y-%m-%d %H:%M:%S")# 插入上次订单日期时间 dis=abs(dt_current-dt_last)# 时间差的绝对值
row_value[5]=str(dis)# 插入与上次订单时间的间隔时间差 # 插入usertype
if dis <= datetime.timedelta(days=N):# 如果间隔在N天内
row_value[6]='existing'
else:
row_value[6]='new' if dt_current>dt_last:# 如果当前时间更近,更新dict里的上次日期时间
self.dict_mid_data[mber_id][1]=dt_current
else:# 不存在这个key,直接保存初始值
self.dict_mid_data[mber_id]=[1,dt_current]
row_value[3]=1 # 当前是第几次订单
row_value[4]=u'首次下单' # 当前日期时间
row_value[5]='-' # 与上次订单间隔时间
row_value[6]='new' # usertype return list_rowValues # 写入Excel并保存
def write_t_xl(self,list_rowValues,xl_addr):
wb=xlsxwriter.Workbook(xl_addr)
sheet=wb.add_worksheet('sheet1')
# 写入标题
sheet.write(0,0,'order_dt')
sheet.write(0,1,'member_id')
sheet.write(0,2,'member_type')
sheet.write(0,3,'times')
sheet.write(0,4,'last_order_dt')
sheet.write(0,5,'interval')
sheet.write(0,6,'user_type') # 写入处理后的数据
len_list=len(list_rowValues)
for i in range(len_list):
print u'正在写入第'+str(i+1)+u'行……'
row_value=list_rowValues[i]
len_row=len(row_value)
for j in range(len_row):
sheet.write(i+1,j,row_value[j]) wb.close()
print u'写入完毕,excel文件已生成!' l=['../excel/buyer_day.xlsx']#需要输入处理的文件路径list,即可以输入多个文件进行处理
buyerManager=BuyerManager()
list_rowValues=buyerManager.getList_sorted(l)
list_rowValues_new=buyerManager.process(list_rowValues, 100)
buyerManager.write_t_xl(list_rowValues, '../excel/buyer_day_new.xlsx')

结果展示

源码截图

其中附带的Excel数据文件

参考

python高手之路python处理excel文件(方法汇总)

python模块之XlsxWriter

python基础 实战作业 ---Excel基本读写与数据处理

代码地址如下:
http://www.demodashi.com/demo/11650.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

python基础 实战作业 ---Excel基本读写与数据处理的更多相关文章

  1. python基础实战之猜年龄游戏

    目录 一.Python基础实战之猜年龄游戏 给定年龄,用户可以猜三次年龄 年龄猜对,让用户选择两次奖励 用户选择两次奖励后可以退出 age = 18 # 答案 count = 0 # 游戏次数控制 p ...

  2. 001 python基础实战

    报名了阿里大学的AI,一直没有学习,今天开始正式学习. 今天是第一节,Python的基础编程实战,里面包含两个示例. 一:任务实现文件的批量重命名. 1.创建一个目录 2.程序 #!/usr/bin/ ...

  3. Python-Day3 Python基础进阶之集和/文件读写/函数

    一.集和 集合是一个无序的,不重复的数据组合,它的主要作用如下: 去重,把一个列表变成集合,就自动去重了 关系测试,测试两组数据之前的交集.差集.并集等关系 1.创建集合 >>> s ...

  4. Python基础学习七 Excel操作

    python操作excel,python操作excel使用xlrd.xlwt和xlutils模块, xlrd模块是读取excel的,xlwt模块是写excel的,xlutils是用来修改excel的. ...

  5. python基础:day3作业

    修改haproxy配置文件 基本功能:1.获取记录2.添加记录3.删除记录 代码结构:三个函数一个主函数 知识点:1.python简单数据结构的使用:列表.字典等 2.python两个模块的使用:os ...

  6. python基础day2作业:购物车

    #功能:1.可注册账号2.登录买家账号3.可查询编辑购物车里商品4.可以余额充值5.可提示余额不足6.购物车结算 #使用:1.第一次使用先注册账号填写账号金额2.账号金额信息保存在buyer_acco ...

  7. 我的Python成长之路---第一天---Python基础(作业2:三级菜单)---2015年12月26日(雾霾)

    作业二:三级菜单 三级菜单 可一次进入各个子菜单 思路: 这个题看似不难,难点在于三层循环的嵌套,我的思路就是通过flag的真假来控制每一层的循环的,简单来说就是就是通过给每一层循环一个单独的布尔变量 ...

  8. 我的Python成长之路---第一天---Python基础(作业1:登录验证)---2015年12月26日(雾霾)

    作业一:编写登录接口 输入用户名密码 认证成功系那是欢迎信息 输错三次后锁定 思路: 1.参考模型,这个作业我参考了linux的登录认证流程以及结合网上银行支付宝等锁定规则 1)认证流程参考的是Lin ...

  9. python基础之作业1---用户登录

    作业:编写登陆接口 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定 import sys, os, getpass os.system('clear')i = 0while i < 3: ...

随机推荐

  1. 清理tomcat缓存

    解决方案:删除work目录的内容,注意不能删除work目录,不然会出现404错误 rm -rf /usr/local/tomcat/work/*

  2. Django中遇到的mysql问题

    最近在用Django写个网站,连接mysql的时候出现了几个问题,总结一下 写好setting.py和models.py后,syncdb都没什么问题,在测试后台发表文章的时候就出错了,本来是测试mar ...

  3. 将csv格式的数据文件导入/导出数据库+添加新的字段

    最近一直忙于实验室的事情,没有好好更新博客,在抓包的过程中,遇到了很多问题. 因为我常用Wireshark将抓包信息导出为csv文件,这里简单mark一下将csv文件导入/导出到数据库的2种方法: 一 ...

  4. 索引(Index)

    无索引的表就是一个无序的行集.比如下面的人员表中有一些数据: 这个表上没有索引,因此如果我们查找年龄等于17的人员时,必须查看表中的每一行,看它是否与所需的值匹配.这是一个全表扫描,很慢,如果表中只有 ...

  5. JVM的参数配置

    JVM管理的内存叫堆.在32Bit操作系统上有1.5G-2G的限制,而64Bit的就没有. JVM初始分配的内存由-Xms指定,默认是物理内存的1/64但小于1G. JVM最大分配的内存由-Xmx指定 ...

  6. [BZOJ 1912] patrol 巡逻

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1912 Algorithm: K=0:res=(n-1)*2   每条边恰好走2遍 K=1 ...

  7. Modernizr使用指南(转)

    HTML5, CSS3以及相关技术(例如canvas和web sockets)带来了非常有用的特性,可以让我们的web程序提升一个新的level.这些新技术允许我们只用HTML,CSS和JavaScr ...

  8. oracle--v$lock type字段详解

    Name Description AD ASM Disk AU Lock AF Advisor Framework AG Analytic Workspace Generation AK GES De ...

  9. 谁说 JavaScript 很简单了?

    转载请注明出处,保留原文链接以及作者信息 本文介绍了 JavaScript 初学者应该知道的一些技巧和陷阱.如果你是老司机,就当做回顾了,哪里有写的不好的地方欢迎指出. 1. 你是否尝试过对一个数字数 ...

  10. 事务的实现就是利用数据库锁(行锁,表锁等),且db上锁,都是在操作之前上锁

    悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据 ...