基于文本挖掘的企业隐患排查质量分析模型(上)

简介: 基于文本挖掘的企业隐患排查质量分析模型(上)

基于文本挖掘的企业隐患排查质量分析模型


www.sodic.com.cn/competition…


1 赛题名称


基于文本挖掘的企业隐患排查质量分析模型


2 赛题背景


企业自主填报安全生产隐患,对于将风险消除在事故萌芽阶段具有重要意义。企业在填报隐患时,往往存在不认真填报的情况,“虚报、假报”隐患内容,增大了企业监管的难度。采用大数据手段分析隐患内容,找出不切实履行主体责任的企业,向监管部门进行推送,实现精准执法,能够提高监管手段的有效性,增强企业安全责任意识。


3 赛题任务


本赛题提供企业填报隐患数据,参赛选手需通过智能化手段识别其中是否存在“虚报、假报”的情况。


看清赛题很关键,大家需要好好理解赛题目标之后,再去做题,可以避免很多弯路。


4 数据简介


本赛题数据集为脱敏后的企业填报自查隐患记录。


数据说明 训练集数据包含“【id、level_1(一级标准)、level_2(二级标准)、level_3(三级标准)、level_4(四级标准)、content(隐患内容)和label(标签)】”共7个字段。 其中“id”为主键,无业务意义;“一级标准、二级标准、三级标准、四级标准”为《深圳市安全隐患自查和巡查基本指引(2016年修订版)》规定的排查指引,一级标准对应不同隐患类型,二至四级标准是对一级标准的细化,企业自主上报隐患时,根据不同类型隐患的四级标准开展隐患自查工作;“隐患内容”为企业上报的具体隐患;“标签”标识的是该条隐患的合格性,“1”表示隐患填报不合格,“0”表示隐患填报合格。


预测结果文件results.csv

列名 说明
id 企业号
label 正负样本分类
  • 文件名:results.csv,utf-8编码
  • 参赛者以csv/json等文件格式,提交模型结果,平台进行在线评分,实时排名。


5 评测标准


本赛题采用F1 -score作为模型评判标准。


6 赛题解析笔记


1 导入工具包


#  pip install -i https://pypi.tuna.tsinghua.edu.cn/simple transformers
# 导入transformers
import transformers
# from transformers import BertModel, BertTokenizer,BertConfig, AdamW, get_linear_schedule_with_warmup
from transformers import AutoModel, AutoTokenizer,AutoConfig, AdamW, get_linear_schedule_with_warmup
# 导入torch
import torch
from torch import nn, optim
from torch.utils.data import Dataset, DataLoader
import torch.nn.functional as F
# 常用包
import re
import numpy as np
import pandas as pd
import seaborn as sns
from pylab import rcParams
import matplotlib.pyplot as plt
from matplotlib import rc
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report
from collections import defaultdict
from textwrap import wrap
%matplotlib inline
%config InlineBackend.figure_format='retina' # 主题
sns.set(style='whitegrid', palette='muted', font_scale=1.2)
HAPPY_COLORS_PALETTE = ["#01BEFE", "#FFDD00", "#FF7D00", "#FF006D", "#ADFF02", "#8F00FF"]
sns.set_palette(sns.color_palette(HAPPY_COLORS_PALETTE))
rcParams['figure.figsize'] = 12, 8
# 固定随机种子
RANDOM_SEED = 42
np.random.seed(RANDOM_SEED)
torch.manual_seed(RANDOM_SEED)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
device
device(type='cuda', index=0)
torch.cuda.is_available()
True


2 加载数据


train=pd.read_csv('/home/mw/input/task026741/sub.csv')
test=pd.read_csv('/home/mw/input/task026741/test.csv')
sub=pd.read_csv('/home/mw/input/task026741/train.csv')
# train=pd.read_csv('data/02/train.csv')
# test=pd.read_csv('data/02/test.csv')
# sub=pd.read_csv('data/02/sub.csv')
print("train.shape,test.shape,sub.shape",train.shape,test.shape,sub.shape)
train.shape,test.shape,sub.shape (12000, 7) (18000, 6) (18000, 2)
# 查看前三行
train.head(3)
.dataframe tbody tr th:only-of-type {         vertical-align: middle;     } .dataframe tbody tr th {     vertical-align: top; } .dataframe thead th {     text-align: right; }

id level_1 level_2 level_3 level_4 content label
0 0 工业/危化品类(现场)—2016版 (二)电气安全 6、移动用电产品、电动工具及照明 1、移动使用的用电产品和I类电动工具的绝缘线,必须采用三芯(单相)或四芯(三相)多股铜芯橡套软线。 使用移动手动电动工具,外接线绝缘皮破损,应停止使用. 0
1 1 工业/危化品类(现场)—2016版 (一)消防检查 1、防火巡查 3、消防设施、器材和消防安全标志是否在位、完整; 一般 1
2 2 工业/危化品类(现场)—2016版 (一)消防检查 2、防火检查 6、重点工种人员以及其他员工消防知识的掌握情况; 消防知识要加强 0


2.1  查看缺失值


train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 12000 entries, 0 to 11999
Data columns (total 7 columns):
 #   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
 0   id       12000 non-null  int64 
 1   level_1  12000 non-null  object
 2   level_2  12000 non-null  object
 3   level_3  12000 non-null  object
 4   level_4  12000 non-null  object
 5   content  11998 non-null  object
 6   label    12000 non-null  int64 
dtypes: int64(2), object(5)
memory usage: 656.4+ KB
train[train['content'].isna()] # content 非常重要的字段
.dataframe tbody tr th:only-of-type {         vertical-align: middle;     } .dataframe tbody tr th {     vertical-align: top; } .dataframe thead th {     text-align: right;

id level_1 level_2 level_3 level_4 content label
6193 6193 工业/危化品类(现场)—2016版 (一)消防检查 1、防火巡查 3、消防设施、器材和消防安全标志是否在位、完整; NaN 1
9248 9248 工业/危化品类(现场)—2016版 (一)消防检查 1、防火巡查 4、常闭式防火门是否处于关闭状态,防火卷帘下是否堆放物品影响使用; NaN 1
test.info() # 4 条content为空
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 18000 entries, 0 to 17999
Data columns (total 6 columns):
 #   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
 0   id       18000 non-null  int64 
 1   level_1  18000 non-null  object
 2   level_2  18000 non-null  object
 3   level_3  18000 non-null  object
 4   level_4  18000 non-null  object
 5   content  17996 non-null  object
dtypes: int64(1), object(5)
memory usage: 843.9+ KB
print("train null nums")
print(train.shape[0]-train.count())
print("test null nums")
print(test.shape[0]-test.count())
train null nums
id         0
level_1    0
level_2    0
level_3    0
level_4    0
content    2
label      0
dtype: int64
test null nums
id         0
level_1    0
level_2    0
level_3    0
level_4    0
content    4
dtype: int64


2.2 标签分布


tip:NLP所有任务,首先要看下答案或者标签的分布 分类任务,每个类别分布;回归任务,具体数值分布;NER任务,需要标注标签分布。。

train['label'].value_counts()
0    10712
1     1288
Name: label, dtype: int64
sns.countplot(train.label)
plt.xlabel('label count')
Text(0.5, 0, 'label count')

image.png

1288/10712
0.12023898431665422


3 数据预处理


# 填充缺失值
train['content']=train['content'].fillna('空值')
test['content']=test['content'].fillna('空值')
train['level_1']=train['level_1'].apply(lambda x:x.split('(')[0])
train['level_2']=train['level_2'].apply(lambda x:x.split(')')[-1])
train['level_3']=train['level_3'].apply(lambda x:re.split(r'[0-9]、',x)[-1])
train['level_4']=train['level_4'].apply(lambda x:re.split(r'[0-9]、',x)[-1])
test['level_1']=test['level_1'].apply(lambda x:x.split('(')[0])
test['level_2']=test['level_2'].apply(lambda x:x.split(')')[-1])
test['level_3']=test['level_3'].apply(lambda x:re.split(r'[0-9]、',x)[-1])
test['level_4']=test['level_4'].apply(lambda x:re.split(r'[0-9]、',x)[-1])
train
.dataframe tbody tr th:only-of-type {         vertical-align: middle;     } .dataframe tbody tr th {     vertical-align: top; } .dataframe thead th {     text-align: right; }

id level_1 level_2 level_3 level_4 content label
0 0 工业/危化品类 电气安全 移动用电产品、电动工具及照明 移动使用的用电产品和I类电动工具的绝缘线,必须采用三芯(单相)或四芯(三相)多股铜芯橡套软线。 使用移动手动电动工具,外接线绝缘皮破损,应停止使用. 0
1 1 工业/危化品类 消防检查 防火巡查 消防设施、器材和消防安全标志是否在位、完整; 一般 1
2 2 工业/危化品类 消防检查 防火检查 重点工种人员以及其他员工消防知识的掌握情况; 消防知识要加强 0
3 3 工业/危化品类 消防检查 防火巡查 消防设施、器材和消防安全标志是否在位、完整; 消防通道有货物摆放 清理不及时 0
4 4 工业/危化品类 消防检查 防火巡查 常闭式防火门是否处于关闭状态,防火卷帘下是否堆放物品影响使用; 防火门打开状态 0
... ... ... ... ... ... ... ...
11995 11995 商贸服务教文卫类 安全教育培训 员工安全教育 制定安全教育培训计划,确保全员参与培训,并建立安全培训档案。 个别员工对消防栓的使用不熟练\r\n 0
11996 11996 工业/危化品类 电气安全 电气线路及电源插头插座 电源插座、电源插头应按规定正确接线。 化验室超净台照明电源线防护不足,且检测台金属架未安装漏电接地保护线。整改措施:更换照明灯为前... 0
11997 11997 工业/危化品类 机械设备安全防护 人身防护 皮带轮、齿轮、凸轮、曲柄连杆机构等外露的转动和运动部件应有防护罩。 电箱、马达,没有防护罩,现在整改 0
11998 11998 工业/危化品类 作业环境 通风与照明 作业场所通风良好。 D1部车间二楼配胶房排风扇未开启。 0
11999 11999 纯办公场所 消防安全 消防通道 疏散通道无占用、堵塞、封闭等现象。安全出口不得上锁。 已整改 1

12000 rows × 7 columns

# train['text']=train['content']+' '+train['level_1']+' '+train['level_2']+' '+train['level_3']+' '+train['level_4']
# test['text']=test['content']+' '+test['level_1']+' '+test['level_2']+' '+test['level_3']+' '+test['level_4']
train['text']=train['content']+'[SEP]'+train['level_1']+'[SEP]'+train['level_2']+'[SEP]'+train['level_3']+'[SEP]'+train['level_4']
test['text']=test['content']+'[SEP]'+test['level_1']+'[SEP]'+test['level_2']+'[SEP]'+test['level_3']+'[SEP]'+test['level_4']
train.head()
.dataframe tbody tr th:only-of-type {         vertical-align: middle;     } .dataframe tbody tr th {     vertical-align: top; } .dataframe thead th {     text-align: right; }

id level_1 level_2 level_3 level_4 content label text
0 0 工业/危化品类 电气安全 移动用电产品、电动工具及照明 移动使用的用电产品和I类电动工具的绝缘线,必须采用三芯(单相)或四芯(三相)多股铜芯橡套软线。 使用移动手动电动工具,外接线绝缘皮破损,应停止使用. 0 使用移动手动电动工具,外接线绝缘皮破损,应停止使用.[SEP]工业/危化品类[SEP]电气安...
1 1 工业/危化品类 消防检查 防火巡查 消防设施、器材和消防安全标志是否在位、完整; 一般 1 一般[SEP]工业/危化品类[SEP]消防检查[SEP]防火巡查[SEP]消防设施、器材和消...
2 2 工业/危化品类 消防检查 防火检查 重点工种人员以及其他员工消防知识的掌握情况; 消防知识要加强 0 消防知识要加强[SEP]工业/危化品类[SEP]消防检查[SEP]防火检查[SEP]重点工种...
3 3 工业/危化品类 消防检查 防火巡查 消防设施、器材和消防安全标志是否在位、完整; 消防通道有货物摆放 清理不及时 0 消防通道有货物摆放 清理不及时[SEP]工业/危化品类[SEP]消防检查[SEP]防火巡查[...
4 4 工业/危化品类 消防检查 防火巡查 常闭式防火门是否处于关闭状态,防火卷帘下是否堆放物品影响使用; 防火门打开状态 0 防火门打开状态[SEP]工业/危化品类[SEP]消防检查[SEP]防火巡查[SEP]常闭式防...


3.1 文本长度分布


train['text_len']=train['text'].map(len)
train['text'].map(len).describe()# 298-12=286
count    12000.000000
mean        80.439833
std         21.913662
min         43.000000
25%         66.000000
50%         75.000000
75%         92.000000
max        298.000000
Name: text, dtype: float64
test['text'].map(len).describe() # 520-12=518
count    18000.000000
mean        80.762611
std         22.719823
min         43.000000
25%         66.000000
50%         76.000000
75%         92.000000
max        520.000000
Name: text, dtype: float64
train['text_len'].plot(kind='kde')
<AxesSubplot:ylabel='Density'>

image.png

sum(train['text_len']>100) # text文本长度大于100的个数
sum(train['text_len']>200) # text文本长度大于200的个数
11
1878/len(train)
0.1565


4 认识Tokenizer


4.1 将文本映射为id表示


PRE_TRAINED_MODEL_NAME = 'bert-base-chinese'
# PRE_TRAINED_MODEL_NAME = 'hfl/chinese-roberta-wwm-ext'
# PRE_TRAINED_MODEL_NAME = 'hfl/chinese-roberta-wwm'
# tokenizer = BertTokenizer.from_pretrained(PRE_TRAINED_MODEL_NAME)
tokenizer = AutoTokenizer.from_pretrained(PRE_TRAINED_MODEL_NAME)
# tokenizer = BertTokenizer.from_pretrained('C:\\Users\\yanqiang\\Desktop\\bert-base-chinese')
tokenizer
PreTrainedTokenizerFast(name_or_path='bert-base-chinese', vocab_size=21128, model_max_len=512, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'})
  • 可以看到BertTokenizer的词表大小为21128
  • 特殊符号为special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'}

我们尝试使用BertTokenizer进行分词

sample_txt = '今天早上9点半起床,我在学习预训练模型的使用.'
len(sample_txt)
23
tokens = tokenizer.tokenize(sample_txt)
token_ids = tokenizer.convert_tokens_to_ids(tokens)
print(f'文本为: {sample_txt}')
print(f'分词的列表为: {tokens}')
print(f'词对应的唯一id: {token_ids}')
文本为: 今天早上9点半起床,我在学习预训练模型的使用.
分词的列表为: ['今', '天', '早', '上', '9', '点', '半', '起', '床', ',', '我', '在', '学', '习', '预', '训', '练', '模', '型', '的', '使', '用', '.']
词对应的唯一id: [791, 1921, 3193, 677, 130, 4157, 1288, 6629, 2414, 8024, 2769, 1762, 2110, 739, 7564, 6378, 5298, 3563, 1798, 4638, 886, 4500, 119]


4.2 特殊符号


tokenizer.sep_token, tokenizer.sep_token_id
('[SEP]', 102)
tokenizer.unk_token, tokenizer.unk_token_id
('[UNK]', 100)
tokenizer.pad_token, tokenizer.pad_token_id
('[PAD]', 0)
tokenizer.cls_token, tokenizer.cls_token_id
('[CLS]', 101)
tokenizer.mask_token, tokenizer.mask_token_id
('[MASK]', 103)

可以使encode_plus()对句子进行分词,添加特殊符号

encoding=tokenizer.encode_plus(
    sample_txt,
    # sample_txt_another,
    max_length=32,
    add_special_tokens=True,# [CLS]和[SEP]
    return_token_type_ids=True,
    pad_to_max_length=True,
    return_attention_mask=True,
    return_tensors='pt',# Pytorch tensor张量
)
encoding.keys()
Truncation was not explicitly activated but `max_length` is provided a specific value, please use `truncation=True` to explicitly truncate examples to max length. Defaulting to 'longest_first' truncation strategy. If you encode pairs of sequences (GLUE-style) with the tokenizer you can select this strategy more precisely by providing a specific strategy to `truncation`.
F:\ProgramData\Anaconda3\lib\site-packages\transformers\tokenization_utils_base.py:2271: FutureWarning: The `pad_to_max_length` argument is deprecated and will be removed in a future version, use `padding=True` or `padding='longest'` to pad to the longest sequence in the batch, or use `padding='max_length'` to pad to a max length. In this case, you can give a specific length with `max_length` (e.g. `max_length=45`) or leave max_length to None to pad to the maximal input size of the model (e.g. 512 for Bert).
  warnings.warn(
dict_keys(['input_ids', 'token_type_ids', 'attention_mask'])
encoding
{'input_ids': tensor([[ 101,  791, 1921, 3193,  677,  130, 4157, 1288, 6629, 2414, 8024, 2769,
         1762, 2110,  739, 7564, 6378, 5298, 3563, 1798, 4638,  886, 4500,  119,
          102,    0,    0,    0,    0,    0,    0,    0]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         1, 0, 0, 0, 0, 0, 0, 0]])}

token ids的长度为32的张量

print(len(encoding['input_ids'][0]))
32

attention mask具有同样的长度

print(len(encoding['attention_mask'][0]))
encoding['attention_mask']
32
tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
         1, 0, 0, 0, 0, 0, 0, 0]])

我们将ids反转为词语,可以打印下每个字符是什么?

tokenizer.convert_ids_to_tokens(encoding['input_ids'][0])
['[CLS]', '今', '天', '早', '上', '9', '点', '半', '起', '床', ',', '我', '在', '学', '习', '预', '训', '练', '模', '型', '的', '使', '用', '.', '[SEP]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]']


4.2 选取文本最大长度


token_lens = []
for txt in train.text:
    tokens = tokenizer.encode(txt, max_length=512)
    token_lens.append(len(tokens))
sns.distplot(token_lens)
plt.xlim([0, 256]);
plt.xlabel('Token count');
F:\ProgramData\Anaconda3\lib\site-packages\seaborn\distributions.py:2619: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).
  warnings.warn(msg, FutureWarning)

image.png

可以看到大多数文本的ids长度在100以内,我们设置最大长度为160

MAX_LEN = 160


5 构建数据集


5.1 自定义数据集


class EnterpriseDataset(Dataset):
    def __init__(self,texts,labels,tokenizer,max_len):
        self.texts=texts
        self.labels=labels
        self.tokenizer=tokenizer
        self.max_len=max_len
    def __len__(self):
        return len(self.texts)
    def __getitem__(self,item):
        """
        item 为数据索引,迭代取第item条数据
        """
        text=str(self.texts[item])
        label=self.labels[item]
        encoding=self.tokenizer.encode_plus(
            text,
            add_special_tokens=True,
            max_length=self.max_len,
            return_token_type_ids=True,
            pad_to_max_length=True,
            return_attention_mask=True,
            return_tensors='pt',
        )
#         print(encoding['input_ids'])
        return {
            'texts':text,
            'input_ids':encoding['input_ids'].flatten(),
            'attention_mask':encoding['attention_mask'].flatten(),
            # toeken_type_ids:0
            'labels':torch.tensor(label,dtype=torch.long)
        }



目录
相关文章
|
2月前
|
架构师 测试技术
缺陷趋势分析
本文详细解析了累积缺陷发现统计及其在软件测试中的应用,探讨了理想情况下的凹凸曲线变化规律以及不同拐点出现时可能的问题,并提出了相应的调整策略。此外,还讨论了如何判断缺陷收敛及不收敛的情况,并给出了具体对策。这对于软件测试人员来说具有很高的参考价值。
44 3
|
5月前
|
人工智能 安全 定位技术
IT风险管理:识别、评估与缓解的艺术
【6月更文挑战第22天】面对数字化时代的挑战,企业需精通识别、评估与缓解IT风险以保障数字资产安全。本文聚焦风险识别的关键性,使用头脑风暴等工具发现潜在风险;通过概率-影响矩阵等评估风险严重性;并采取加强安全防护、完善制度等措施缓解风险,确保企业稳定运营。持续提升风险管理能力至关重要。
|
5月前
|
机器学习/深度学习 数据采集 算法
基于机器学习的糖尿病风险预警分析系统是一个非常有用的应用
基于机器学习的糖尿病风险预警分析系统是一个非常有用的应用
65 1
|
4月前
|
传感器 数据采集 存储
在环境治理领域,污染治理系统工程旨在通过系统的方法来解决环境污染问题。这通常包括污染源的识别、污染物的监测、治理技术的选择、治理效果的评估等多个环节。
在环境治理领域,污染治理系统工程旨在通过系统的方法来解决环境污染问题。这通常包括污染源的识别、污染物的监测、治理技术的选择、治理效果的评估等多个环节。
|
6月前
|
监控 测试技术
深入分析软件测试中的风险评估与管理
【5月更文挑战第30天】 在软件开发生命周期中,风险无处不在,特别是在软件测试阶段。本文旨在探讨软件测试过程中如何有效地进行风险评估和管理,以确保软件质量和项目成功。文中将介绍风险评估的基本概念,提出一个结构化的风险识别和评估框架,并详细讨论如何通过定性和定量方法来管理测试风险。此外,文章还将展示一个案例研究,以说明所提策略在实际中的应用效果。
|
测试技术
如何评估软件测试的质量风险?记住这5个核心关键点
如何评估软件测试的质量风险?记住这5个核心关键点
320 0
|
机器学习/深度学习 数据采集 数据处理
如何做一个诊断系统
如何做一个诊断系统
142 0
|
运维
《智能运维里的时间序列:异常检测、根源分析、预测》电子版地址
智能运维里的时间序列:异常检测、根源分析、预测
240 0
《智能运维里的时间序列:异常检测、根源分析、预测》电子版地址
基于文本挖掘的企业隐患排查质量分析模型(下)
基于文本挖掘的企业隐患排查质量分析模型(下)
104 0
基于文本挖掘的企业隐患排查质量分析模型(下)
|
人工智能 大数据 云计算
测试-风险甄别
测试-风险甄别