很多开发者说自从有了 Python/Pandas,Excel 都不怎么用了, 用它来处理与可视化表格非常快速.
下面我来举几个例子.
1. 删除重复行和空行
我们直接用 dict.fromkeys 的方法把当前的数据转为字典, 默认的值为 None 因为用不到, 也就无所谓了. 然后我们再用 list 直接对结果进行类型转换, 转换为 list.
- In [135]:
- for row in rows4:
- print(row)
- ('name', 'address')
- ('tom li', 'beijing')
- ('tom li', 'beijing')
- ('',)
- ('mary wang', 'shandong')
- ('mary wang', 'shandong')
- ('',)
- ('de8ug', 'guangzhou')
- In [148]:
- dict.fromkeys(rows4)
- Out[148]:
- {('name', 'address'): None,
- ('tom li', 'beijing'): None,
- ('',): None,
- ('mary wang', 'shandong'): None,
- ('de8ug', 'guangzhou'): None}
- In [137]:
- list(dict.fromkeys(rows4))
- Out[137]:
- [('name', 'address'),
- ('tom li', 'beijing'),
- ('',),
- ('mary wang', 'shandong'),
- ('de8ug', 'guangzhou')]
这时候, 重复数据直接去掉了, 注意我们这里的 dict 是 python3 新版本的, 所以顺序没有影响, 如果你还在用 python2 或者 python3.5 以下, 建议升级一下 python 版本.
接下来, 就是空数据的处理了. 观察 ('',) 是个元组, 第一个位置的数据为空字符串, 那么整体长度为 1, 可以直接通过循环来去掉. 这里的循环我们可以用 Python 中的语法糖写法, 直接一行搞定, 最后加个判断只留下长度大于 1, 最后用 list 转换为列表.
- In [179]:
- list(x for x in dict.fromkeys(rows4) if len(x[0])>1)
- Out[179]:
- [('name', 'address'),
- ('tom li', 'beijing'),
- ('mary wang', 'shandong'),
- ('de8ug', 'guangzhou')]
上面的研究搞定了, 直接把研究结果放到函数中解决重复行和空行的问题.
注意这时候我们处理的行数据, 所以就不再按列循环了. 而且, 当前的 sheet 中处理之后, 每一行的内容都会修改位置或删除. 所以我们先用 old_rows = [x for x in sheet.values]取到旧的每一行的数据, 注意这里的 sheet 后直接用 values 取到数据, 而不是 cell 对象. 这里的 old_rows 是个列表, 就可以用刚才的研究直接转为删除重复和空行的数据了.
接下来, 用 sheet.delete_rows(1, sheet.max_row)
删除所有行, 第一个参数表示从第一行开始, 第二个参数为最大行数. 最后, 用循环新的行数据的方式, 把新数据写入当前的 sheet.
- In [189]:
- def handle_duplicate(wb, sheetname):
- """
- 去除重复行, 空行
- 先取出每一行, 清空 sheet, 处理后写回
- """print(f'开始处理工作表:{sheetname}'.center(18,'-'))
- sheet = wb[sheetname]
- old_rows = [x for x in sheet.values]
- print('修改前:', old_rows)
- new_rows = list(x for x in dict.fromkeys(old_rows) if len(x[0])>1)
- print('修改后 -》》', new_rows)
- # 删除所有行
- sheet.delete_rows(1, sheet.max_row)
- # 写入新数据
- for row in new_rows:
- sheet.append(row)
运行测试, 查看结果. 再说一次, 一定记得测试啊! 如果有错误就根据错误提示, 查看代码, 反复调试, 去除 bugs.
- In [190]:
- wb = load_data()
- handle_duplicate(wb, '重复行')
- save_as(wb)
2. 删除空格
删除空格也需要用到字符串的函数, 所以这里还是简单研究一下. 如果我们想去除字符串中间的空格, 可以用 split 默认进行分割, 然后把分割的结果用''.join 方法连接起来就可以了. 注意 join 前是空的字符串. 这里也用不到 strip 去除两端的空格了, 因为 split 分割后只有几个最后的字符串组成的列表.
- In [192]:
- a="a b c"
- In [194]:
- a.strip()
- Out[194]:
- 'a b c'
- In [195]:
- a.split()
- Out[195]:
- ['a', 'b', 'c']
- In [196]:
- ''.join(a.split())
- Out[196]:
- 'abc'
- In [ ]:
研究成功后, 写入函数. 这次命名为 handle_blank.
- In [197]:
- def handle_blank(wb, sheetname):
- """
- 按列循环, 通过参数确认目标
- """print(f'开始处理工作表:{sheetname}'.center(18,'-'))
- sheet = wb[sheetname]
- for col in sheet.iter_cols(): # 不加参数, 循环所有列
- for cell in col:
- print('修改前:', cell.value, end='')
- cell.value = ''.join(cell.value.split())
- print('修改后 -》》',cell.value)
- In [198]:
- handle_blank(wb, '空格')
3. 修改日期和时间格式
有时候, 我们需要对表格中时间相关的单元格进行格式修改, 这里需要用到 Python 中时间模块 datetime, 将需要的格式进行拼接后, 用 strftime 进行转换.
假设这里我们想把之前简单的 1/11 月日格式, 更改为年月日的样式, 中间加上分隔符 / 或 -, 就需要用 "%x" 或 "%Y-%m-%d" 来进行操作了. 注意这里的 % 加字母都是官方定义好的格式而已, 我们用到时候进行拼接, 传给函数就可以了.
具体更多的拼接格式如下:
- In [199]:
- import datetime
- In [209]:
- d=datetime.datetime(2019,1,11)
- In [203]:
- d.strftime("%x")
- Out[203]:
- '01/11/19'
- In [205]:
- d.strftime("%Y-%m-%d")
- Out[205]:
- '2019-01-11'
研究完成后, 我们编写函数.
首先需要用 m, d = cell.value.split('/')把之前简单的日期进行分割, 得到 m, 代表月份和日期, 然后用 datetime 进行转换, 生成时间相关的对象 day, 注意里面的参数是数字, 所以用 int 转换, 最后把 day 进行格式化输出. 编写函数后, 一定记得测试.
- In [218]:
- def handle_time(wb, sheetname):
- """
- 按列循环, 通过参数确认目标
- """print(f'开始处理工作表:{sheetname}'.center(18,'-'))
- sheet = wb[sheetname]
- for col in sheet.iter_cols(max_col=1, min_row=2): # 找到时间的列, 第一列, 从第二行开始
- for cell in col:
- print('修改前:', cell.value, end='')
- m, d = cell.value.split('/')
- day = datetime.datetime(2019, int(m), int(d))
- cell.value = day.strftime("%Y-%m-%d")
- print('修改后 -》》',cell.value)
- In [220]:
- wb = load_data()
- handle_time(wb, '时间')
- save_as(wb)
4. 修复数字和符号
接下来, 处理数字和符号相关的操作. 加入我们之前的价格, 很多是有小数点的, 这时候还想保存两位小数, 并加上人民币符号为前缀. 就需要新的一波研究了.
有小数点, 一是要保证位数, 我们这里要求 2 位, 二是要对多余的位数四舍五入. 可以有以下俩个方式完成, 一个用 Decimal 一个用 round, 两个的区别是 Decimal("0.00")指定位数后, 会自动补 0, 而 round 遇到 0 就自动舍掉了. 而且 round 在四舍五入的计算中, 还有点特殊. 具体可查看官方文档.
我们这里用 Decimal 来完成函数内相关操作. 记得测试啊!
- In [227]:
- from decimal import Decimal
- In [240]:
- a = 3.1
- b=Decimal(a).quantize(Decimal("0.00"))
- print(b)
- 3.10
- In [244]:
- round(a,2) # 位数自动省略 0
- Out[244]:
- 3.1
- In [247]:
- def handle_num(wb, sheetname):
- """
- 按列循环, 通过参数确认目标
- """print(f'开始处理工作表:{sheetname}'.center(18,'-'))
- sheet = wb[sheetname]
- for col in sheet.iter_cols(min_col=3, max_col=3, min_row=2): # 找到时间的列, 第一列, 从第二行开始
- for cell in col:
- print('修改前:', cell.value, end='')
- # cell.value = round(float(cell.value), 3)
- cell.value = '¥' + str(Decimal(cell.value).quantize(Decimal("0.00")))
- print('修改后 -》》',cell.value)
- In [249]:
- wb = load_data()
- handle_num(wb, '数字符号')
- save_as(wb)
9 元微专栏, 带你《用 Python 玩转 Excel》
还有群答疑服务哦↓
来源: http://blog.51cto.com/51ctoblog/2438164