Python常用功能函数系列总结(二)
本节目录
常用函数一:sel文件转换
常用函数二:refwork文件转换
常用函数三:xml文档解析
常用函数四:文本分词
常用函数一:sel文件转换
sel是种特殊的文件格式,具体应用场景的话可以在搜狗细胞词库中看到,经常在做文本处理,分词的时候需要一些词典,那么搜狗细胞词库中的一些相关词库就会被使用,而这种sel文件格式不能直接使用,需要进行转换,转换成txt文件之后就可以去做进一步使用了,转换的代码是从网上找到,我自己也是用过多次,使用的时候可以直接拿来用。
# -*- coding:utf-8 -*-
"""
@author:Zhang Yafei
@time: 2019/12/26
Description: scel 文件格式转换
"""
import struct
import os # 搜狗的scel词库就是保存的文本的unicode编码,每两个字节一个字符(中文汉字或者英文字母)
# 找出其每部分的偏移位置即可
# 主要两部分
# 1.全局拼音表,貌似是所有的拼音组合,字典序
# 格式为(index,len,pinyin)的列表
# index: 两个字节的整数 代表这个拼音的索引
# len: 两个字节的整数 拼音的字节长度
# pinyin: 当前的拼音,每个字符两个字节,总长len
#
# 2.汉语词组表
# 格式为(same,py_table_len,py_table,{word_len,word,ext_len,ext})的一个列表
# same: 两个字节 整数 同音词数量
# py_table_len: 两个字节 整数
# py_table: 整数列表,每个整数两个字节,每个整数代表一个拼音的索引
#
# word_len:两个字节 整数 代表中文词组字节数长度
# word: 中文词组,每个中文汉字两个字节,总长度word_len
# ext_len: 两个字节 整数 代表扩展信息的长度,好像都是10
# ext: 扩展信息 前两个字节是一个整数(不知道是不是词频) 后八个字节全是0
#
# {word_len,word,ext_len,ext} 一共重复same次 同音词 相同拼音表 # 拼音表偏移,
startPy = 0x1540; # 汉语词组表偏移
startChinese = 0x2628; # 全局拼音表
GPy_Table = {} # 解析结果
# 元组(词频,拼音,中文词组)的列表
GTable = [] # 原始字节码转为字符串
def byte2str(data):
pos = 0
str = ''
while pos < len(data):
c = chr(struct.unpack('H', bytes([data[pos], data[pos + 1]]))[0])
if c != chr(0):
str += c
pos += 2
return str # 获取拼音表
def getPyTable(data):
data = data[4:]
pos = 0
while pos < len(data):
index = struct.unpack('H', bytes([data[pos], data[pos + 1]]))[0]
pos += 2
lenPy = struct.unpack('H', bytes([data[pos], data[pos + 1]]))[0]
pos += 2
py = byte2str(data[pos:pos + lenPy]) GPy_Table[index] = py
pos += lenPy # 获取一个词组的拼音
def getWordPy(data):
pos = 0
ret = ''
while pos < len(data):
index = struct.unpack('H', bytes([data[pos], data[pos + 1]]))[0]
ret += GPy_Table[index]
pos += 2
return ret # 读取中文表
def getChinese(data):
pos = 0
while pos < len(data):
# 同音词数量
same = struct.unpack('H', bytes([data[pos], data[pos + 1]]))[0] # 拼音索引表长度
pos += 2
py_table_len = struct.unpack('H', bytes([data[pos], data[pos + 1]]))[0] # 拼音索引表
pos += 2
py = getWordPy(data[pos: pos + py_table_len]) # 中文词组
pos += py_table_len
for i in range(same):
# 中文词组长度
c_len = struct.unpack('H', bytes([data[pos], data[pos + 1]]))[0]
# 中文词组
pos += 2
word = byte2str(data[pos: pos + c_len])
# 扩展数据长度
pos += c_len
ext_len = struct.unpack('H', bytes([data[pos], data[pos + 1]]))[0]
# 词频
pos += 2
count = struct.unpack('H', bytes([data[pos], data[pos + 1]]))[0] # 保存
GTable.append((count, py, word)) # 到下个词的偏移位置
pos += ext_len def scel2txt(file_name):
print('-' * 60)
with open(file_name, 'rb') as f:
data = f.read() print("词库名:", byte2str(data[0x130:0x338])) # .encode('GB18030')
print("词库类型:", byte2str(data[0x338:0x540]))
print("描述信息:", byte2str(data[0x540:0xd40]))
print("词库示例:", byte2str(data[0xd40:startPy])) getPyTable(data[startPy:startChinese])
getChinese(data[startChinese:]) def run(to_file, file=None, dir_path=None):
"""
sel 多个文件转换
:param file: sel文件路径 转换单个sel文件
:param dir_path: sel文件夹路径 若设置 则转换该文件加内所有sel文件
:param to_file: 转换完成文件路径
:return:
"""
if dir_path:
fin = [fname for fname in os.listdir(in_path) if fname[-5:] == ".scel"]
for f in fin:
f = os.path.join(in_path, f)
scel2txt(f)
elif file:
scel2txt(file)
else:
raise Exception('参数必须包含file或者dir_path')
# 保存结果
with open(to_file, 'w', encoding='utf8') as f:
f.writelines([word + '\n' for count, py, word in GTable]) def dict_merge():
"""
词典合并
:return:
"""
with open('data/medical_dict.txt', encoding='utf8') as f:
word_set1 = {word.strip() for word in f}
with open('data/medical_dict2.txt', encoding='utf8') as f:
word_set2 = {word.strip() for word in f}
with open('data/medical_dict3.txt', encoding='utf8') as f:
word_set3 = {word.strip() for word in f}
word_set = word_set1 | word_set2 | word_set3
with open('data/words_dict.txt', encoding='utf-8', mode='w') as f:
for word in word_set:
f.write(word + '\n') if __name__ == '__main__':
# run(file='data/细胞词库/医学词汇大全【官方推荐】.scel', to_file='医学词库.txt',)
run(dir_path="data/细胞词库", to_file="data/cell_dict.txt")
经验分享:直接拿来用。
常用函数二:refwork文件转换
refowrk是一种文献格式,可以用一些科研软件做分析使用,有些场景下我们需要将excel格式的文件转成refwork文件,一下代码可以实现这个功能。
# -*- coding: utf-8 -*-
"""
Datetime: 2020/03/04
author: Zhang Yafei
description: refwork格式转换
数据格式
列 RT,A1,T1,JF,YR,K1,AB,AD
...
"""
import pandas as pd def main(ref_file, to_file):
"""
:param ref_file: 转换的csv或者excel文件路径
:param to_file: 转换之后保存的refwork文件路径
"""
if ref_file.endswith('csv'):
rawdata = pd.read_csv(ref_file)
elif ref_file.endswith('xls') or ref_file.endswith('xlsx'):
rawdata = pd.read_excel(ref_file)
with open(to_file, 'a') as f:
for index, item in rawdata.iterrows():
f.write('RT ' + item.RT)
A1 = item.A1
f.write('\n' + 'A1 ' + A1)
T1 = item.T1
f.write('\n' + 'T1 ' + T1)
YR = item.YR
f.write('\n' + 'YR ' + YR)
JF = item.JF
f.write('\n' + 'JF ' + JF)
K1 = item.K1
f.write('\n' + 'K1 ' + K1)
AB = item.AB
if pd.notna(AB):
f.write('\n' + 'AB ' + AB)
AD = item.AD
if pd.notna(AD):
f.write('\n' + 'AD ' + AD)
f.write('\nDS CNKI')
if index < rawdata.shape[0] - 1:
f.write('\n\n\n') if __name__ == '__main__':
main(ref_file='data.xlsx', to_file='result.txt')
经验分享:直接拿来用
常用函数三:xml文档解析
xml文档经常作为数据传输格式在web领域使用,它有很多优势,但我们平时梳理的数据大多是csv或者exel这种,那么解析xml文档就是一个必备的技能吗,下面以pubmed下载的xml文档解析为例,展示了xml文档解析的整个流程。
# -*- coding: utf-8 -*- """
@Datetime: 2019/4/26
@Author: Zhang Yafei
@Description: 07_xml文档解析
"""
import os
import re
import threading
from concurrent.futures import ThreadPoolExecutor from lxml import etree
import pandas as pd def pubmed_xpath_parse(path):
tree = etree.parse(path)
# 如果xml数据中出现了关于dtd的声明(如下面的例子),那样的话,必须在使用lxml解析xml的时候,进行相应的声明。
# parser = etree.XMLParser(load_dtd=True) # 首先根据dtd得到一个parser(注意dtd文件要放在和xml文件相同的目录)
# tree = etree.parse('1.xml', parser=parser) # 用上面得到的parser将xml解析为树结构
data_list = []
pmid_set = []
for articles in tree.xpath('//PubmedArticle'):
pmid = articles.xpath('MedlineCitation/PMID/text()')[0]
if pmid in pmid_set:
continue
pmid_set.append(pmid)
Article = articles.xpath('MedlineCitation/Article')[0]
journal = Article.xpath('Journal/ISOAbbreviation/text()')[0]
try:
authors = Article.xpath('AuthorList/Author')
affiliations_info = set()
for author in authors:
# author_name = author.find('LastName').text + ' ' + author.find('ForeName').text
affiliations = [x.xpath('Affiliation/text()')[0] for x in author.xpath('AffiliationInfo')]
# author = author_name + ':' + ';'.join(affiliations)
for affiliation in affiliations:
affiliations_info.add(affiliation)
affiliations_info = ';'.join(affiliations_info)
except AttributeError:
affiliations_info = ''
try:
date = Article.xpath('Journal/JournalIssue/PubDate/Year/text()')[0]
except IndexError:
date = Article.xpath('Journal/JournalIssue/PubDate/MedlineDate/text()')[0]
date = re.search('\d+', date).group(0)
try:
mesh_words = []
for mesh_heading in articles.xpath('MedlineCitation/MeshHeadingList/MeshHeading'):
if len(mesh_heading.xpath('child::*')) == 1:
mesh_words.append((mesh_heading.xpath('child::*'))[0].text)
continue
mesh_name = ''
for mesh in mesh_heading.xpath('child::*'):
if mesh.tag == 'DescriptorName':
mesh_name = mesh.xpath('string()')
continue
if mesh_name and mesh.tag == 'QualifierName':
mesh_word = mesh_name + '/' + mesh.xpath('string()')
mesh_words.append(mesh_word)
mesh_words = ';'.join(mesh_words)
except AttributeError:
mesh_words = ''
article_type = '/'.join([x.xpath('./text()')[0] for x in Article.xpath('PublicationTypeList/PublicationType')])
country = articles.xpath('MedlineCitation/MedlineJournalInfo/Country/text()')[0]
data_list.append(
{'PMID': pmid, 'journal': journal, 'affiliations_info': affiliations_info, 'pub_year': date,
'mesh_words': mesh_words,
'country': country, 'article_type': article_type, 'file_path': path})
print(pmid + '\t解析完成')
df = pd.DataFrame(data_list)
with threading.Lock():
df.to_csv('pubmed.csv', encoding='utf_8_sig', mode='a', index=False, header=False) def to_excel(data, path):
writer = pd.ExcelWriter(path)
data.to_excel(writer, sheet_name='table', index=False)
writer.save() def get_files_path(dir_name):
xml_files = []
for base_path, folders, files in os.walk(dir_name):
xml_files = xml_files + [os.path.join(base_path, file) for file in files if file.endswith('.xml')]
return xml_files if __name__ == '__main__':
files = get_files_path(dir_name='data')
if not files:
print('全部解析完成')
else:
with ThreadPoolExecutor() as pool:
pool.map(pubmed_xpath_parse, files)
常用函数四:文本分词
方式一:jieba分词+停用词+自定义词典+同义词替换
# -*- coding: utf-8 -*- """
Datetime: 2020/06/25
Author: Zhang Yafei
Description: 文本分词
输入 停用词文件路径 词典文件路径 同义词文件路径 分词文件路径 表名(可选) 列名 分词结果列名 保存文件名
输出 分词结果-文件
"""
import os
import re
import time
from collections import defaultdict
from functools import wraps import jieba
import pandas as pd if not os.path.exists('res'):
os.mkdir('res') def timeit(func):
""" 时间装饰器 """ @wraps(func)
def inner(*args, **kwargs):
start_time = time.time()
ret = func(*args, **kwargs)
end_time = time.time() - start_time
if end_time < 60:
print(f'共花费时间:', round(end_time, 2), '秒')
else:
minute, sec = divmod(end_time, 60)
print(f'花费时间\t{round(minute)}分\t{round(sec, 2)}秒')
return ret return inner class TextCut(object):
def __init__(self, dictionary=None, stopwords=None, synword=None):
self.dictionary = dictionary
self.word_list = None
if self.dictionary:
jieba.load_userdict(self.dictionary)
if stopwords:
with open(stopwords, 'r', encoding='utf-8') as swf:
self.stopwords = [line.strip() for line in swf]
else:
self.stopwords = None
if synword:
self.syn_word_dict = self.build_sync_dict(synword)
else:
self.syn_word_dict = None @staticmethod
def clean_txt(raw):
file = re.compile(r"[^0-9a-zA-Z\u4e00-\u9fa5]+")
return file.sub(' ', raw) def cut(self, text):
sentence = self.clean_txt(text.strip().replace('\n', ''))
return ' '.join([i for i in jieba.cut(sentence) if i.strip() and i not in self.stopwords and len(i) > 1]) def cut2(self, text):
sentence = self.clean_txt(text.strip().replace('\n', ''))
return ' '.join([i for i in jieba.cut(sentence) if
i.strip() and i not in self.stopwords and len(i) > 1 and i in self.word_list]) def syn_word_replace(self, row):
word_list = []
for word in row.split(' '):
if word in self.syn_word_dict:
word = self.syn_word_dict[word]
word_list.append(word)
return ' '.join(word_list) def build_sync_dict(self, synword):
syn_map = {}
with open(synword, mode='r', encoding='utf-8') as f:
for row in f:
stand_word = row.split(',')[0].strip()
for word in row.split(',')[1:]:
if word.strip():
syn_map[word.strip()] = stand_word
return syn_map @timeit
def run(self, file_path, col_name, new_col_name, to_file, sheet_name=None, word_in_dict=False):
print('######### 开始读取数据文件 ############')
if sheet_name:
df = pd.read_excel(file_path, sheet_name=sheet_name)
else:
df = pd.read_excel(file_path)
print('######### 开始进行数据处理 ############')
if word_in_dict:
with open(self.dictionary, encoding='utf-8') as f:
self.word_list = [word.strip() for word in f]
df[new_col_name] = df[col_name].apply(self.cut2)
else:
df[new_col_name] = df[col_name].apply(self.cut) if self.syn_word_dict:
print('######### 正在进行同义词合并 ############')
df[f'{new_col_name}_同义词替换'] = df[new_col_name].apply(self.syn_word_replace)
print('######### 同义词合并完成 ############')
df.to_excel(to_file, index=False)
print('######### 处理完成 ############') if __name__ == "__main__":
text_cut = TextCut(stopwords='data/stopwords.txt', dictionary='data/word_dict.txt', synword='data/同义词.txt')
text_cut.run(file_path='data/山西政策.xlsx', sheet_name='1.21-2.20', col_name='全文', new_col_name='全文分词',
to_file='res/山西政策_分词.xlsx')
# text_cut.run(file_path='data/微博数据_处理.xlsx', col_name='微博正文_处理', new_col_name='全文分词',
# to_file='data/微博分词.xlsx')
方式二:jieba分词+信息熵合并
# -*- coding: utf-8 -*- """
Datetime: 2020/03/01
Author: Zhang Yafei
Description: 基于信息熵对分词结果进行合并
"""
from collections import Counter
from functools import reduce
from pandas import read_excel, DataFrame class InfoEntropyMerge(object):
def __init__(self, data, stopwords='data/stopwords.txt'):
self.data = data
self.words_freq_one = {}
self.words_freq_two = {}
self.entropy_words_dict = {}
if stopwords:
with open(stopwords, 'r', encoding='utf-8') as f:
self.stopwords = {line.strip() for line in f}
else:
self.stopwords = None def count_word_freq_one(self, save_to_file=False, word_freq_file=None):
keywords = (word for word_list in self.data for word in word_list if word)
self.words_freq_one = Counter(keywords)
if save_to_file:
words = [word for word in self.words_freq_one]
freqs = [self.words_freq_one[word] for word in words]
words_df = DataFrame(data={'word': words, 'freq': freqs})
words_df.sort_values('freq', ascending=False, inplace=True)
words_df.to_excel(word_freq_file, index=False) def count_freq(self, word1, word2):
"""
统计相邻两个词出现的频率
:param word1:
:param word2:
:return:
"""
if (word1, word2) not in self.words_freq_two:
self.words_freq_two[(word1, word2)] = 1
else:
self.words_freq_two[(word1, word2)] += 1
return word2 def count_word_freq_two(self, save_to_file=False, word_freq_file=None):
"""
计算相邻两个词出现的频率
:param save_to_file:
:param word_freq_file:
:return:
"""
for word_list in self.data:
reduce(self.count_freq, word_list)
if save_to_file and word_freq_file:
words_list = [(word1, word2) for word1, word2 in self.words_freq_two]
freqs = [self.words_freq_two[w1_w2] for w1_w2 in words_list]
words_df = DataFrame(data={'word': words_list, 'freq': freqs})
words_df.sort_values('freq', ascending=False, inplace=True)
words_df.to_excel(word_freq_file, index=False) @staticmethod
def is_chinese(word):
for ch in word:
if '\u4e00' <= ch <= '\u9fff':
return True
return False def clac_entropy(self, save_to_file=False, dict_path='data/entropy_dict.txt'):
"""
计算信息熵: E(w1, w2) = P(w1,w2)/min(P(w1),P(w2))
:param save_to_file: 是否将熵值大于0.5的新词保存到文件中
:param dict_path: 保存字典路径
:return:
"""
for word1, word2 in self.words_freq_two:
freq_two = self.words_freq_two[(word1, word2)]
freq_one_min = min(self.words_freq_one[word1], self.words_freq_one[word2])
freq_one_max = max(self.words_freq_one[word1], self.words_freq_one[word2])
w1_w2_entropy = freq_two / freq_one_max
if self.stopwords:
if w1_w2_entropy > 0.5 and word1 not in self.stopwords and word2 not in self.stopwords and self.is_chinese(word1) and self.is_chinese(word2):
# print(word1, word2, freq_two, freq_one_min, freq_one_max)
self.entropy_words_dict[word1+word2] = w1_w2_entropy
else:
if w1_w2_entropy > 0.5:
self.entropy_words_dict[word1+word2] = w1_w2_entropy print('信息熵大于0.5的词语组合:\n', self.entropy_words_dict)
if save_to_file and dict_path:
with open(dict_path, mode='r+', encoding='utf-8') as f:
content = f.read()
f.seek(0, 0)
for word in self.entropy_words_dict:
f.write(word+'\n')
f.write(content)
print(f'成功将信息熵大于0.5的词语保存到了{dict_path}中') def data_read(path, col_name):
df = read_excel(path)
texts = df.loc[df[col_name].notna(), col_name].str.split()
return texts if __name__ == '__main__':
text_list = data_read(path='res/国家政策_分词.xlsx', col_name='全文分词')
info_entro = InfoEntropyMerge(data=text_list)
info_entro.count_word_freq_one()
info_entro.count_word_freq_two()
info_entro.clac_entropy(save_to_file=False, dict_path='data/entropy_dict.txt')
经验分享:若有好的词典和停用词,优先选用方式一,否则选择方式二。
Python常用功能函数系列总结(二)的更多相关文章
- Python常用功能函数系列总结(一)
本节目录 常用函数一:获取指定文件夹内所有文件 常用函数二:文件合并 常用函数三:将文件按时间划分 常用函数四:数据去重 写在前面 写代码也有很长时间了,总觉得应该做点什么有价值的事情,写代码初始阶段 ...
- Python常用功能函数系列总结(三)
本节目录 常用函数一:词频统计 常用函数二:word2vec 常用函数三:doc2vec 常用函数四:LDA主题分析 常用函数一:词频统计 # -*- coding: utf-8 -*- " ...
- Python常用功能函数系列总结(六)
本节目录 常用函数一:词云图 常用函数二:关键词清洗 常用函数三:中英文姓名转换 常用函数四:去除文本中的HTML标签和文本清洗 常用函数一:词云图 wordcloud # -*- coding: ...
- Python常用功能函数系列总结(五)
本节目录 常用函数一:向量距离和相似度计算 常用函数二:pagerank 常用函数三:TF-IDF 常用函数四:关键词提取 常用函数一:向量距离和相似度计算 KL距离.JS距离.余弦距离 # -*- ...
- Python常用功能函数系列总结(四)之数据库操作
本节目录 常用函数一:redis操作 常用函数二:mongodb操作 常用函数三:数据库连接池操作 常用函数四:pandas连接数据库 常用函数五:异步连接数据库 常用函数一:redis操作 # -* ...
- Python常用功能函数系列总结(七)
本节目录 常用函数一:批量文件重命名 常用函数一:批量文件重命名 # -*- coding: utf-8 -*- """ DateTime : 2021/02/08 10 ...
- Python常用功能函数总结系列
Python常用功能函数系列总结(一) 常用函数一:获取指定文件夹内所有文件 常用函数二:文件合并 常用函数三:将文件按时间划分 常用函数四:数据去重 Python常用功能函数系列总结(二) 常用函数 ...
- Python常用功能函数
Python常用功能函数汇总 1.按行写字符串到文件中 import sys, os, time, json def saveContext(filename,*name): format = '^' ...
- Python 常用string函数
Python 常用string函数 字符串中字符大小写的变换 1. str.lower() //小写>>> 'SkatE'.lower()'skate' 2. str.upper ...
随机推荐
- 攻击科普:DDos
目录 一.DDoS 攻击究竟是什么? 二.DDoS 攻击多少G是什么意思? 二.DDoS攻击种类 ICMP Flood UDP Flood NTP Flood SYN Flood CC攻击 DNS Q ...
- 使用hbuilder打包vue项目容易出现的坑点
1.打包后手机打开"该app专为旧版本安卓"问题解决(在hbuilder中设置) 打开manifest.json 然后 2.打包后app打开显示白屏. 路径问题:在webpack中 ...
- N1BOOK——[第五章 CTF之RE章]wp
推荐在了解了相应章节的内容后再来练习,你会觉得顿时悟了 记录一下自己的解题过程 2,3,4题目附件来源:https://book.nu1l.com/tasks/#/pages/reverse/5.4 ...
- 【Web】BUUCTF-warmup(CVE-2018-12613)
BUUCTF 的第一题,上来就给搞懵了.. .这要是我自己做出来的,岂不是相当于挖了一个 CVE ?(菜鸡这样安慰自己) 问题在 index.php 的 55~63 行 // If we have ...
- Dubbo配置注册中心设置application的name使用驼峰命名法存在的隐藏项目启动异常问题
原创/朱季谦 首先,先提一个建议,在SpringBoot+Dubbo项目中,Dubbo配置注册中心设置的application命名name的值,最好使用xxx-xxx-xxx这样格式的,避免随便使用驼 ...
- CF1145F Neat Words 题解
Content 本题为 CF 愚人节比赛题目. 给定一个长度为 \(n\) 的,仅包含大写字母的字符串,问这个字符串里面的字母是否全部都是由仅有直线的字母组成,或者全部都是由有曲线的字母构成. 数据范 ...
- CF1428A Box is Pull 题解
Content 有一个兔子拖着一个盒子在走,每秒钟可以带着盒子走一个单位,也可以不带着盒子走一个单位.当且仅当兔子和盒子的距离不超过 \(1\) 时可以带着盒子走一个单位.现给出 \(t\) 次询问, ...
- java 常用类库:时间类LocalDate;LocalTime;LocalDateTime;Calendar 类;Date ;
LocalDate类 LocalDate类代表不带时区的日期,列入2020-12-20.该类提供了静态的now()方法来获取当前的日期.这个类是线程安全的. LocalTime类 代表不带时区的时间, ...
- libevent实现多线程
libevent并不是线程安全的,但这不代表libevent不支持多线程模式.前几天在微博上看到ruanyf发了条微博说到apache和nginx的并发模型,看到评论很多人都说不对于是自己又查了下,总 ...
- 【LeetCode】1120. Maximum Average Subtree 解题报告 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 DFS 日期 题目地址:https://leetcod ...