紧接上文爬虫,我们获取到了一些数据,接下来就是使用和分析了~爬虫阶段式教学——从数据获取到格式化存储(附代码与效果图)_爬虫网页数据格式化-CSDN博客
为保证数据的正确性和有效性需要对数据进行筛选,保存有效信息,但很显然数据量大的话,数据庞杂很难说提取所有特征,进行分类和后续的操作,而且一旦出错……整个人都要崩溃了……于是便尝试了几种算法辅助完成。
同时,有些数据中存在人名、地址等敏感信息,需要进行加密处理,由于为个人非商业使用,所以采取了简单的文字替换方式,完成加密要求并不影响可读性。
(筛选和加密这两步,自由决定先后)
采取环境:python 3.11
一、数据加密
1、字符串偏移法
汉字通过 Unicode 编码来进行存储,最直接的便是对它的编码向前/后推。
import openpyxl
import random# 打开 Excel 文件
workbook = openpyxl.load_workbook('你的文件名.xlsx')
sheet = workbook.active
# 选定表格,sheet# 汉字的 Unicode 范围
zh_start = 0x4E00 # 汉字起始
zh_end = 0x9FFF # 汉字结束# 对第2列(姓名列)进行字符偏移加密,改成你的列
for row in range(2, sheet.max_row + 1):name = sheet.cell(row=row, column=1).valueif name:encrypted_name = []for char in name:offset = random.randint(-2, -1) # 随机调整偏移量,随机1-2位new_char = chr(ord(char) + offset)# 确保新字符在汉字范围内if zh_start <= ord(new_char) <= zh_end:encrypted_name.append(new_char)else:# 如果超出范围,保持原字符encrypted_name.append(char)# 将加密后的姓名保存到 Excelsheet.cell(row=row, column=2, value=''.join(encrypted_name))# 保存加密后的 Excel
workbook.save('保存的文件名.xlsx')# 此方法虽然可行,但整体影响可读性
效果如下:
很显然不容易解读,不适合当前使用。
2、常用词替换
此种方法,即为用常见的汉字来对名字进行替换,自建常用词列表,对名字进行:
import randomimport openpyxl# 打开 Excel 文件
workbook = openpyxl.load_workbook('你需要进行加密处理的文件.xlsx')
sheet = workbook.active# 一个常用汉字列表,用于替换
common_chars = ['明', '伟', '芳', '丽', '军', '静', '鹏', '霞', '婷', '波','强', '娟', '斌', '欣', '勇', '峰', '璐', '涛', '雪', '超','华', '莹', '媛', '杰', '玲', '蕾', '东', '春', '浩', '颖','志', '琪', '蕊', '晓', '俊', '琴', '义', '义', '凡', '燕','玥', '冰', '悦', '皓', '妍', '露', '阳', '欣', '明', '达','淼', '伟', '豪', '洁', '博', '鑫', '凯', '峰', '琪', '捷','晗', '瑞', '梦', '航', '娜', '睿', '佳', '晓', '泽', '宁','世', '皓', '瑜', '哲', '瑜', '昊', '博', '睿', '璇', '思','莺', '秋', '宇', '琦', '彦', '晨', '华', '星', '莉', '珊','雪', '慧', '妮', '凡', '蕙', '文', '馨', '晴', '斌', '凡'
]# 替换汉字列表# 对第2列(为我表的姓名列)进行字符替换
for row in range(2, sheet.max_row + 1):name = sheet.cell(row=row, column=1).value # 假设姓名在第一列if name:name_length = len(name)# 随机选择要替换的字的位置num_replacements = random.randint(1, 2) # 1到2个字进行替换indices_to_replace = random.sample(range(name_length), num_replacements)encrypted_name = list(name) # 将姓名转为列表以便修改for index in indices_to_replace:# 替换指定位置的字encrypted_name[index] = random.choice(common_chars)# 将加密后的姓名保存到 文件中sheet.cell(row=row, column=2, value=''.join(encrypted_name))# 保存加密后的 Excel
workbook.save('encrypted_alumni.xlsx')print("姓名加密完成,结果已保存为 '加密后文件.xlsx'。")
效果图:
,整体还是可以的。
二、数据分类与有效提取
前言:
对敏感数据完成加密后,接下来就是对提取到的数据进行筛选了。主要就是分类和有效信息提取。这里引入两个无监督算法:k-means聚类 与 DBSCAN 聚类,虽然不一定全适用。(但毕竟嘛,如果是论文里,加上这东西,那不就是创新点和亮点了嘛😆)
注意:如果当前你获取到的数据本身就已经是很规范的,那就没必要进行这一步了~直接用就行
以下将从两种聚类方法进行逐个讲解。
这里说点题外话,简单说说我对这些分类、聚类算法等的理解。
这些算法无非就是特征的选择与提取,那要怎么寻找特征呢?我们不妨拆借一下 “特征” 二字,它是 "相似" 文字特点提取后的抽象。转换一下:我们找到相似的文字,便可得出这个特征,而要衡量这种相似,必须要量化,即可以数字计算。
如果计算,那什么最直观可以表示字与字之间的联系呢?距离的远近!
那有没有什么方法可以实现这种想法呢?坐标!?我们不如设定一套规则,将所有文字数字化,句子则为一个多维度的坐标,而这套规则的准确度、适用度决定了相似判定的准确性。而要保证这种准确性,这需要考虑文字的位置、语义、出现频次等等信息,这里有对应的算法表示(比如TF-IDF,不再赘述)
1、K-means聚类
(1)简述:
简单说一下k-means,它是无监督算法的一种,基本逻辑是依据一些特征将数据集分成若干个簇(Cluster,其实就是子集)。在数据坐标化后,先随便选择几个质心,将数据点分配到离它最近的簇中。然后在几个簇中不断重复这两步。直到质心不再开始变化。
(2)代码:
# 这个是通用的配置:两个聚类算法实际都需要这个
import pandas as pd
# 读取Excel文件
file_path = 'tieba.xlsx' # 替换为你的文件路径
sheet_name = '贴吧数据' # 数据位置,对应的sheet,我这儿sheet的名称是“贴吧数据”# 读取Excel表格
df = pd.read_excel(file_path, sheet_name=sheet_name)# 选择你要处理的内容列
texts = df['标题'].fillna('').tolist() # 将空值处理为空字符串# 测试一下看有无数据,打印前几个帖子内容
print(texts[:5])
以下是基础版本代码:
# 这是具体的聚类算法代码
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import PCA
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
import re
import matplotlib# 设置字体为支持中文的字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 选择中文字体
matplotlib.rcParams['axes.unicode_minus'] = False # 处理负号显示问题# 文本清洗,这一步很有必要
def clean_text(text):text = re.sub(r'<[^>]+>', '', text) # 去掉HTML标签text = re.sub(r'[^\w\s]', '', text) # 去掉标点符号return text.lower()# 对文本进行清洗
texts_cleaned = [clean_text(text) for text in texts]# 使用TF-IDF将文本转为向量,
vectorizer = TfidfVectorizer(max_features=5000)
X = vectorizer.fit_transform(texts_cleaned)# 使用K-means进行聚类,这里的n_clusters:表示 聚类数量 ,具体哪个最精确需要动态调整。
kmeans = KMeans(n_clusters=5, random_state=42)
kmeans.fit(X)# 获取每个帖子所属的聚类
labels = kmeans.labels_# 使用PCA将数据降维到2D
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X.toarray())# 创建一个散点图,使用不同颜色表示不同类别
plt.figure(figsize=(10, 6))
unique_labels = np.unique(labels)
colors = plt.cm.get_cmap('tab10', len(unique_labels))for label in unique_labels:indices = np.where(labels == label)plt.scatter(X_pca[indices, 0], X_pca[indices, 1], label=f'类别 {label}', s=50, alpha=0.7)# 添加中文标题和坐标轴标签
plt.title('贴吧帖子 K-Means 聚类结果')
plt.xlabel('主成分 1')
plt.ylabel('主成分 2')
plt.legend(loc='best', title='聚类类别')
plt.grid()# 显示图形
plt.show()
(3)结果:
展示如下:
当前展现出的结果:说明特征值过小,大概是我直接从贴吧获取到的数据基本都一个样……
(4)扩展:
接下来我们就此种算法进行轮廓系数 和 总内聚度 评估(我这儿只是举个例子,大家学个方法就行)。
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import PCA
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import re
import matplotlib# 设置字体为支持中文的字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 选择中文字体
matplotlib.rcParams['axes.unicode_minus'] = False # 处理负号显示问题# 文本清洗函数
def clean_text(text):text = re.sub(r'<[^>]+>', '', text) # 去掉HTML标签text = re.sub(r'[^\w\s]', '', text) # 去掉标点符号return text.lower()# 对文本进行清洗
texts_cleaned = [clean_text(text) for text in texts]# 使用TF-IDF将文本转为向量
vectorizer = TfidfVectorizer(max_features=5000)
X = vectorizer.fit_transform(texts_cleaned)# 绘制肘部法则图,选择最合适的K
inertia_values = []
silhouette_scores = []# 计算不同K值下的inertia和silhouette_score
for k in range(2, 11):kmeans = KMeans(n_clusters=k, random_state=42)kmeans.fit(X)inertia_values.append(kmeans.inertia_)# 计算轮廓系数score = silhouette_score(X, kmeans.labels_)silhouette_scores.append(score)# 绘制肘部法则图
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.plot(range(2, 11), inertia_values, marker='o', color='b')
plt.title('肘部法则')
plt.xlabel('K 值')
plt.ylabel('总内聚度 (Inertia)')
plt.grid()# 绘制轮廓系数图
plt.subplot(1, 2, 2)
plt.plot(range(2, 11), silhouette_scores, marker='o', color='g')
plt.title('轮廓系数')
plt.xlabel('K 值')
plt.ylabel('轮廓系数')
plt.grid()plt.tight_layout()
plt.show()# 选择合适的K值,比如5,进行最终的聚类
kmeans = KMeans(n_clusters=5, random_state=42)
kmeans.fit(X)# 获取每个帖子所属的聚类
labels = kmeans.labels_# 使用PCA将数据降维到2D
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X.toarray())# 创建一个散点图,使用不同颜色表示不同类别
plt.figure(figsize=(10, 6))
unique_labels = np.unique(labels)
colors = plt.cm.get_cmap('tab10', len(unique_labels))for label in unique_labels:indices = np.where(labels == label)plt.scatter(X_pca[indices, 0], X_pca[indices, 1], label=f'类别 {label}', s=50, alpha=0.7)# 添加中文标题和坐标轴标签
plt.title('贴吧帖子 K-Means 聚类结果')
plt.xlabel('主成分 1')
plt.ylabel('主成分 2')
plt.legend(loc='best', title='聚类类别')
plt.grid()# 显示图形
plt.show()
总之呢:总内聚度值越小,聚类效果越好,轮廓系数越接近1越好。我这儿最佳k值为7,但整体聚类效果是在不大行,哈哈。
大家可以尝试一下。
2、DBSCAN 聚类
(1)简述
DBSCAN 聚类不同于K-means,它是基于密度的聚类算法,通过寻找数据点的密度区域来形成簇。核心思想是“密集区域”的数据点属于同一簇,而密度较低的区域被视为噪声或离群点。
具体的就不说了,我们直接上代码吧
(2)代码:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score, homogeneity_score, completeness_score, v_measure_score, davies_bouldin_score, calinski_harabasz_score, adjusted_rand_score, fowlkes_mallows_score
import re
import matplotlib# 设置字体为支持中文的字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 选择中文字体
matplotlib.rcParams['axes.unicode_minus'] = False # 处理负号显示问题# 文本清洗函数
def clean_text(text):text = re.sub(r'<[^>]+>', '', text) # 去掉HTML标签text = re.sub(r'[^\w\s]', '', text) # 去掉标点符号return text.lower()# texts = [...] # 这里的texts,和上文k-means的一致,直接调用即可# 对文本进行清洗
texts_cleaned = [clean_text(text) for text in texts]# 使用TF-IDF将文本转为向量
vectorizer = TfidfVectorizer(max_features=5000)
X = vectorizer.fit_transform(texts_cleaned)# 标准化数据
X_scaled = StandardScaler().fit_transform(X.toarray())# 使用DBSCAN进行聚类
dbscan = DBSCAN(eps=0.5, min_samples=5)
dbscan_labels = dbscan.fit_predict(X_scaled)# 将聚类标签存储到 DataFrame 中
df = pd.DataFrame({'文本内容': texts, '聚类标签': dbscan_labels})# 使用PCA将数据降维到2D
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)# 创建一个散点图,使用不同颜色表示不同类别
plt.figure(figsize=(12, 8))
colors = plt.cm.get_cmap('tab10', len(np.unique(dbscan_labels)))for label in np.unique(dbscan_labels):if label == -1: # -1表示噪声点plt.scatter(X_pca[dbscan_labels == label, 0], X_pca[dbscan_labels == label, 1],color='k', label='噪声', s=50, alpha=0.5, edgecolor='k')else:plt.scatter(X_pca[dbscan_labels == label, 0], X_pca[dbscan_labels == label, 1],label=f'类别 {label}', s=100, alpha=0.7, edgecolor='k')# 添加数据点编号
for i, txt in enumerate(range(len(texts))):plt.annotate(txt, (X_pca[i, 0], X_pca[i, 1]), fontsize=8, alpha=0.7)# 添加中文标题和坐标轴标签
plt.title('贴吧帖子 DBSCAN 聚类结果', fontsize=16)
plt.xlabel('主成分 1', fontsize=14)
plt.ylabel('主成分 2', fontsize=14)
plt.legend(loc='best', title='聚类类别', fontsize=12)
plt.grid()# 显示图形
plt.tight_layout()
plt.show()# 保存聚类结果到Excel
df.to_excel('聚类标签-DBSCAN.xlsx', index=False)# 评估指标:轮廓系数、同质性、完整性、V-Measure、Davies-Bouldin指数、Calinski-Harabasz指数等# 由于DBSCAN会生成噪声点(-1),我们只计算除噪声外的数据点的评估指标# 去除噪声标签 (-1)
non_noise_indices = dbscan_labels != -1
X_non_noise = X_scaled[non_noise_indices]
dbscan_labels_non_noise = dbscan_labels[non_noise_indices]# 计算轮廓系数
silhouette_avg = silhouette_score(X_non_noise, dbscan_labels_non_noise)
print(f'轮廓系数(Silhouette Score):{silhouette_avg}')# 计算同质性、完整性和V-Measure
# 如果没有真实标签,可以跳过
# homogeneity = homogeneity_score(true_labels, dbscan_labels_non_noise)
# completeness = completeness_score(true_labels, dbscan_labels_non_noise)
# v_measure = v_measure_score(true_labels, dbscan_labels_non_noise)# 计算Davies-Bouldin指数(值越小越好)
db_index = davies_bouldin_score(X_non_noise, dbscan_labels_non_noise)
print(f'Davies-Bouldin指数:{db_index}')# 计算Calinski-Harabasz指数(值越大越好)
ch_index = calinski_harabasz_score(X_non_noise, dbscan_labels_non_noise)
print(f'Calinski-Harabasz指数:{ch_index}')# 真实标签:就是你这儿实际弄好的,大多是人工分辨得出。
# 计算Adjusted Rand Index(ARI)
# 如果没有真实标签,则不能计算ARI
# ari = adjusted_rand_score(true_labels, dbscan_labels_non_noise)
# print(f'Adjusted Rand Index:{ari}')# 计算Fowlkes-Mallows指数(FMI)
# 如果没有真实标签,则不能计算FMI
# fmi = fowlkes_mallows_score(true_labels, dbscan_labels_non_noise)
# print(f'Fowlkes-Mallows Index:{fmi}')# 如果没有真实标签,则输出如下
print(f'同质性(Homogeneity):{silhouette_avg}') # 用轮廓系数作为示例
print(f'完整性(Completeness):{silhouette_avg}') # 用轮廓系数作为示例
print(f'V-Measure:{silhouette_avg}') # 用轮廓系数作为示例
(3)结果:
以下是:输出的结果
轮廓系数(Silhouette Score):0.999999995613945
Davies-Bouldin指数:4.570585821073591e-07
Calinski-Harabasz指数:1.7907473496544669e+31
同质性(Homogeneity):0.999999995613945
完整性(Completeness):0.999999995613945
V-Measure:0.999999995613945
看看这聚类效果!图基本汇聚到一个点,非常好!数据点在其所在簇内很紧密,并且与其他簇之间有很好的分离!簇之间的分离度很行,簇内的紧密度也很高!
但是,似乎我本来是想分类来着……搞着一出,分不出来,咋整??
我们似乎要想另一种办法了……那还有什么办法呢……
监督学习!!!