【数据科学项目02】:NLP应用之垃圾短信 邮件检测(端到端的项目)_短消息分析 nlp

#1.字符数
df['char']=df['message'].apply(len)

nltk.download('punkt')

[nltk_data] Downloading package punkt to /root/nltk_data...
[nltk_data]   Unzipping tokenizers/punkt.zip.

True

#2.单词数,这里我们首先要对其进行分词处理,使用nltk
#分词处理
df['words']=df['message'].apply(lambda x: len(nltk.word_tokenize(x)))

# 3.句子数
df['sen']=df['message'].apply(lambda x: len(nltk.sent_tokenize(x)))

df.head()

labelmessagecharwordssen
00Go until jurong point, crazy… Available only …111242
10Ok lar… Joking wif u oni…2982
21Free entry in 2 a wkly comp to win FA Cup fina…155372
30U dun say so early hor… U c already then say…49131
40Nah I don’t think he goes to usf, he lives aro…61151

描述性统计

# 描述性统计
df.describe()

indexlabelcharwordssen
count5572.05572.05572.05572.0
mean0.1340631730078966480.1188083273510518.695620961952621.9707465900933239
std0.3407507548977697459.690840776503313.7425868017449751.4177777134026657
min0.02.01.01.0
25%0.036.09.01.0
50%0.061.015.01.0
75%0.0121.027.02.0
max1.0910.0220.028.0

下面我们通过可视化比较一下不同短信在这些数字特征上的分布情况

# 字符数比较
plt.figure(figsize=(12,6))
sns.histplot(df[df['label']==0]['char'],color='red')#正常短信
sns.histplot(df[df['label']==1]['char'],color = 'blue')#垃圾短信

<matplotlib.axes._subplots.AxesSubplot at 0x7fce63763dd0>

png

# 比较
plt.figure(figsize=(12,6))
sns.histplot(df[df['label']==0]['words'],color='red')#正常短信
sns.histplot(df[df['label']==1]['words'],color = 'blue')#垃圾短信

<matplotlib.axes._subplots.AxesSubplot at 0x7fce63f4bed0>


png

sns.pairplot(df,hue='label')

在这里插入图片描述

#删除数据集中存在的一些异常值
i=df[df['char']>500].index
df.drop(i,axis=0,inplace=True)

df=df.reset_index()
df.drop("index",inplace=True,axis=1)

#相关系数矩阵
sns.heatmap(df.corr(),annot=True)

<matplotlib.axes._subplots.AxesSubplot at 0x7fce606d0250>

output_34_1

我们这里看到存在多重共线性,因此,我们不使用所有的列,在这里选择与label相关性最强的char

3.数据预处理

对于英文文本数据,我们常用的数据预处理方式如下

  • 去除标点符号
  • 去除停用词
  • 去除专有名词
  • 变换成小写
  • 分词处理
  • 词根、词缀处理

下面我们来看看如何实现这些步骤

nltk.download('stopwords')

[nltk_data] Downloading package stopwords to /root/nltk_data...
[nltk_data]   Unzipping corpora/stopwords.zip.

True

# 首先导入需要使用到的包
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
from wordcloud import WordCloud
import string,time

# 标点符号
string.punctuation

'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'

# 停用词
stopwords.words('english')

3.1清洗文本数据

  • 去除web链接
  • 去除邮件
  • 取掉数字

下面使用正则表达式来处理这些数据。

def remove\_website\_links(text):
    no_website_links = text.replace(r"http\S+", "")#去除网络连接
    return no_website_links

def remove\_numbers(text):
    removed_numbers = text.replace(r'\d+','')#去除数字
    return removed_numbers

def remove\_emails(text):
    no_emails = text.replace(r"\S\*@\S\*\s?",'')#去除邮件
    return no_emails

df['message'] = df['message'].apply(remove_website_links)
df['message'] = df['message'].apply(remove_numbers)
df['message'] = df['message'].apply(remove_emails)

df.head()

labelmessagecharwordssen
00Go until jurong point, crazy… Available only …111242
10Ok lar… Joking wif u oni…2982
21Free entry in 2 a wkly comp to win FA Cup fina…155372
30U dun say so early hor… U c already then say…49131
40Nah I don’t think he goes to usf, he lives aro…61151

3.2 文本特征转换

def message\_transform(text):
  
  text = text.lower()#转换为小写
  
  text = nltk.word_tokenize(text)#分词处理
  
  # 去除停用词和标点
  y = []#创建一个空列表
  for word in text:
    stopwords_punc = stopwords.words('english')+list(string.punctuation)#存放停用词和标点
    if word.isalnum()==True and word not in stopwords_punc:
      y.append(word)
  
  # 词根变换
  message=y[:]
  y.clear()
  for i in message:
    ps=PorterStemmer()
    y.append(ps.stem(i))
  return " ".join(y)#返回字符串形式

df['message'] = df['message'].apply(message_transform)
df['num\_words\_transform']=df['message'].apply(lambda x: len(str(x).split()))

df.head()

labelmessagecharwordssen
00Go until jurong point, crazy… Available only …111242
10Ok lar… Joking wif u oni…2982
21Free entry in 2 a wkly comp to win FA Cup fina…155372
30U dun say so early hor… U c already then say…49131
40Nah I don’t think he goes to usf, he lives aro…61151

4.词频统计

4.1绘制词云

#绘制信息中出现最多的词的词云
from wordcloud import WordCloud
#首先,创建一个object
wc=WordCloud(width=500,height=500,min_font_size=10,background_color='white')

# 垃圾信息的词云
spam_wc=wc.generate(df[df['label']==1]['message'].str.cat(sep=""))

plt.figure(figsize=(18,12))
plt.imshow(spam_wc)

<matplotlib.image.AxesImage at 0x7fce5d938710>

output_53_1

可以看出,这些垃圾邮件出现频次最多的单词是:free、call等这种具有诱导性的信息

# 正常信息的词云
ham_wc = wc.generate(df[df['label']==0]['message'].str.cat(sep=''))
plt.figure(figsize=(18,12))
plt.imshow(ham_wc)

<matplotlib.image.AxesImage at 0x7fce607af190>

output_55_1

可以看出正常信息出现频次较多的单词为u、go、got、want等一些传达信息的单词

为了简化词云图的信息,我们现在分别统计垃圾短信和正常短信频次top30的单词

4.2找出词数top30的单词

垃圾短信:

# 统计词频
spam_corpus=[]
for i in df[df['label']==1]['message'].tolist():
  for word in i.split():
        spam_corpus.append(word)


from collections import Counter
Counter(spam_corpus)#记数
Counter(spam_corpus).most_common(30)#取最多的30个单词
plt.figure(figsize=(10,7))
sns.barplot(y=pd.DataFrame(Counter(spam_corpus).most_common(30))[0],x=pd.DataFrame(Counter(spam_corpus).most_common(30))[1])
plt.xticks()
plt.xlabel("Frequnecy")
plt.ylabel("Spam Words")
plt.show()

output_61_0

正常短信

ham_corpus=[]
for i in df[df['label']==0]['message'].tolist():
  for word in i.split():
    ham_corpus.append(word)

from collections import Counter
plt.figure(figsize=(10,7))
sns.barplot(y=pd.DataFrame(Counter(ham_corpus).most_common(30))[0],x=pd.DataFrame(Counter(ham_corpus).most_common(30))[1])
plt.xticks()
plt.xlabel("Frequnecy")
plt.ylabel("Ham Words")
plt.show()

output_64_0

下面进一步分析垃圾短信和非垃圾短信的单词和字符数分布情况

# 字符数
fig,(ax1,ax2)=plt.subplots(1,2,figsize=(15,6))
text_len=df[df['label']==1]['text'].str.len()
ax1.hist(text_len,color='green')
ax1.set_title('Original text')
text_len=df[df['label']==0]['text'].str.len()
ax2.hist(text_len,color='red')
ax2.set_title('Fake text')
fig.suptitle('Characters in texts')
plt.show()

在这里插入图片描述

#单词数
fig,(ax1,ax2)=plt.subplots(1,2,figsize=(15,6))
text_len=df[df['label']==1]['num\_words\_transform']
ax1.hist(text_len,color='red')
ax1.set_title('Original text')
text_len=df[df['label']==0]['num\_words\_transform']
ax2.hist(text_len,color='green')
ax2.set_title('Fake text')
fig.suptitle('Words in texts')
plt.show()

在这里插入图片描述

总结
经过上面分析,我们可以得出结论,垃圾短信文本与非垃圾短信文本相比具有更多的单词和字符。

  • 垃圾短信中包含的平均字符数约为 90 个字符
  • 垃圾短信中包含的平均字数约为 15 个字

5.模型构建

根据历史经验,在文本数据上朴素贝叶斯算法效果很好,因此我们将使用它,但在此过程中还将它与不同的算法进行比较。
在统计学中,朴素贝叶斯分类器是一系列简单的“概率分类器”,它们基于应用贝叶斯定理和特征之间的(朴素)条件独立假设。它们是最简单的贝叶斯网络模型之一,但与核密度估计相结合,它们可以达到更高的准确度水平。

image-20220823233043973

首先,我们这里的输入数据是文本数据,不能够直接建立模型。因此,我们必须将这些文本数据进行特征提取。比较常用的几种方法:

  • 词袋模型(Bag of words) 存在稀疏性问题
  • TF-IDF
  • Word2vec

因为是实战训练,在这里不具体展开的几种方法的原理,在这里我选择TF-IDF

image-20220823233013280

我也试了一下Word embedding,结合一些深度学习的方法,精度能够有所提高,感兴趣的小伙伴可以自己尝试一下,基本步骤类似。下面我们首先建立贝叶斯模型。

5.1 构建贝叶斯模型

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer(max_features=3000)

X = tfidf.fit_transform(df['message']).toarray()
y = df['label'].values

array([0, 0, 1, ..., 0, 0, 0])

from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=2)#训练集测试集划分


from sklearn.naive_bayes import GaussianNB,MultinomialNB,BernoulliNB
from sklearn.metrics import accuracy_score,confusion_matrix,precision_score


这里我们比较三种不同的贝叶斯模型的各个评估指标结果

#GaussianNB
gnb = GaussianNB()
gnb.fit(X_train,y_train)
y_pred1 = gnb.predict(X_test)
print("Accuracy Score -",accuracy_score(y_test,y_pred1))
print("Precision Score -",precision_score(y_test,y_pred1))
print(confusion_matrix(y_test,y_pred1))

Accuracy Score - 0.8456014362657092
Precision Score - 0.47038327526132406
[[807 152]
 [ 20 135]]

#MultinomialNB
mnb = MultinomialNB()
mnb.fit(X_train,y_train)
y_pred2 = mnb.predict(X_test)
print("Accuracy Score -",accuracy_score(y_test,y_pred2))
print("Precision Score -",precision_score(y_test,y_pred2))
print(confusion_matrix(y_test,y_pred2))

Accuracy Score - 0.9793536804308797
Precision Score - 0.9925373134328358

[[958   1]
 [ 22 133]]

#Bernuli
bnb = BernoulliNB()
bnb.fit(X_train,y_train)
y_pred3 = bnb.predict(X_test)
print("Accuracy Score -",accuracy_score(y_test,y_pred3))
print("Precision Score -",precision_score(y_test,y_pred3))
print(confusion_matrix(y_test,y_pred3))

Accuracy Score - 0.9829443447037702
Precision Score - 1.0
[[959   0]
 [ 19 136]]

从上述结果来看,我选择了BNB来建模

5.2 模型比较

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

t(X_test)
print(“Accuracy Score -”,accuracy_score(y_test,y_pred3))
print(“Precision Score -”,precision_score(y_test,y_pred3))
print(confusion_matrix(y_test,y_pred3))



Accuracy Score - 0.9829443447037702
Precision Score - 1.0
[[959 0]
[ 19 136]]


从上述结果来看,我选择了BNB来建模


### 5.2 模型比较


[外链图片转存中...(img-fPgrBKCt-1714736182385)]
[外链图片转存中...(img-75dA2830-1714736182386)]
[外链图片转存中...(img-l0ZpxKUE-1714736182386)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值