正则表达式是字符串处理必备的科目,也是结构化数据变成结构化数据的一个关键环节,还有就是爬虫中非常重要的一步,所以先从一个简单的大家感兴趣的日常工作的切口,入门一下正则表达式。
有交易员朋友提出想整理一下成交数据,很多交易员收盘会获得一些中介粘贴的表,但是不同的中介给的格式有所微妙的差异,所以需要手动整理一下,如果能有每一天保存下来的数据,就可以回溯成交啦。
候要感谢现券汪和其中不辞辛苦传数据一位群友,一位交易员提供的需求哈~
我们首先要看一下数据格式是什么样的:
惯例声明,这次不用声明wind的接口了。utf-8是一定的,如果大家比较费解,可以百度utf-8与gbk
# -*- coding: utf-8 -*-import pandas as pdimport reimport numpy as np
读取群里面发的一天的中介的文件。file_obj是读取文件的一个指针,后面的.readlines()是调用分行读取的方法,然后要关闭文件指针.close()
file_obj = open('2019年09月02日周一.txt')lines = file_obj.readlines()file_obj.close()
正则表达式书写:分别是期限、债券简称、债券代码、评级、成交价格的正则表达式。我分别解释一下正则表达式的逻辑,关于正则表达式的具体含义可以搜索Python 正则表达式 | 菜鸟教程和在线正则表达式测试
pet_term = '[\.\d]+[YMD]'pat_name = '[\d\w]+[\u4e00-\u9fa5]+[\d\w]+'pet_code = '\d{6}[A-Z0-9]*'pat_rating = '[A]*AA[+-]*'pet_price = '\d+\.\d+'pet_xingquan = '\u884c\u6743'
1. 期限:[\.\d]是匹配任意包含有"."和各类数字的字符,+意思是前面方括号中的变量可以任意重复多次(但是至少要出现一次),[YMD]意思是只要包含方括号中Y,M,D中任意一个就可以,因为期限数据必然含有这三个字母加上数字的组合。
2. 简称:三个部分,[\d\w]是意味着数字,[\u4e00-\u9fa5]意味着是任意汉字,这个就是汉字在unicode编码中的数位,所以我构成了 数字+汉字+英文与数字的这种债券简称结构,比如17中铝MTN002
3. 代码:代码基本上就是六位以上的纯数字或者加上.sh,.ib,.sz等,利率债是六位,190210,信用债多一些,比如011901659,所以正则表达式的含义就是在至少满足六位数字的前提下,后面会有任意位数的字母或者数字,其实[0~9]的含义等于[\d].
4. 评级:评级至少会有AA,所以在前面加一个可选的[A],*意味着可以有任意一个前面的字符,包括0,但是+至少是1。后面是可选的+或者是-,意味着某些债既可以是AA-也开始是AA+
5. 价格:有小数点的小数就可以,比如成交价格3.45,不过这部分会和第一部分的1.68Y相冲突,我还没想好正则表达式改怎么剔除,所以选择在程序里面进行剔除。
6.是否行权:直接与这两个字符进行匹配,'\u884c\u6743',这两个字符分别代表“行”和“权”两个数字的编码,具体某个汉字的unicode是什么可以参考搜索:Unicode编码转换 - 站长工具
生成一个空的dict字典进行数据的保存。
data_series ={'剩余期限':[], '简称':[], '代码':[], '评级':[], '成交价':[], '是否行权':[]}
开始对每一行进行循环和字符串匹配,结果存入data_series
# 对lines的每一行进行循环for line in lines: line_spt = line.split() # 如果对某一行line的根据空格切分后,单位少于3个,就不进行运算,进行下一步循环 if len(line_spt) < 3: continue # 利用正则表达式的条件,筛选出满足正则表达式条件的数据 idata = re.findall(pet_term, line) # 如果没有匹配到,则返回的是空list,这样将NaN赋值给相应的位置 if len(idata) == 0: data_series['剩余期限'].append(np.nan) else: data_series['剩余期限'].append(idata[0]) idata = re.findall(pat_name, line) if len(idata) == 0: data_series['简称'].append(np.nan) else: data_series['简称'].append(idata[0]) idata = re.findall(pet_code, line) if len(idata) == 0: data_series['代码'].append(np.nan) else: data_series['代码'].append(idata[0]) idata = re.findall(pat_rating, line) if len(idata) == 0: data_series['评级'].append(np.nan) else: data_series['评级'].append(idata[0]) # 如果匹配的数据多余1个,则选择结果的后面一个作为成交 idata = re.findall(pet_price, line) if len(idata) == 0: data_series['成交价'].append(np.nan) elif len(idata) == 1: data_series['成交价'].append(idata[0]) else: data_series['成交价'].append(idata[1]) idata = re.findall(pet_xingquan, line) if len(idata) == 0: data_series['是否行权'].append(np.nan) else: data_series['是否行权'].append(idata[0])
将list数据转换成dataframe,然后输出成csv格式。
data_pd = pd.DataFrame(data_series)data_pd.to_csv('output.csv', encoding="utf_8_sig")
dataframe的view:
csv:
关于原始数据、代码、清洗后的数据,保存到了网盘上:
链接: https://pan.baidu.com/s/12TeeKEomElYMtH8cj8UCVQ
提取码: bykw
如果整理一个文件夹所有的,在读取的时候遍历一个文件夹内所有的文件,要import os啊
入
如有需求请跟我讲哈,多谢关注和支持~