【NLP实战】基于Bert和双向LSTM的情感分类【上篇】

文章目录

  • 前言
  • 简介
  • 数据获取与提取
  • 数据清洗
    • 读取数据,查看数据
    • 清洗训练集
      • 观察数据分布
      • 去除空数据
      • 去除重复数据
      • 关于去除停用词
      • 关于特殊符号
      • 储存清洗后的数据集
    • 清洗测试集
      • 观察数据分布
      • 去除空数据
      • 去除重复数据(并储存)
    • 清洗验证集
      • 观察数据分布
      • 去除空行
      • 去除重复数据(并储存)
  • 总结
  • 代码汇总

前言

最近自己找了个实验做,写了很多实验记录和方法,现在我将它们整理成文章,希望能对不熟悉NLP的伙伴们起到些许帮助。如有疑问请及时联系作者。

博主page:issey的博客 - 愿无岁月可回首

本系列文章中不会说明环境和包如何安装,这些应该是最基础的东西,可以自己边查边安装。

许多函数用法等在代码里有详细解释,但还是希望各位去看它们的官方文档,我的代码还有很多可以改进的方法,需要的函数等在官方文档都有说明。

简介

本系列将带领大家从数据获取、数据清洗、模型构建、训练,观察loss变化,调整超参数再次训练,并最后进行评估整一个过程。我们将获取一份公开竞赛中文数据,并一步步实验,到最后,我们的评估可以达到排行榜13位的位置。但重要的不是排名,而是我们能在其中学到很多。

本系列将分为三篇文章,分别是:

  • 上篇:数据获取,数据分割与数据清洗
  • 中篇:模型构建,改进pytorch结构,开始第一次训练
  • 下篇:测试与评估,绘图与过拟合,超参数调整

本文为该系列第一篇文章,在本文中,我们将一同观察原始数据,进行数据清洗。样本是很重要的一个部分,学会观察样本并剔除一些符合特殊条件的样本,对模型在学习时有很大的帮助。

数据获取与提取

数据来源:Weibo nCoV Data | Kaggle

竞赛官网:疫情期间网民情绪识别 竞赛 - DataFountain

关于kaggle如何下载数据,本文不再赘述。

为了把数据分割也作为我们实验的一部分,假设我们现在拿到的nCoV_100k_train.labled.csv就是我们爬取到的原始数据。

先来看看我们用到的数据长什么样。

思考:

  • 我们只需要text和情感倾向的列,其他列都不需要。
  • 分割数据时,训练集:测试集:验证集 = 6:2:2。这只是博主自己选择的比例,各位可以自行调整。

编写代码。这部分比较简单,就不一步步运行了,但是各位应该逐行运行观察变化,写文章不能像jupyter notebook那样一行行运行,为了方便起见,文章涉及的代码都将以块状给出。但是运行实际上很多都是逐行调整的。

数据获取.py

import pandas as pd
from sklearn.model_selection import train_test_split

# todo: 读取数据
df = pd.read_csv('./data/archive/nCoV_100k_train.labled.csv')
print(df)
# 只要text和标签
df = df[['微博中文内容', '情感倾向']]
df = df.rename(columns={'微博中文内容': 'text', '情感倾向': 'label'})
print(df)

# todo: 分割数据集,储存.0.6/0.2/0.2
train, test = train_test_split(df, test_size=0.2)
train, val = train_test_split(train, test_size=0.25)
print(train)
print(test)
print(val)
train.to_csv('./data/archive/train.csv', index=None)
val.to_csv('./data/archive/val.csv', index=None)
test.to_csv('./data/archive/test.csv', index=None)

运行结束后,这三个文件就是我们需要的文件。

数据清洗

我的清洗思路来源于这篇:Emotion analysis and Classification using LSTM 93% | Kaggle

该部分需要的库:

  • seaborn:一个适合数据分析的绘图库,需要matplotlib作为前置库

读取数据,查看数据

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# todo:读取数据
df_train = pd.read_csv('./data/archive/train.csv')
df_test = pd.read_csv('./data/archive/test.csv')
df_val = pd.read_csv('./data/archive/val.csv')

# 输出前5行
print(df_train.head())
print(df_train.shape)

print(df_test.head())
print(df_test.shape)

print(df_val.head())
print(df_val.shape)

输出:

清洗训练集

观察数据分布

# todo: 清洗Train
# 观察数据是否平衡
print(df_train.label.value_counts())
print(df_train.label.value_counts() / df_train.shape[0] * 100)
plt.figure(figsize=(8, 4))
sns.countplot(x='label', data=df_train)
plt.show()

可以发现,-2.0,9.0,10.0都只有一个样本,当作异常数据处理,我选择直接丢掉不要。

另外,这个样本分布略微存在分布不平衡imbalance的情况,至于要不要用smote等方法过采样,暂时先不进行讨论,我们暂时保持数据不变。

print(df_train[df_train.label > 5.0])
print(df_train[(df_train.label < -1.1)])
# 丢掉异常数据
df_train.drop(df_train[(df_train.label < -1.1) | (df_train.label > 5)].index, inplace=True, axis=0)
df_train.reset_index(inplace=True, drop=True)
print(df_train.label.value_counts())
sns.countplot(x='label', data=df_train)
plt.show()

去除空数据

# 观察是否有空行
print(df_train.isnull().sum())
# 删除空行数据
df_train.dropna(axis=0, how='any', inplace=True)
df_train.reset_index(inplace=True, drop=True)
print(df_train.isnull().sum())

去除重复数据

# 查看重复数据
print(df_train.duplicated().sum())
# print(df_train[df_train.duplicated()==True])
# 删除重复数据
index = df_train[df_train.duplicated() == True].index
df_train.drop(index, axis=0, inplace=True)
df_train.reset_index(inplace=True, drop=True)
print(df_train.duplicated().sum())

然后我们还需要去除text一样但是label不一样的数据。

# 我们还需要关心的重复数据是text一样但是label不一样的数据。
print(df_train['text'].duplicated().sum())
print(df_train[df_train['text'].duplicated() == True])
# 查看例子
print(df_train[df_train['text'] == df_train.iloc[856]['text']])
print(df_train[df_train['text'] == df_train.iloc[3096]['text']])

# 去掉text一样但是label不一样的数据
index = df_train[df_train['text'].duplicated() == True].index
df_train.drop(index, axis=0, inplace=True)
df_train.reset_index(inplace=True, drop=True)
# 检查
print(df_train['text'].duplicated().sum())  # 0

关于去除停用词

去不去除停用词和构建word embedding选择的方法有关,去查了一下,使用Bert构建时,不需要去除停用词处理,否则还会丢失上下文。于是这里没有进一步去除停用词。

问题解答:nlp - Is it necessary to do stopwords removal ,Stemming/Lemmatization for text classification while using Spacy,Bert? - Stack Overflow

关于特殊符号

观察我们现在的数据:

很容易发现里面有特殊字符。

待会儿用到的bert,它会用到一个中文字典,这个字典是它自己有的,如果出现字典里没有的字符,它会自动替换成[UNK],所以不用管。

储存清洗后的数据集

df_train.to_csv('./data/archive/train_clean.csv', index=None)

清洗测试集

整体步骤和清洗训练集的一样。这里为了巩固处理思路,自己还是详细做一遍吧。

观察数据分布

# 观察数据是否平衡
print(df_test.label.value_counts())
print(df_test.label.value_counts() / df_test.shape[0] * 100)
plt.figure(figsize=(8, 4))
sns.countplot(x='label', data=df_test)
plt.show()

输出就不放了,放个图。

没有特殊label,不用进行去除的操作。

哦对,执行时可以把上面清洗train的代码注释了,用不着重新跑。

去除空数据

# 观察是否有空行
print(df_test.isnull().sum())
# 删除空行数据
df_test.dropna(axis=0, how='any', inplace=True)
df_test.reset_index(inplace=True, drop=True)
print(df_test.isnull().sum())

去除重复数据(并储存)

# 查看重复数据
print(df_test.duplicated().sum())
# print(df_test[df_test.duplicated()==True])
# 删除重复数据
index = df_test[df_test.duplicated() == True].index
df_test.drop(index, axis=0, inplace=True)
df_test.reset_index(inplace=True, drop=True)
print(df_test.duplicated().sum())

# 重复数据是text一样但是label不一样的数据。
print(df_test['text'].duplicated().sum())
print(df_test[df_test['text'].duplicated() == True])
# 查看例子
# print(df_test[df_test['text'] == df_test.iloc[2046]['text']])
# print(df_test[df_test['text'] == df_test.iloc[3132]['text']])
# 去掉text一样但是label不一样的数据
index = df_test[df_test['text'].duplicated() == True].index
df_test.drop(index, axis=0, inplace=True)
df_test.reset_index(inplace=True, drop=True)
# 检查
print(df_test['text'].duplicated().sum())  # 0
# print(df_test)
# 检查形状与编号
print(df_test.tail())
print(df_test.shape)
df_test.to_csv('./data/archive/test_clean.csv', index=None)

有的注释可以打开自己看着调。

清洗验证集

观察数据分布

# 观察数据是否平衡
print(df_val.label.value_counts())
print(df_val.label.value_counts() / df_val.shape[0] * 100)
plt.figure(figsize=(8, 4))
sns.countplot(x='label', data=df_val)
plt.show()

有三个取值我们需要剔除。

# 丢掉异常数据
df_val.drop(df_val[(df_val.label == '4') |
                   (df_val.label == '-') |
                   (df_val.label == '·')].index, inplace=True, axis=0)
df_val.reset_index(inplace=True, drop=True)
print(df_val.label.value_counts())
sns.countplot(x='label', data=df_val)
plt.show()

去除空行

# 观察是否有空行
print(df_val.isnull().sum())
# 删除空行数据
df_val.dropna(axis=0, how='any', inplace=True)
df_val.reset_index(inplace=True, drop=True)
print(df_val.isnull().sum())

去除重复数据(并储存)

# 查看重复数据
print(df_val.duplicated().sum())
# print(df_val[df_val.duplicated()==True])
# 删除重复数据
index = df_val[df_val.duplicated() == True].index
df_val.drop(index, axis=0, inplace=True)
df_val.reset_index(inplace=True, drop=True)
print(df_val.duplicated().sum())

# 重复数据是text一样但是label不一样的数据。
print(df_val['text'].duplicated().sum())
# print(df_val[df_val['text'].duplicated() == True])
# 查看例子
# print(df_val[df_val['text'] == df_val.iloc[1817]['text']])
# print(df_val[df_val['text'] == df_val.iloc[2029]['text']])
# 去掉text一样但是label不一样的数据
index = df_val[df_val['text'].duplicated() == True].index
df_val.drop(index, axis=0, inplace=True)
df_val.reset_index(inplace=True, drop=True)
# 检查
print(df_val['text'].duplicated().sum())  # 0
# print(df_val)
# 检查形状与编号
print(df_val.tail())
print(df_val.shape)
df_val.to_csv('./data/archive/val_clean.csv', index=None)

总结

到此为止,我们已经清洗好了数据。让我们来看看在本次清洗时,忽略了哪些在其他实验中可以继续改进的地方:

  • 本次清洗没有去除停用词,因为使用bert时去除停用词可能会丢失上下文。
  • 本次清洗没有去除特殊字符,因为bert会自动将未知字符转化为[UKN]
  • 本次没有对样本进行过采样/欠采样来解决imbalance问题,这个问题留到评估模型后再考虑要不要讨论。

下一篇文章中,我们将会使用Pytorch搭建Bert和双向LSTM实现多分类。

代码汇总

数据清洗.py

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# todo:读取数据
df_train = pd.read_csv('./data/archive/train.csv')
df_test = pd.read_csv('./data/archive/test.csv')
df_val = pd.read_csv('./data/archive/val.csv')

# 输出前5行
# print(df_train.head())
# print(df_train.shape)

# print(df_test.head())
# print(df_test.shape)

# print(df_val.head())
# print(df_val.shape)

# todo: 清洗Train
# 观察数据是否平衡
# print(df_train.label.value_counts())
# print(df_train.label.value_counts() / df_train.shape[0] * 100)
# plt.figure(figsize=(8, 4))
# sns.countplot(x='label', data=df_train)
# plt.show()
# print(df_train[df_train.label > 5.0])
# print(df_train[(df_train.label < -1.1)])
# 丢掉异常数据
df_train.drop(df_train[(df_train.label < -1.1) | (df_train.label > 5)].index, inplace=True, axis=0)
df_train.reset_index(inplace=True, drop=True)
# print(df_train.label.value_counts())
# sns.countplot(x='label', data=df_train)
# plt.show()

# 观察是否有空行
# print(df_train.isnull().sum())
# 删除空行数据
df_train.dropna(axis=0, how='any', inplace=True)
df_train.reset_index(inplace=True, drop=True)
# print(df_train.isnull().sum())

# 查看重复数据
# print(df_train.duplicated().sum())
# print(df_train[df_train.duplicated()==True])
# 删除重复数据
index = df_train[df_train.duplicated() == True].index
df_train.drop(index, axis=0, inplace=True)
df_train.reset_index(inplace=True, drop=True)
# print(df_train.duplicated().sum())

# 我们还需要关心的重复数据是text一样但是label不一样的数据。
# print(df_train['text'].duplicated().sum())
# print(df_train[df_train['text'].duplicated() == True])
# 查看例子
# print(df_train[df_train['text'] == df_train.iloc[856]['text']])
# print(df_train[df_train['text'] == df_train.iloc[3096]['text']])
# 去掉text一样但是label不一样的数据
index = df_train[df_train['text'].duplicated() == True].index
df_train.drop(index, axis=0, inplace=True)
df_train.reset_index(inplace=True, drop=True)
# 检查
# print(df_train['text'].duplicated().sum())  # 0
# print(df_train)
# 检查形状与编号
print("======train-clean======")
print(df_train.tail())
print(df_train.shape)
df_train.to_csv('./data/archive/train_clean.csv', index=None)

# todo: 清洗test
# 观察数据是否平衡
# print(df_test.label.value_counts())
# print(df_test.label.value_counts() / df_test.shape[0] * 100)
# plt.figure(figsize=(8, 4))
# sns.countplot(x='label', data=df_test)
# plt.show()
# 观察是否有空行
# print(df_test.isnull().sum())
# 删除空行数据
df_test.dropna(axis=0, how='any', inplace=True)
df_test.reset_index(inplace=True, drop=True)
# print(df_test.isnull().sum())
# 查看重复数据
# print(df_test.duplicated().sum())
# print(df_test[df_test.duplicated()==True])
# 删除重复数据
index = df_test[df_test.duplicated() == True].index
df_test.drop(index, axis=0, inplace=True)
df_test.reset_index(inplace=True, drop=True)
# print(df_test.duplicated().sum())
# 重复数据是text一样但是label不一样的数据。
# print(df_test['text'].duplicated().sum())
# print(df_test[df_test['text'].duplicated() == True])
# 查看例子
# print(df_test[df_test['text'] == df_test.iloc[2046]['text']])
# print(df_test[df_test['text'] == df_test.iloc[3132]['text']])
# 去掉text一样但是label不一样的数据
index = df_test[df_test['text'].duplicated() == True].index
df_test.drop(index, axis=0, inplace=True)
df_test.reset_index(inplace=True, drop=True)
# 检查
# print(df_test['text'].duplicated().sum())  # 0
# print(df_test)
# 检查形状与编号
print("======test-clean======")
print(df_test.tail())
print(df_test.shape)
df_test.to_csv('./data/archive/test_clean.csv', index=None)

# todo: 清洗验证集
# 观察数据是否平衡
# print(df_val.label.value_counts())
# print(df_val.label.value_counts() / df_val.shape[0] * 100)
# plt.figure(figsize=(8, 4))
# sns.countplot(x='label', data=df_val)
# plt.show()
# 丢掉异常数据
df_val.drop(df_val[(df_val.label == '4') |
                   (df_val.label == '-') |
                   (df_val.label == '·')].index, inplace=True, axis=0)
df_val.reset_index(inplace=True, drop=True)
# print(df_val.label.value_counts())
# sns.countplot(x='label', data=df_val)
# plt.show()

# 观察是否有空行
# print(df_val.isnull().sum())
# 删除空行数据
df_val.dropna(axis=0, how='any', inplace=True)
df_val.reset_index(inplace=True, drop=True)
# print(df_val.isnull().sum())

# 查看重复数据
# print(df_val.duplicated().sum())
# print(df_val[df_val.duplicated()==True])
# 删除重复数据
index = df_val[df_val.duplicated() == True].index
df_val.drop(index, axis=0, inplace=True)
df_val.reset_index(inplace=True, drop=True)
# print(df_val.duplicated().sum())

# 重复数据是text一样但是label不一样的数据。
print(df_val['text'].duplicated().sum())
# print(df_val[df_val['text'].duplicated() == True])
# 查看例子
# print(df_val[df_val['text'] == df_val.iloc[1817]['text']])
# print(df_val[df_val['text'] == df_val.iloc[2029]['text']])
# 去掉text一样但是label不一样的数据
index = df_val[df_val['text'].duplicated() == True].index
df_val.drop(index, axis=0, inplace=True)
df_val.reset_index(inplace=True, drop=True)
# 检查
print(df_val['text'].duplicated().sum())  # 0
# print(df_val)
# 检查形状与编号
print("======val-clean======")
print(df_val.tail())
print(df_val.shape)
df_val.to_csv('./data/archive/val_clean.csv', index=None)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/16674.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

16.基于主从博弈理论的共享储能与综合能源微网优化运行研究

说明书 MATLAB代码&#xff1a;基于主从博弈理论的共享储能与综合能源微网优化运行研究 关键词&#xff1a;主从博弈 共享储能 综合能源微网 优化调度 参考文档&#xff1a;《基于主从博弈理论的共享储能与综合能源微网优化运行研究》完全复现 仿真平台&#xff1a;MATLAB …

图解项目管理必备十大管理模型

请点击↑关注、收藏&#xff0c;本博客免费为你获取精彩知识分享&#xff01;有惊喜哟&#xff01;&#xff01; 心智模型 心智模型是根深蒂固存在于人们心中&#xff0c;影响人们如何理解这个世界&#xff08;包括我们自己、他人、组织和整个世界&#xff09;&#xff0c;以及…

pytest - Getting Start

前言 项目开发中有很多的功能&#xff0c;通常开发人员需要对自己编写的代码进行自测&#xff0c;除了借助postman等工具进行测试外&#xff0c;还需要编写单元测试对开发的代码进行测试&#xff0c;通过单元测试来判断代码是否能够实现需求&#xff0c;本文介绍的pytest模块是…

Android APK 反编译后重新打包并签名

APKTool&#xff1a; Apktool 是一个逆向android非常有用的工具&#xff0c;可以用来反编译apk文件&#xff0c;并且能在修改部分资源文件后&#xff0c;重新打包成一个新的apk。 下载连接&#xff1a;http://ibotpeaches.github.io/Apktool/install/ 下载之后文件夹非常清爽&…

ChatGPT会颠覆SEO内容创作吗

近几年 AI 的发展日新月异。除了搜索算法本身大规模应用人工智能&#xff0c;我也一直关注着 AI 用于写作的进展。 上篇关于 Google 有用内容更新的帖子还在说&#xff0c;高质量内容创作是 SEO 最难的事之一&#xff0c;对某些网站来说&#xff0c;如果能有工具帮助&#xff…

Mysql 日志

目录 0 课程视频 1 错误日志 -> 默认开启 1.1 查看变量 show variables like %log_error%; 1.2 文件位置 /var/log -> mysqld.log 1.3 指令语法 2 二进制日志 -> 修改数据和数据库结构的日志 2.1 记录原则 2.1.1 记录 数据库创建语句 和 增删改查 2.1.2 不记…

JdbcTemplate常用语句代码示例

目录 JdbcTemplate 需求 官方文档 JdbcTemplate-基本介绍 JdbcTemplate 使用实例 需求说明 创建数据库 spring 和表 monster 创建配置文件 src/jdbc.properties 创建配置文件 src/JdbcTemplate_ioc.xml 创建类JdbcTemplateTest测试是否可以正确得到数据源 配置 J…

智能算法系列之基于粒子群优化的模拟退火算法

文章目录 前言1. 算法结合思路2. 问题场景2.1 Sphere2.2 Himmelblau2.3 Ackley2.4 函数可视化 3. 算法实现代码仓库&#xff1a;IALib[GitHub] 前言 本篇是智能算法(Python复现)专栏的第四篇文章&#xff0c;主要介绍粒子群优化算法与模拟退火算法的结合&#xff0c;以弥补各自…

《基于EPNCC的脉搏信号特征识别与分类研究》阅读笔记

目录 一、论文摘要 二、论文十问 三、论文亮点与不足之处 四、与其他研究的比较 五、实际应用与影响 六、个人思考与启示 参考文献 一、论文摘要 为了快速获取脉搏信号的完整表征信息并验证脉搏信号在相关疾病临床诊断中的敏感性和有效性。在本文中&#xff0c;提出了一…

Ubantu docker学习笔记(八)私有仓库

文章目录 一、建立HTTPS链接1.在仓库服务器上获取TLS证书1.1 生成证书颁发机构证书1.2 生成服务器证书1.3 利用证书运行仓库容器 2.让私有仓库支持HTTPS3.客户端端配置 二、基本身份验证三、对外隐藏仓库服务器3.1 在服务器端3.2 在客户端进行 四、仓库可视化 在前面的学习中&a…

ChatGPT被淘汰了?Auto-GPT到底有多强

大家好&#xff0c;我是可夫小子&#xff0c;关注AIGC、读书和自媒体。解锁更多ChatGPT、AI绘画玩法。 说Auto-GPT淘汰了ChatGPT了&#xff0c;显然是营销文案里面的标题党。毕竟它还是基于ChatGPT的API&#xff0c;某种意义只是基于ChatGPT能力的应用。但最近&#xff0c;Auto…

Nautilus Chain Layer 3 圆桌会议圆满举办,超4.8K用户观看

在4月21日&#xff0c;Nautilus Chain举办了以“Layer 3区块链的意义和发展以及Crypto的演变”为主题的线上圆桌会议&#xff0c;我们邀请了众多行业嘉宾包括GitcoinDAO社区管理者Bob jiang、Whalers Community发起者崔棉大师、Chatpuppy联合创始人 古千峰、Whalers Community核…

机器学习与深度学习——通过决策树算法分类鸢尾花数据集iris求出错误率画出决策树并进行可视化

什么是决策树&#xff1f; 决策树是一种常用的机器学习算法&#xff0c;它可以对数据集进行分类或回归分析。决策树的结构类似于一棵树&#xff0c;由节点和边组成。每个节点代表一个特征或属性&#xff0c;每个边代表一个判断或决策。从根节点开始&#xff0c;根据特征的不同…

vue3的props和defineProps

文章目录 1. Props 声明1.1 props用字符串数组来声明Blog.vueBlogPost.vue 1.2 props使用对象来声明Blog.vueBlogPost.vue 2. 传递 prop 的细节2.1 Prop 名字格式2.1 静态Prop & 动态 Prop静态prop动态prop示例Blog.vueBlogPost.vue 2.3 传递不同的值类型NumberBooleanArra…

基于YOLOv4的目标检测系统(附MATLAB代码+GUI实现)

摘要&#xff1a;本文介绍了一种MATLAB实现的目标检测系统代码&#xff0c;采用 YOLOv4 检测网络作为核心模型&#xff0c;用于训练和检测各种任务下的目标&#xff0c;并在GUI界面中对各种目标检测结果可视化。文章详细介绍了YOLOv4的实现过程&#xff0c;包括算法原理、MATLA…

C++知识点 -- 异常

C知识点 – 异常 文章目录 C知识点 -- 异常一、异常概念二、异常的使用1.异常的抛出和捕获2.异常的重新抛出3.异常安全4.异常规范 三、自定义异常体系四、C标准库的异常体系五、C异常的优缺点 一、异常概念 当一个函数发现自己无法处理错误时&#xff0c;就可以抛出异常&#…

14-3-进程间通信-消息队列

前面提到的管道pipe和fifo是半双工的&#xff0c;在某些场景不能发挥作用&#xff1b; 接下来描述的是消息队列&#xff08;一种全双工的通信方式&#xff09;&#xff1b; 比如消息队列可以实现两个进程互发消息&#xff08;不像管道&#xff0c;只能1个进程发消息&#xff…

kali: kali工具-Ettercap

kali工具-Ettercap ettercap工具&#xff1a; 用来进行arp欺骗&#xff0c;可以进行ARP poisoning&#xff08;arp投毒&#xff09;&#xff0c;除此之外还可以其他功能&#xff1a; ettercap工具的arp投毒可以截取web服务器、FTP服务器账号密码等信息&#xff0c;简略后打印出…

前端学习之使用JavaScript

前情回顾&#xff1a;网页布局 JavaScript 简介 avaScript诞生于1995年&#xff0c;它的出现主要是用于处理网页中的前端验证。所谓的前端验证&#xff0c;就是指检查用户输入的内容是否符合一定的规则。比如&#xff1a;用户名的长度&#xff0c;密码的长度&#xff0c;邮箱的…

SQL中去除重复数据的几种方法,我一次性都告你​

使用SQL对数据进行提取和分析时&#xff0c;我们经常会遇到数据重复的场景&#xff0c;需要我们对数据进行去重后分析。 以某电商公司的销售报表为例&#xff0c;常见的去重方法我们用到distinct 或者group by 语句&#xff0c; 今天介绍一种新的方法&#xff0c;利用窗口函数…