上接:数据挖掘实战 —— 抖音用户浏览行为数据分析与挖掘(一)
(六)模型选择与建立——聚类分析,关联规则
针对抖音用户浏览行为数据,我们可以选择使用各种适应的数据挖掘模型或算法,如关联规则挖掘、聚类分析、分类模型等。根据具体的问题和数据特点,选择合适的模型并进行训练和优化。
(1)聚类分析
聚类方法是一种将数据对象分组或聚集成具有相似特征的类别或簇的技术。聚类分析是无监督学习的一种常用方法,它不依赖于预先定义的类别标签,而是根据数据对象之间的相似性或距离度量来进行分组。
常见的聚类方法:
A.K均值聚类:将数据对象划分为K个簇,每个簇代表一个聚类中心,通过最小化数据对象与聚类中心之间的距离来进行优化。
B.层次聚类:基于不同的聚类合并或分裂策略,通过构建聚类树或聚类层次结构来划分数据对象。
C.密度聚类:通过密度可达性和密度相连性来识别高密度区域,将数据对象划分为簇。
D.谱聚类:通过数据对象之间的相似性矩阵或图表示,将数据对象划分为簇。
E.DBSCAN聚类:通过定义邻域半径和最小密度阈值,将数据对象划分为核心对象、边界对象和噪声对象。
针对用户和作者的数据特征,使用k-means聚类算法量化的将两个群体进行分类:
A.导入用于聚类分析的相关库和函数
B. 确保计算机上已安装Python和pip,并且已经配置好了正确的环境。
C.使用pd.read_csv()函数读取用户特征、作者特征的CSV文件
D.基于用户特征数据筛选出满足条件的用户数据,计算满足条件的用户数据占总用户数据的比例
用户聚类可以服务于平台对用户分级,探索性的分析用户特点,但在数据可视化分析中,可以看到有一部分用户使用程度平台低 ,浏览少,不点赞,对这样的用户进行聚类分析是无效多余的,增加筛选认为至少观看过一个完整短视频且有一定浏览量的用户才具有分析意义。
E. 基于作者特征数据筛选出满足条件的作者数据,计算满足条件的作者数据
总作者数据的比例
而在对作者的考量上,聚类的结果是服务于商务合作和广告投放,此时核心是浏览量,而大部分的作者总浏览量非常小,这些作者是无需考虑的,故进行筛选。
F. 定义K-means聚类算法的函数km
在函数内部,通过循环遍历K值的范围,
①初始化KMeans模型并进行聚类。
②预测数据的聚类结果。
③计算模型的评估指标,包括轮廓系数和SSE(Sum of Squared Errors)。
④保存聚类模型。
⑤存储评估指标。
⑥打印聚类计算完成的消息。
⑦保存评估指标,并返回存储了每个K值对应的轮廓系数和SSE的字典。
G. 定义绘制聚类效果图的函数draw(sse和sc曲线)
①创建一个Line图表对象,并设置图表的初始化选项,包括主题、宽度和高度。
②使用.add_xaxis()方法将K值作为X轴数据添加到图表中。
③使用.add_yaxis()方法分别将SSE和轮廓系数作为两条线的Y轴数据添加到图表中,并通过yaxis_index参数指定它们在不同的Y轴上。
④使用.extend_axis()方法添加一个额外的Y轴。
⑤使用.set_global_opts()方法设置图表的全局选项,包括标题、X轴和Y轴的选项。
⑥返回创建的图表对象。
H. 根据给定的用户数据进行聚类
①模型训练与保存:根据给定的用户数据进行聚类,并将聚类结果保存在user_score中
②聚类k值选择——通过综合肘部法则和sc值,选择作为用户聚类模型
③聚类结果
I. 根据给定的作者数据进行聚类
①模型训练与保存:根据给定的作者数据进行聚类,并将聚类结果保存在user_score中
②聚类k值选择——通过综合肘部法则和sc值,选择作为用户聚类模型
③聚类结果
聚类的结果解释性较为明显,其核心与浏览量相关,提供了一定数据特征下的量化分类作用。
(2)关联规则
A.根据 用户特征 的CSV文件使用Apriori算法进行关联规则挖掘并输出关联规则、置信度和支持度。
①确保已经安装了pandas和mlxtend库,并且已经将用户特征.CSV文件保存在Jupyter Notebook。
②使用pd.read_csv()函数读取作者特征的CSV文件
③对数据进行预处理,使用独热编码将数据转换为适用于关联规则挖掘的形式。
使用Pandas中的applymap()函数对user_df DataFrame进行转换,对每个元素进行操作。该lambda函数的逻辑是,如果元素大于0,则将其赋值为1,否则赋值为0。
④使用Apriori算法挖掘频繁项集,设置适当的min_support参数来控制最小支持度的阈值
⑤使用循环遍历rules的每一行,并输出满足条件的关联规则、支持度和置信度。
B. 根据 作者特征的 CSV文件使用Apriori算法进行关联规则挖掘并输出关联规则、置信度和支持度。
C. 根据 作品特征 的CSV文件使用Apriori算法进行关联规则挖掘并输出关联规则、置信度和支持度。
(七)模型评估与调优——二分类预测(浏览行为中的点赞预测)
-
导入必要的python软件包和模块
-
数据类型展示
读取数据,并保留用户特征、作品特征和是否点赞,其余无效字段如channel(不确定),finish(没有浏览行为时不存在), H、date(real_time中包括)。
- 数据抽样处理
为了减少训练成本,对数据集中的数据进行抽样训练通过等距抽样获取部分浏览信息作为训练数据(需要同时保证点赞数据的合理比例)。
- 时间数据处理
训练数据中的real_time字段包括的是字符串对象对应代表时间值,通过将其转化为与固定时间的差值(秒)来进行数值化。
-
数据集划分
-
模型训练函数
-
模型训练
-
绘制模型AUC曲线
综合准确率和AUC值表现,模型的效果不是很好,在数据抽样时扩大抽样规模会有效的提高auc值,同时点赞和不点赞的数据分布较为不均衡也是重要原因这里只做继续方法的演示,相对来说随机森林的效果比较好,所以选择随机森林作为二分类模型。
-
n_e优化
-
max_f优化
-
模型训练
虽然整体的效果不行,auc值比较低,但是可以看到有优化提升。
- 模型准确率
转换一下df中的时间,看看使用2.5%左右的数据训练出来的模型准确率能有多少。
预测点赞的模型准确率为99.6。
即使预测不点赞,模型准确率也高达99.3。
(八)结果解释与应用
该模型结果显示,通过对用户、作者和作品等主体的特征描述和数据分析方法的应用,可以服务于业务优化等目的。如下图所示。
该模型可以应用于对用户价值进行判定,比如第一类用户的浏览量、点赞、完播率都不怎么高,这类用户更多会关注到视频前半段的内容,兴趣点可通过停留时间进行判断,但使用时间相对较长,反映产品依赖性,一定程度上来说算是核心用户。可以利用停留时间判断喜好,优化推荐算法,重点推荐前半段内容吸引力大的。
该模型还可以应用于提高作者创作效率,如上图所示。可以看出,高浏览量、高点赞量、高观完量的作者通常都会比其他作者使用更多的配乐,发布的作品更多,去过的城市更多,说明作者需要积累大量的创作经验以及丰富的阅历才能创作出更多脍炙人口的视频。
这套模型的预测准确率高达99%,说明通过用户特征和作品特征,能够训练一个用于预测用户是否会点赞的二分类模型。在用户对作品的浏览过程中,是否点赞是一个非常重要的指标。通过点赞行为,我们可以判断出用户的喜好,评价作品的质量等。而这套模型可以应用于给自媒体公司提供一个内容优化和广告投放的手段。
分录
聚类
import numpy as np
import pandas as pd
from pyecharts.charts import *
from pyecharts import options as opts
from sklearn.cluster import KMeans
import joblib
from sklearn import metrics
from scipy.spatial.distance import cdist
user_feature = pd.read_csv('用户特征.csv', index_col=0)
author_feature = pd.read_csv('作者特征.csv', index_col=0)
user_data = user_feature[(user_feature['完整观看数']>=1)&(user_feature['浏览量']>=5)]
print(len(user_data)/len(user_feature))
author_data = author_feature[(author_feature['总观完量']>=1)&(author_feature['总浏览量']>=3)]
print(len(author_data)/len(author_feature))
def km(data, name):
K = range(2, 10) # K值选取范围
X = data # 数据
# scores = { 'SSE': [], 'sc': [], 'sse': []}
scores = {'sc': [], 'sse': []}
for _k in K:
# 初始化模型并进行聚类 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
kmeans = KMeans(n_clusters=_k, init='k-means++', random_state=0)
kmeans.fit(X)
_y = kmeans.predict(X) # 预测结果
# 计算模型评估指标 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sse = sum(np.min(cdist(X,kmeans.cluster_centers_,'euclidean'),axis=1))/X.shape[0]
sc = metrics.silhouette_score(X, _y) # 计算轮廓系数
joblib.dump(kmeans, f'{name}{_k}聚类.model')
# 储存评估值 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# scores['SSE'].append(SSE)
scores['sse'].append(sse)
scores['sc'].append(sc)
print(f'聚{_k}类计算完成', end='\t')
joblib.dump(scores, f'{name}聚类指标.score')
print('指标储存完毕')
return scores
def draw(k, sse, sc):
chart = (
Line(init_opts=opts.InitOpts(
theme='light',
width='350px',
height='350px'
))
.add_xaxis(k)
.add_yaxis('sse', sse, yaxis_index=0, label_opts=opts.LabelOpts(is_show=False))
.add_yaxis('sc', sc, yaxis_index=1, label_opts=opts.LabelOpts(is_show=False))
.extend_axis(yaxis=opts.AxisOpts())
.set_global_opts(
title_opts=opts.TitleOpts(title='聚类效果'),
xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=True),
yaxis_opts=opts.AxisOpts(
type_="value",
axistick_opts=opts.AxisTickOpts(is_show=True),
splitline_opts=opts.SplitLineOpts(is_show=True),
),
)
)
return chart
user_score = km(user_data, '用户')
user_score = joblib.load(f'用户聚类指标.score')
draw([str(x) for x in range(2,10)], user_score['sse'], user_score['sc']).render_notebook()
user_km = joblib.load(f'用户4聚类.model')
user_centers = pd.DataFrame(user_km.cluster_centers_, columns=user_feature.columns)
user_centers['人数']=pd.Series(user_km.predict(user_data)).value_counts()
user_centers
author_score = km(author_data, '作者')
author_score = joblib.load(f'作者聚类指标.score')
draw([str(x) for x in range(2,10)], author_score['sse'], author_score['sc']).render_notebook()
author_km = joblib.load(f'作者4聚类.model')
author_centers = pd.DataFrame(author_km.cluster_centers_, columns=author_feature.columns)
author_centers['人数'] = pd.Series(author_km.predict(author_data)).value_counts()
author_centers
二分类
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, auc
from sklearn import ensemble
from sklearn.model_selection import GridSearchCV
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['font.size'] = 20
df = pd.read_csv('douyin_dataset.csv')
del df['Unnamed: 0'], df['H'], df['date'], df['finish'], df['channel']
df.head()
df_like = df[df['like']==1]
df_dislike = df[df['like']==0]
data = pd.concat([df_like[::20], df_dislike[::40]], axis=0)
print(len(data)/len(df))
flag = pd.to_datetime('2019-01-01 00:00:00')
data['real_time'] = pd.to_datetime(data['real_time'])
data['real_time'] = pd.to_timedelta( data['real_time'] - flag).dt.total_seconds()
data.head()
xtrain,xtest, ytrain, ytest = \
train_test_split(
data.drop('like', axis=1), # X
data['like'],test_size=0.3, # Y
random_state=0 # random_seed
)
def train(name, model):
model = model.fit(xtrain, ytrain)
print(f'{name}准确率: \t{model.score(xtest, ytest)}')
return model
# 逻辑回归
lgs = train('lgs', LogisticRegression(solver='liblinear', C=100.0,random_state=1))
# 朴素贝叶斯
gnb = train('gnb', GaussianNB().fit(xtrain,ytrain))
# 单棵决策树
clf = train('clf', DecisionTreeClassifier(class_weight='balanced',random_state=0))
# 随机森林
rfc = train('rfc', RandomForestClassifier(n_estimators=100, class_weight='balanced',random_state=0))
def my_auc(model):
y_test_proba = model.predict_proba(xtest)
false_positive_rate, recall, thresholds = roc_curve(ytest, y_test_proba[:, 1])
roc_auc = auc(false_positive_rate, recall)
return false_positive_rate, recall, roc_auc
lgs_auc = my_auc(lgs)
gnb_auc = my_auc(gnb)
clf_auc = my_auc(clf)
rfc_auc = my_auc(rfc)
# 画图 画出俩模型的ROC曲线
plt.figure(figsize=(6,4),dpi=120)
plt.plot(lgs_auc[0], lgs_auc[1], color='cyan', label='AUC_lgs=%0.3f' % lgs_auc[2])
plt.plot(gnb_auc[0], gnb_auc[1], color='blue', label='AUC_gnb=%0.3f' % gnb_auc[2])
plt.plot(clf_auc[0], clf_auc[1], color='green', label='AUC_clf=%0.3f' % clf_auc[2])
plt.plot(rfc_auc[0], rfc_auc[1], color='yellow', label='AUC_rfc=%0.3f' % rfc_auc[2])
plt.legend(loc='best', fontsize=12, frameon=False)
plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.ylabel('Recall')
plt.xlabel('Fall-out')
plt.show()
params = {
'n_estimators': [x for x in range(100,1500,100)]
}
grid = GridSearchCV(
RandomForestClassifier(class_weight='balanced', random_state=0),
params, scoring="roc_auc",
cv=3, verbose=1, n_jobs=-1
).fit(xtrain, ytrain)
a = grid.cv_results_['mean_test_score']
plt.figure(figsize=(6,4),dpi=120)
plt.plot(params['n_estimators'], a, color='blue')
plt.show()
grid.best_params_
params = {
'max_features': range(2,10,2)
}
grid = GridSearchCV(
RandomForestClassifier(n_estimators=1000, class_weight='balanced', random_state=0),
params, scoring="roc_auc",
cv=3, verbose=1, n_jobs=-1
).fit(xtrain, ytrain)
a = grid.cv_results_['mean_test_score']
plt.figure(figsize=(6,4),dpi=120)
plt.plot(params['max_features'], a, color='blue')
plt.show()
grid.best_params_
rfc0 = RandomForestClassifier(n_estimators=1000,
max_features=6,
class_weight='balanced',
random_state=0)
rfc0 = train('rfc++', rfc0)
auc_rfc0 = my_auc(rfc0)
# 画图 画出俩模型的ROC曲线
plt.figure(figsize=(6,4),dpi=120)
plt.plot(auc_rfc0[0], auc_rfc0[1], color='cyan', label='rfc++=%0.3f' % auc_rfc0[2])
plt.plot(rfc_auc[0], rfc_auc[1], color='yellow', label='rfc=%0.3f' % rfc_auc[2])
plt.legend(loc='best', fontsize=12, frameon=False)
plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.ylabel('Recall')
plt.xlabel('Fall-out')
plt.show()
df.head()
flag = pd.to_datetime('2019-01-01 00:00:00')
df['real_time'] = pd.to_datetime(df['real_time'])
df['real_time'] = pd.to_timedelta( df['real_time'] - flag).dt.total_seconds()
rfc0.score(df.drop('like', axis=1), df['like'])
lk = df['like'].value_counts()
lk
lk[0]/lk.sum()
关联规则
import pandas as pd
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
# 读取用户特征数据
user_df = pd.read_csv("用户特征.csv")
# 使用独热编码将数据转换为适用于关联规则挖掘的形式
encoded_user_df = user_df.applymap(lambda x: 1 if x > 0 else 0)
# 使用Apriori算法挖掘频繁项集
frequent_itemsets = apriori(encoded_user_df, min_support=0.2, use_colnames=True)
# 根据频繁项集生成关联规则
rules = association_rules(frequent_itemsets, metric="confidence", min_threshold=0.7)
# 设置最小置信度和最小支持度阈值,并筛选关联规则
min_confidence = 0.7
min_support = 0.2
filtered_rules = rules[(rules['confidence'] > min_confidence) & (rules['support'] > min_support)]
# 输出满足条件的关联规则、支持度和置信度
for index, row in filtered_rules.iterrows():
antecedents = ', '.join(list(row['antecedents']))
consequents = ', '.join(list(row['consequents']))
confidence = row['confidence']
support = row['support']
print(f"规则: {antecedents} -> {consequents}")
print(f"置信度: {confidence}")
print(f"支持度: {support}")
print("------------------")
import pandas as pd
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
# 读取作者特征数据
author_df = pd.read_csv("作者特征.csv")
# 使用独热编码将数据转换为适用于关联规则挖掘的形式
encoded_author_df = author_df.applymap(lambda x: 1 if x > 0 else 0)
# 设置最小支持度和最小置信度阈值
min_support = 0.9
min_confidence = 0.9
# 使用Apriori算法挖掘频繁项集
frequent_itemsets = apriori(encoded_author_df, min_support=min_support, use_colnames=True)
# 根据频繁项集生成关联规则
rules = association_rules(frequent_itemsets, metric="confidence", min_threshold=min_confidence)
# 输出满足条件的关联规则、支持度和置信度
for index, row in rules.iterrows():
antecedents = ', '.join(list(row['antecedents']))
consequents = ', '.join(list(row['consequents']))
confidence = row['confidence']
support = row['support']
print(f"规则: {antecedents} -> {consequents}")
print(f"支持度: {support}")
print(f"置信度: {confidence}")
print("------------------")
import pandas as pd
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
# 读取作品特征数据
item_df = pd.read_csv("作品特征.csv")
# 使用独热编码将数据转换为适用于关联规则挖掘的形式
encoded_item_df = item_df.applymap(lambda x: 1 if x > 0 else 0)
# 设置最小支持度和最小置信度阈值
min_support = 0.2
min_confidence = 0.7
# 使用Apriori算法挖掘频繁项集
frequent_itemsets = apriori(encoded_item_df, min_support=min_support, use_colnames=True)
# 根据频繁项集生成关联规则
rules = association_rules(frequent_itemsets, metric="confidence", min_threshold=min_confidence)
# 输出满足条件的关联规则、支持度和置信度
for index, row in rules.iterrows():
antecedents = ', '.join(list(row['antecedents']))
consequents = ', '.join(list(row['consequents']))
support = row['support']
confidence = row['confidence']
print(f"规则: {antecedents} -> {consequents}")
print(f"支持度: {support}")
print(f"置信度: {confidence}")
print("------------------")