使用nlp分析事故报告

数据挖掘 机器学习 nlp
2022-02-10 21:08:37

我想使用自然语言处理来分析交通事故报告并从文本中确定两件事:

  1. 车辆行驶方向(只是指南针方向,如北、东南等)
  2. 车辆运动描述(例如倒车、红灯左转、交通停止、右转、停车)。

事故报告叙述的片段如下所示:

TU2 停在 Main St 的西侧,面向西,发动机关闭。TU1 停在 Main St 的东侧,朝东,驶出停车位,向后行驶。TU1 的后部与 TU2 的后部相撞。当 TU1 追尾时,TU2 仍处于发动机关闭状态。

事故报告保存在数千份文件中,一个城市一年内的所有事故报告都在一个文件中。提供车辆行驶方向和运动描述的“答案”(标签)以及事故报告的叙述。所以我有一个不错的训练数据集。

我正在考虑从一个方法开始,比如一个 n-gram 词袋和一个简单的车辆方向分类器(北、西南等)。那会是一个好的开始吗?

3个回答

首先,我希望标签要么是简短的摘要,要么是长度不一的词,而不仅仅是一个词的方向。因为发生事故的移动汽车可能有多个方向,或者像示例中那样只停放一辆车。

其次,鉴于您计划预测不同长度的标签,并给出示例文本,我很确定词袋不会很好地工作。你需要上下文。而且你没有百万大小的训练集来训练一个 Transformer 深度神经网络。因此,请尝试使用预训练的嵌入,如 USE、GloVe 等。如果您正在使用嵌入,它可以为您提供出色的特征工程。只需在(标签,嵌入)上训练一些低复杂度模型,例如随机森林/ xgboost。您还可以探索预训练的摘要生成器,例如 bertseq2seq,但是我的代码还不适合我。

如果你想生成一个 n-gram,你可以使用一个简单的 python fctn:

def ngram(tokens, n):
  grams = []
  for i in range(len(tokens) - n + 1):
    grams.append(tokens[i:i+n])
  return grams
sent = 'hi i am fred fred burger :)'
bigrams = ngram(sent.split(), 2)

对于数据处理,您可以单独嵌入每个 gram(如果您想使用某种形式的逻辑回归或类似的方式继续前进,只需持有一个 dict {gram : index}。然后您可以在您喜欢的任何框架中编写模型。我推荐作为使用 keras 的初学者,因为逻辑模型将是 2 行,然后在该抽象级别扩展到更多模型会容易得多。此外,他们有很多预处理工具可以帮助您(用于填充等)

如果我对您的理解正确,您的问题是如何将您的数据放入模型中?这是一个使用 R 的简短示例。该图显示了当我将数据读入 R 时数据的格式。它是一列,包含(label将是你的y)和一列包含event做一个词袋)。确保文本为小写且不包含特殊字符。也许删除停用词,做词干或修剪你的词汇。我的文本格式适合我的任务。

在此处输入图像描述

在 R 中,您可以将列声明type为一个因子并将该因子插入回归模型中。或者,您可以简单地将类型“重新编码”为数字,例如0=accident1=crash(等)。任何模型都应该能够消化这些数字,这些数字表明您要预测的“类别”。不要忘记将数据拆分为训练集和测试集。

下一步是生成一袋单词或 n-gram event(我认为根据在线示例这对您来说应该是可行的)。

一旦你有了你的标签 ( y) 和你的词袋 ( x),你就可以从一些模型开始。在另一个答案中,提出了一个 Keras 模型。我认为这是一种选择,但可能是一个设计过度的解决方案。另一种方法是使用带有正则化(套索或山脊)的“正常”Logit。套索/岭的原因是,如果特征(也就是你的词袋中的列)对良好的预测贡献不大,它们会自动“缩小”。这通常会提高合身性。

估计很简单,使用glmnet

library(glmnet)
# Fit model to training set
cv_fit <- cv.glmnet(x = dtm_train, y = train[['type']],
                    nfolds = 5,
                    type.measure = "class",
                    alpha=1,  # 1=Lasso / 0=Ridge 
                    grouped = FALSE,
                    family = "multinomial")  # I have 4 classes

# Plot CV results for parameter lambda
plot(cv_fit)

# Get best lambda
bestlam = cv_fit$lambda.min

# Predict classes
classes = predict(cv_fit, newx=dtm_test, s=bestlam, type="class") 

# Look at results
table(classes, test[['type']])

您首先“调整”参数 lamda CV你得到的是一个不错的数字和一个最佳的 lambda。

在此处输入图像描述

接下来,您可以预测类并查看结果:

classes    Accident Crash Incident Report
  Accident      142     5       23      5
  Crash           2     9        0      0
  Incident       64     5     1697     29
  Report          8     1       11      1

好吧,这只是我的一个疯狂的例子(没有微调)。但是,如果您检查不同的 alpha 值[0,1],您的任务可能会得到不错的结果。

这是 R 的一个很好的指南glmnet和一些文档。顺便说一下,你可以在Python中做同样的事情。