本节目录

  • 常用函数一: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常用功能函数系列总结(二)的更多相关文章

  1. Python常用功能函数系列总结(一)

    本节目录 常用函数一:获取指定文件夹内所有文件 常用函数二:文件合并 常用函数三:将文件按时间划分 常用函数四:数据去重 写在前面 写代码也有很长时间了,总觉得应该做点什么有价值的事情,写代码初始阶段 ...

  2. Python常用功能函数系列总结(三)

    本节目录 常用函数一:词频统计 常用函数二:word2vec 常用函数三:doc2vec 常用函数四:LDA主题分析 常用函数一:词频统计 # -*- coding: utf-8 -*- " ...

  3. Python常用功能函数系列总结(六)

    本节目录 常用函数一:词云图 常用函数二:关键词清洗 常用函数三:中英文姓名转换  常用函数四:去除文本中的HTML标签和文本清洗 常用函数一:词云图 wordcloud # -*- coding: ...

  4. Python常用功能函数系列总结(五)

    本节目录 常用函数一:向量距离和相似度计算 常用函数二:pagerank 常用函数三:TF-IDF 常用函数四:关键词提取 常用函数一:向量距离和相似度计算 KL距离.JS距离.余弦距离 # -*- ...

  5. Python常用功能函数系列总结(四)之数据库操作

    本节目录 常用函数一:redis操作 常用函数二:mongodb操作 常用函数三:数据库连接池操作 常用函数四:pandas连接数据库 常用函数五:异步连接数据库 常用函数一:redis操作 # -* ...

  6. Python常用功能函数系列总结(七)

    本节目录 常用函数一:批量文件重命名 常用函数一:批量文件重命名 # -*- coding: utf-8 -*- """ DateTime : 2021/02/08 10 ...

  7. Python常用功能函数总结系列

    Python常用功能函数系列总结(一) 常用函数一:获取指定文件夹内所有文件 常用函数二:文件合并 常用函数三:将文件按时间划分 常用函数四:数据去重 Python常用功能函数系列总结(二) 常用函数 ...

  8. Python常用功能函数

    Python常用功能函数汇总 1.按行写字符串到文件中 import sys, os, time, json def saveContext(filename,*name): format = '^' ...

  9. Python 常用string函数

    Python 常用string函数 字符串中字符大小写的变换 1. str.lower()   //小写>>> 'SkatE'.lower()'skate' 2. str.upper ...

随机推荐

  1. vscode高效管理不同项目文件

    vscode作为一个轻量级编辑器,深受大家喜爱,这其中当然也囊括了本人.我同时使用vscode写c++.java.python以及markdown文档,每次打开vscode都要切换到对应的文件夹,非常 ...

  2. mysql中索引,触发器,事务,存储引擎的理解

    网址:http://blog.51cto.com/760470897/1790460

  3. redis实例cpu占用率过高问题优化

    目录 一.简介 一.简介 前情提要: 最近接了大数据项目的postgresql运维,刚接过来他们的报表系统就出现高峰期访问不了的问题,报表涉及实时数据和离线数据,离线读pg,实时读redis.然后自然 ...

  4. Mysql资料 数据类型

    目录 一.类型 整型 浮点型 定点数 字符串 二进制数据 时间日期类型 二.长度和范围 三.使用建议 原则 存储引擎 text和blob 浮点数和定点数 四.属性 一.类型 整型 取值范围如果加了un ...

  5. pipeline parameters指令

    目录 一.简介 二.类型 参数类型 多参数 一.简介 参数化pipeline是指通过传参来决定pipeline的行为.参数化让写pipeline就像写函数,而函数意味着可重用.更抽象.所以,通常使用参 ...

  6. MySQL如何随机筛选25000条数据

    一.SELECT * FROM sheet1 t1 ORDER BY RAND() LIMIT 10000; 二.SELECT * FROM sheet1 AS t1 JOIN (SELECT ROU ...

  7. Shell if 参数含义列表

    [ -a FILE ]  如果 FILE 存在则为真.   [ -b FILE ]  如果 FILE 存在且是一个块特殊文件则为真.   [ -c FILE ]  如果 FILE 存在且是一个字特殊文 ...

  8. OpenWrt之关闭IPv6

    目录 OpenWrt之关闭IPv6 1.前言 2.WAN口设置 3.LAN口设置 4.保存并应用 5.防火墙设置 6.DHCP/DNS设置 1)SSH连接路由器 2)输入第一条命令,按回车执行 3)输 ...

  9. Python的动态语言特性; __slots__属性

    python是动态语言 1. 动态语言的定义 动态编程语言 是 高级程序设计语言 的一个类别,在计算机科学领域已被广泛应用.它是一类 在运行时可以改变其结构的语言 :例如新的函数.对象.甚至代码可以被 ...

  10. JAVA比较两个版本号的大小

    /** * 比较版本号的大小 (两个版本号格式应尽量相同) * * @param v1 版本号1 * @param v2 版本号2 * @return 正数:v1大 负数:v2大 0:相等 */ pu ...