02.数据预处理之清洗文本信息

准备30万条新闻数据

编号 新闻类别 新闻数量(条)
1 财经 37098
2 教育 41963
3 科技 65534
4 时政 63086
5 体育 65534
6 娱乐 65534

链接: https://pan.baidu.com/s/17Q0jIDBcM40hXwPPw6Di2g 提取码: byg6
文件比较大,各位可以先下载,继续看后面


yield生成器

  • 斐波那契数列介绍和数学描述
  • 斐波那契数列算法实现
  • 斐波那契数列算法生成器实现
  • 算法时间性能对比分析
# coding=utf-8

"""
Description:yield生成器案例
"""
import time

"""
斐波那契数列:1,1,2,3,5,8,13,21,34,55,89,144
从数列的第三项开始,后面每一项是前面两项之和

数学上的定义:F(0) = 1, F(1) = 1, F(n) = F(n-1) + F(n-2)(n>=2, n∈N)
"""


# 普通的斐波那契数列实现
def fab1(max):
    n, a, b = 0, 0, 1
    while n < max:
        # print('->', b)
        a, b = b, a + b

        n = n + 1


# 生成器算法实现斐波那契数列
def fab2(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b  # 使用yield生成器
        a, b = b, a + b

        n = n + 1


def test():
    # 最大迭代数
    max_num = 1000000
    start_time = time.time()
    fab1(max_num)
    end_time = time.time()
    print('fab1 total time %.2f' % (1000 * (end_time - start_time)), 'ms')

    start_time = time.time()
    #  B为一个<generator object fab2 at 0x00000273C87679A8>
    # 可以通过遍历进行获取值
    b = fab2(max_num)
    end_time = time.time()
    print('fab2 total time %.2f' % (1000 * (end_time - start_time)), 'ms')


if __name__ == '__main__':
    test()


输出:
fab1 total time 7085.11 ms
fab2 total time 0.00 ms

递归读取30万新闻

  • 实现文件遍历递归
  • 遍历读取30万新闻
  • 每万条读取打印一次
  • 完成30万新闻遍历读取
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@Description : 递归批量读取30W文本
@Time : 2020/1/2 23:41
@Author : sky
@Site :
@File : FileRead.py
@Software: PyCharm
"""

import os
import time


def traversal_dir(root_dir):
    """
    返回指定目录包含的文件或文件夹名字列表
    :param root_dir: 根目录
    :return: 文件(文件夹)名字列表
    """
    for index, file_name in enumerate(os.listdir(root_dir)):
        # 待处理文件名字列表
        child_file_path = os.path.join(root_dir, file_name)

        if os.path.isfile(child_file_path):
            # 对文件进行操作
            if index % 10000 == 0:
                print('{c} *** {t} *** {i} \t docs has been read'
                      .format(c=root_dir, i=index, t=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())))
        elif os.path.isdir(child_file_path):
            # 递归遍历文件目录
            traversal_dir(child_file_path)


if __name__ == '__main__':
    root_dir = '../dataset/CSCMNews'
    start_time = time.time()
    traversal_dir(root_dir)
    end_time = time.time()

    print('Total Cost Time %.2f' % (end_time - start_time) + 's')


高效读取30万新闻

  • 构建生成器
  • 构建迭代器
  • 高效读取30万新闻
  • 读取30万新闻性能对比
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
# @Description 高效读取30万新闻
# @Time : 2020/1/4 14:47 
# @Author : sky 
# @Site :  
# @File : EfficRead.py 
# @Software: PyCharm
"""

import os
import time


# 迭代器
class LoadFolders(object):
    def __init__(self, parent_path):
        self.parent_path = parent_path

    def __iter__(self):
        for file in os.listdir(self.parent_path):
            file_abspath = os.path.join(self.parent_path, file)
            if os.path.isdir(file_abspath):
                yield file_abspath


class LoadFiles(object):
    def __init__(self, parent_path):
        self.parent_path = parent_path

    def __iter__(self):
        folders = LoadFolders(self.parent_path)
        # 第一级目录
        for folder in folders:
            category = folder.split(os.sep)[-1]
            # 第二级目录
            for file in os.listdir(folder):
                yield category, file


if __name__ == '__main__':
    file_path = os.path.abspath('../dataset/CSCMNews')

    start_time = time.time()

    files = LoadFiles(file_path)
    for index, msg in enumerate(files):
        if index % 10000 == 0:
            print('{t} *** {i} \t docs has bean read'.format(t=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), i=index))

    end_time = time.time()

    print('Total Cost Time %.2f' % (end_time - start_time) + 's')

小结

  • 数组、链表、字符串、文件等缺点就是所有的\color{red}{数据都在内存里},海量的数据\color{red}{耗内存}
  • 生成器是可以迭代的,\color{red}{工作原理}就是重复调用\color{red}{next方法},直到没有下一个
  • \color{red}{yield的函数}不再是一个普通的函数,而是一个\color{red}{生成器},可用于\color{red}{迭代}
  • yield是一个类似\color{red}{return的关键字}

正则清洗数据

  • 分析新闻语料文本
  • 读取新闻文本信息
  • 正则过滤掉特殊符号、标点、英文、数字等
  • 正则去除空格、换行符、多空格合并等
  • 实现正则清洗文本数据

正则表达式学习

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
# @Description 正则表达式学习
# @Time : 2020/1/4 15:13 
# @Author : sky 
# @Site :  
# @File : reqular.py 
# @Software: PyCharm
"""

import re


# . 任意字符
# * 任意次数
# ^ 表示开头
# $ 表示结尾
# ? 非贪婪模式,提取第一个字符
# + 至少出现一次
# {1}出现一次
# {3,}出现3次以上
# {2,5}最少2次,最多5次
# \d 匹配数字
# [\u4E00-\u9FA5] 匹配汉字
# | 或
# [] 满足任意一个, [2345] 2345中任意一个 [0-9]区间 [^1]非1
# \s 空格 \S 非空格
# \w 匹配[A-Za-z0-9_] \W=非\w

text = 'this is Python 数据预处理, 这次学习的很好,使用的环境是Anaconda4.4,现在的时间是2020年1月4日'

# 开头 + 任意字符 + 任意次数
reg_1 = '(^t.*)'
# 存在s 这样会一直匹配到最后一个s
reg_2 = '.*(s+)'
# 存在s 贪婪 匹配到第一个s
reg_3 = '.*?(s+)'
# 匹配汉字?的作用同上
reg_4 = '.*?([\u4E00-\u9FA5]+的)'
# 匹配日期
reg_5 = '.*(\d{4}年)(\d{1,2}月)'

res = re.match(reg_5, text)
if res:
    print(res)
    print(res.group(2))  # group对应的数字是正则中括号的内容
else:
    print('没匹配到')

# 日期的提取
print('-'*20)

date_text = '现在的日期是2020年1月4日'
# date_text = '现在的日期是2020年01月04日'
# date_text = '现在的日期是2020-1-4'
# date_text = '现在的日期是2020-01-04'
# date_text = '现在的日期是2020/1/4'
# date_text = '现在的日期是2020/01/04'
# date_text = '现在的日期是2020-01'

reg_date = '.*(\d{4}[年/-]\d{1,2}[月/-]\d{,2}[日]?)'
res = re.match(reg_date, date_text)
if res:
    print(res)
    print(res.group(1))  # group对应的数字是正则中括号的内容
else:
    print('没匹配到')

# 手机号的提取
print('-'*20)

# phone_text = '我的手机号是13030010152,有什么问题可以联系我'
# phone_text = '我的手机号是17091033442,有什么问题可以联系我'
# phone_text = '我的手机号是18519299012,有什么问题可以联系我'
phone_text = '我的手机号是13691769664 ,有什么问题可以联系我'

reg_phone = '.*?(1[37859]\d{9})'
res = re.match(reg_phone, phone_text)
if res:
    print(res)
    print(res.group(1))  # group对应的数字是正则中括号的内容
else:
    print('没匹配到')

清洗文本数据

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
# @Description 正则清洗文本数据
# @Time : 2020/1/4 15:52 
# @Author : sky 
# @Site :  
# @File : REdealText.py 
# @Software: PyCharm
"""


import re


# 正则对字符串的清洗
def text_parse(text):
    # 正则过滤掉特殊符号,标点,英文,数字等
    reg_1 = '[a-zA-Z0-9’!"#$%&\'()*+,-./::;;|<=>?@,—。?★、…【】《》?“”‘’![\\]^_`{|}~]+'
    # 去除空格
    reg_2 = '\\s+'
    text = re.sub(reg_1, ' ', text)
    text = re.sub(reg_2, ' ', text)

    # 去除换行符
    text = text.replace('\n', '')
    return text


def read_file(path):
    str_doc = ''
    with open(path, encoding='utf-8') as f:
        str_doc = f.read()
    return str_doc


if __name__ == '__main__':
    # 读取文本
    str_doc_path = '../dataset/CSCMNews/体育/0.txt'
    str_doc = read_file(str_doc_path)
    print(str_doc)

    # 数据清洗
    clear_text = text_parse(str_doc)
    print(clear_text)


清洗HTML数据

  • 分析html文本信息
  • 导入正则:re.I、re.L、re.M、re.S……
  • 清洗HTML标签:DOCTYPE、CDATA、Script、style……
  • HTML标签、注释、换行等处理:re.compile
  • 实现正则清洗HTML数据
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
# @Description 正则清洗HTML
# @Time : 2020/1/4 18:46 
# @Author : sky 
# @Site :  
# @File : DealHtml.py 
# @Software: PyCharm
"""

import re


# 清洗HTML标签文本
def filter_tags(html_str):
    # 去掉多余的空格
    html_str = ' '.join(html_str.split())
    # 过滤DOCTYPE
    re_doctype = re.compile(r'<!DOCTYPE .*?>', re.S)
    res = re_doctype.sub('', html_str)
    # 过滤CDATA
    re_cdata = re.compile(r'//<!CDATA\[[ >]∗ //\] > ', re.I)
    res = re_cdata.sub('', res)
    # Script
    re_script = re.compile(r'<\s*script[^>]*>[^<]*<\s*/\s*script\s*>', re.I)
    res = re_script.sub('', res)
    # style
    re_style = re.compile(r'<\s*style[^>]*>[^<]*<\s*/\s*style\s*>', re.I)
    res = re_style.sub('', res)  # 去掉style

    # 处理换行
    re_br = re.compile(r'<br\s*?/?>')
    res = re_br.sub('', res)  # 将br转换为换行

    # HTML标签
    re_h = re.compile(r'</?\w+[^>]*>')
    res = re_h.sub('', res)  # 去掉HTML 标签

    # HTML注释
    re_comment = re.compile(r'<!--[^>]*-->')
    res = re_comment.sub('', res)

    # 多余的空行
    blank_line = re.compile(r'\n+')
    res = blank_line.sub('', res)

    blank_line_l = re.compile(r'\n')
    res = blank_line_l.sub('', res)

    blank_kon = re.compile(r'\t')
    res = blank_kon.sub('', res)

    blank_one = re.compile(r'\r\n')
    res = blank_one.sub('', res)

    blank_two = re.compile(r'\r')
    res = blank_two.sub('', res)

    blank_three = re.compile(r' ')
    res = blank_three.sub('', res)

    # 剔除超链接
    http_link = re.compile(r'(http://.+.html)')
    res = http_link.sub('', res)
    return res


def read_file(path):
    str_doc = ''
    with open(path, encoding='utf-8') as f:
        str_doc = f.read()
    return str_doc


if __name__ == '__main__':
    str_doc = read_file('./htmldemo.txt')
    res = filter_tags(str_doc)
    print(res)

简繁体转换

  • 简繁体python包下载与使用
  • 简繁对照表分析与自定义添加
  • python实现繁体文本转为简体文本
  • python实现简体文本转为繁体文本

工具包可以在https://gitee.com/tangjinghong/data_process进行下载

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
# @Description 简繁体转换
# @Time : 2020/1/4 19:08 
# @Author : sky 
# @Site :  
# @File : zhline.py 
# @Software: PyCharm
"""

from ClearText.zhtools.langconv import *

# 1、简体字转化为繁体
str1 = '上港5-4恒大5分领跑剑指冠军,下轮打平便可夺冠,' \
       '武磊平纪录—广州恒大淘宝|上海上港|蔡慧康|武磊|胡尔克|张成林|阿兰|保利尼奥|王燊超|吕文君|懂球帝' \
       '北京时间11月3日19:35,中超第28轮迎来天王山之战,广州恒大淘宝坐镇主场迎战上海上港。' \
       '上半场吕文君和蔡慧康先后进球两度为上港取得领先,保利尼奥和阿兰两度为恒大将比分扳平,' \
       '补时阶段保利尼奥进球反超比分;下半场武磊进球追平李金羽单赛季进球纪录,王燊超造成张成林乌龙,' \
       '胡尔克点射破门,阿兰补时打进点球。最终,上海上港客场5-4战胜广州恒大淘宝,' \
       '赛季双杀恒大同时也将积分榜上的领先优势扩大到五分,上港下轮只要战平就将夺得冠军。非常抱歉!'
line1 = Converter('zh-hant').convert(str1)
print('繁体---\n', line1)

# 2、繁体字转化为简体
str2 = '上港5-4恆大5分領跑劍指冠軍,下輪打平便可奪冠,' \
       '武磊平紀錄—廣州恆大淘寶|上海上港|蔡慧康|武磊|胡爾克|張成林|阿蘭|保利尼奧|王燊超|呂文君|懂球帝' \
       '北京時間11月3日19:35,中超第28輪迎來天王山之戰,廣州恆大淘寶坐鎮主場迎戰上海上港。' \
       '上半場呂文君和蔡慧康先後進球兩度為上港取得領先,保利尼奧和阿蘭兩度為恆大將比分扳平,' \
       '補時階段保利尼奧進球反超比分;下半場武磊進球追平李金羽單賽季進球紀錄,王燊超造成張成林烏龍,' \
       '胡爾克點射破門,阿蘭補時打進點球。最終,上海上港客場5-4戰勝廣州恆大淘寶,' \
       '賽季雙殺恆大同時也將積分榜上的領先優勢擴大到五分,上港下輪只要戰平就將奪得冠軍。非常抱歉!'
line2 = Converter('zh-hans').convert(str2)
print('简体---\n', line2)

30万新闻数据清洗

  • 高效读取30W新闻文本
  • 实现新闻文本抽样
  • 抽样新闻文本数据清洗
  • 每万条打印一次信息
  • 实现30W新闻文本数据清洗
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
# @Description 30W新闻文本数据清洗
# @Time : 2020/1/4 19:35 
# @Author : sky 
# @Site :  
# @File : 30wClear.py 
# @Software: PyCharm
"""

import os
import re
import time
from ClearText.REdealText import text_parse


# 高效读取文件
# 迭代器
class LoadFolders(object):
    def __init__(self, parent_path):
        self.parent_path = parent_path

    def __iter__(self):
        for file in os.listdir(self.parent_path):
            file_abspath = os.path.join(self.parent_path, file)
            if os.path.isdir(file_abspath):
                yield file_abspath


class LoadFiles(object):
    def __init__(self, parent_path):
        self.parent_path = parent_path

    def __iter__(self):
        folders = LoadFolders(self.parent_path)
        # 第一级目录
        for folder in folders:
            category = folder.split(os.sep)[-1]
            # 第二级目录
            for file in os.listdir(folder):
                file_path = os.path.join(folder, file)
                if os.path.isfile(file_path):
                    this_file = open(file_path, 'rb')  # rb读取快
                    content = this_file.read().decode('utf-8')
                yield category, content
                this_file.close()


if __name__ == '__main__':
    start_time = time.time()

    file_path = '../dataset/CSCMNews'
    files = LoadFiles(file_path)
    # 抽样
    n = 2
    for index, msg in enumerate(files):
        if index % n == 0:
            category = msg[0]
            content = msg[1]
            content = text_parse(content)
            if int(index / n) % 10000 == 0:
                print(
                    '{t} *** {i} \t docs has bean dealed'.format(t=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()),
                                                                 i=index), '\n', category, '\t', content[:20])

    end_time = time.time()
    print('Total Cost Time %.2f' % (end_time - start_time) + 's')

扩展

  • 缺失值处理方法(忽略/人工填值/均值/中位数等)
  • 噪声数据处理方式(向均值光滑、离群点分析等)
  • 正则学习

相关代码:https://gitee.com/tangjinghong/data_process


内容均来源于学习资料,在学习过程中进行记录,如有侵权联系作者进行删除

Change the world by program

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345