Python格式化解析不规则txt文本并转为dataframe
很多时候我们拿到的文本文件都是格式不规范的,甚至是相当不规范的。。所以我们想要把不规范的文本文件变成规范的表格式,便于后续的模型训练和分析,在本篇文章中,主要的难点是从文本文件提取key-value的工作。
Step-0:数据示例
比如我们需要把如下数据中的key和value分别提取出来,并将相同key的值放在一列:
qid=157238221 isAdopted=1 qTags= qTime=2010-06-03 19:47 giveScore=200 askerid=188349317 askerGrade=5 askerGoodRate=48 askerAnswerNumber=44 askerName=cribberbd aid=467956656 isBest=1 ahasComment=0 aTime=2010-06-04 16:54 aCon=参看:a href="http:baike.baidu.comview1678662.htm?fr=ala0_1_1" target="_blank"http:baike.baidu.comview1678662.htm?fr=ala0_1_1a answerid=169837710 answerName= answerCareField= answerGrade= answerGoodRate= answerNum= answerIsMaster= answerIsFamous= aid=467569408 isBest= ahasComment=0 aTime=2010-06-03 20:09 aCon= will always love you下载地址a href="http:mp3.baidu.comm?f=ms&rn=&tn=baidump3&ct=134217728&word=I+will+always+love+you&lm=-1" target="_blank"http:mp3.baidu.comm?f=ms&rn=&tn=baidump3&ct=134217728&word=I+will+always+love+you&lm=-1a answerid=129235439 answerName=唯念潇湘 answerCareField= answerGrade=5 answerGoodRate=40 answerNum=46 answerIsMaster=0 answerIsFamous=0 aid=467584335 isBest= ahasComment=0 aTime=2010-06-03 20:35 aCon=是i will always love you= = answerid=12422236 answerName=qizi86 answerCareField=电视" answerGrade=18 answerGoodRate=36 answerNum=13266 answerIsMaster=0 answerIsFamous=0 aid=467849272 isBest= ahasComment=0 aTime=2010-06-04 13:17 aCon=长风镖局》 answerid=194560318 answerName=水滴里的火花 answerCareField= answerGrade=2 answerGoodRate=19 answerNum=5 answerIsMaster=0 answerIsFamous=0 aid=470025197 isBest= ahasComment=0 aTime=2010-06-08 17:27 aCon=长风镖局》 answerid=192636431 answerName=346317740 answerCareField=校园生活 answerGrade=5 answerGoodRate=14 answerNum=17 answerIsMaster=0 answerIsFamous=0
Step-1:数据载入:
没什么可说的,直接with open,需要注意的是原始文档当中有特殊字符,因此需要加上忽略错误with open(filename,encoding='utf-8',errors='ignore') as f:
另外由于原始文件特别大,为了避免内存直接爆掉,采用了循环逐行读取的f.readline()。
Step-2:格式化:
进入重头戏格式化,分析数据发现不同的keyvalue对是用空格分割的,但是许多内容中本身就有空格。。。坑爹啊这不是。。。看来直接用空格分割不靠谱。。。
后来尝试了分割成list,用list组成dataframe,不过分完才发现,每条记录的key个数并不相同,所以这样做也会出问题。
最后发现key、value之间是用=号分割的,因此采用正则来提取pattern,但是提取出来才发现,许多文本中也含有“=”这个特殊字符,做到这我已经想不出别的招来了= =,所以决定给“=”前后正则加上限制,只有大小写英文小写开头小写结束(分析不完整的参数key字典发现的规则)的才勉强算是正常的key,后面通过key传非空的比例来决定key的取舍,异常的key的值空率放在大样本上应该是接近百分百的。。
最后话不多说,放代码吧:
def load_data(filename,n):
with open(filename,encoding='utf-8',errors='ignore') as f:
#f=open('QACorpusData',encoding='utf-8',errors='ignore')
#确定正则匹配模式
pattern= re.compile(r'[a-z]{1,}[a-zA-Z]{1,}[a-z]{1,}=[^=]{0,} |[a-z]{1,}[a-zA-Z]{1,}[a-z]{1,}=[^=]{0,}')
#循环文件中每一行
kv_data_Q=[]
kv_data_A=[]
#for each_line in f:
for k in range(0,n):
#将Question和Answer分开分别建表
each_line= f.readline()
line=each_line.strip().split('\t')
for i in range(0,len(line)):
ss=pattern.findall(line[i])
#print(ss)
#print(len(ss))
data=[]
#取出key-value并分割
for i in ss:
tmp=i.strip().split('=')
data.append(tmp)
#转换为dict类型
data_dict=dict(data)
#增加Q&A分类
if 'qid' in data_dict.keys():
#data_dict['type']='Q'
qid=data_dict['qid']
#append到Qusetion表
kv_data_Q.append(data_dict)
else:
data_dict['qid']=qid
#data_dict['type']='A'
kv_data_A.append(data_dict)
#append到Answer表
df_Q=pd.DataFrame.from_dict(kv_data_Q)
df_A=pd.DataFrame.from_dict(kv_data_A)
return df_Q,df_A
#f.close()
Step-3:去除误识别:
通过列的空值比例去除误识别,代码如下:
#考察各列的空值个数
def empty_count(df):
n=len(df)#数据集记录数
empty_cnt = pd.DataFrame(columns=['columns_name', 'normal', 'null','empty'])
for c in df.columns:
n_cnt=sum(df[c].isnull())#判断是否为NaN
e_cnt=sum(df[c].apply(lambda x: True if x =='' else False))#判断是否为空字符
empty_cnt=empty_cnt.append({'columns_name':c,'normal':(n-n_cnt-e_cnt)/n,'null':n_cnt/n,'empty':e_cnt/n},ignore_index=True)
return empty_cnt
#print(empty_cnt)
#删除异常的列
def del_cols(df):
df_ec=empty_count(df)
for col in df_ec[df_ec.null>=0.9].columns_name:
df.drop(col,axis=1,inplace=True)
for df_deal in [df_Q_Cheat,df_A_Cheat,df_Q_Normal,df_A_Normal]:
del_cols(df_deal)
print(df_deal,'check!')
空值判断效果