youtube涨粉丝 --油管买播放量平台

译者:Lianne & Justin
校对:ronghuaiyang
编者按
采用Python一步棋一步棋的对Youtube盛行的瘦身电音频道展开机器学习,找出提升下载量的方式,觉得社会公众号也是适用于的。
在这首诗中,他们在YouTube统计数据上采用了机器学习演算法,得出许多能赢得更多的下载量的提议。
他们将包涵整座的端到端操作过程:
- 截取YouTube统计数据
- 采用NLP的音频副标题
- 特点工程建设 — 创建预估计算机程序
- 更多
全数用Python同时实现。
假如你想晓得统计数据自然科学怎样协助YouTube电音频道赢得更多的下载量和总收入,那就去看一看吧。
让他们已经开始吧。
今天还没有锻炼吗?看一看她最近的音频吧。
30分钟的强力手臂和臀大肌锻炼
你可能已经注意到,她的音频副标题遵循一个标准的格式。它们通常包括时间长度、身体部位、燃烧的卡路里和其他有关锻炼的描述性词语。在我点击这个音频之前,我会晓得:
- 30分钟 — 我将在30分钟内完成整座锻炼。
- 强大的手臂和臀大肌 — 我将致力于手臂和臀大肌和集中力量。
- 燃烧310卡路里 — 我将燃烧相当数量的卡路里。
他们会分析这些关键信息。
让他们看一看他们是否能给Sydney推荐许多新的内容创作策略来进一步棋改进!
为了方便阅读,文章的结构如下:
- 准备:截取统计数据
- 第1步:观察统计数据
- 第2步:采用NLP技术来对音频分类
- 第3步:特点工程建设
- 第4步:构建目标变量
- 第5步:构建计算机程序
- 第6步:理解计算机程序
- 获取更多浏览的许多可行的提议
准备:截取统计数据
截取YouTube统计数据有不同的方式。因为这只是一个一次性的项目,所以他们用最简单的方式来做,这需要手工操作,但是不需要额外的工具。
以下是一步棋一步棋的程序:
1、滚动到电音频道的音频页面,直到所有的音频出现。
2、右键点击最新的音频,选择Inspect
3、将光标悬停在每行上,找出所有高亮显示音频的HTML代码/元素的最低级别。
例如,他们采用Chrome浏览器,它看起来是这样的:
4、右键点击元素,选择复制,然后选择复制元素。
5、将复制的元素粘贴到文本文件中并保存。他们采用JupyterLab文本文件,并将其保存为sydney.txt。
6、采用Python提取信息并清理统计数据。
他们不解释细节,因为每个案例都是不同的。代码在这里:https://gist.github.com/liannewriting/cd35e68deee092eeab9c288f414d6bc1为你提供方便。
现在他们能已经开始有趣的部分了!
他们将从这个统计数据集中提取特点,并研究影响观看数量的特点。
第1步:观察统计数据
在最后一步棋中将统计数据加载到Python中已经完成了,让他们看一看他们的统计数据集df_videos。
df_videos有8个特点描述每个音频的细节,包括:
- 副标题
- 发布了多长时间(小时)
- 音频长度
- 观看量
- 链接
- 卡路里数
- 发布日期
- 已发布的天数
已有837个音频上传。
另外,他们发现统计数据中有重复,因为Sydney上传了多次相同的音频。但他们忽略它,因为重复的很少。
there are duplicatesdf_videos[title].value_counts(dropna=False).iloc[:30]
第2步:采用NLP技术来对音频分类
在这一步棋中,他们主要根据副标题中的关键词对音频展开分类。
他们希望根据以下内容对音频展开分组:
- 这段音频关注的是身体的哪些部位?
- 这个音频是协助他们增加力量还是减少脂肪?
- 其他关键字?
他们采用NLP技术和Natural Language Toolkit (NLTK)包来处理副标题。在这首诗中,他们不解释技术的细节。
构建关键词列表
首先,他们对音频的副标题展开分词。
这个操作过程显式地将副标题文本字符串分割为不同的tokens(单词),并采用空格分隔。通过这种方式,计算机程序能更好地理解文本。
import all the packagesimportpandasaspdimportnumpyasnpfromdatetimeimporttimedelta, datetimeimportmatplotlib.pyplotaspltimportmatplotlib.mlabasmlabimportmatplotlib
plt.style.use(ggplot)frommatplotlib.pyplotimportfigurefromplotlyimport__version__fromplotly.offlineimportdownload_plotlyjs, init_notebook_mode, plot, iplotimportplotly.graph_objsasgoimportplotly
%matplotlib inline
matplotlib.rcParams[figure.figsize] = (12,8)fromsklearn.treeimportDecisionTreeRegressorfromsklearnimporttreefromsklearn.ensembleimportGradientBoostingRegressor, GradientBoostingClassifierfromsklearn.model_selectionimportcross_val_scoreimportseabornassns
pd.options.mode.chained_assignment =Nonefromnltkimportword_tokenizefromcollectionsimportCounter
words = df_videos[title].str.lower().str.cat(sep=)
word_tokens = word_tokenize(words)
word_counter = Counter(word_tokens)
print({} different words.format(len(word_counter)))
word_counter.most_common(538)
在这些副标题中有538个不同的单词。列表的顶部许多词如下。
许多词被频繁采用。这再次证实了Sydney确实采用了标准格式的音频副标题。通过查看上面的列表,他们创建了3个关键词列表,这些关键词可用于在以后的步骤中对音频展开分类。
- body_keywords — 识别音频关注的身体部位,如full body,abs,legs。
- workout_type_keywords — 这告诉锻炼类型,如 cardio,stretch,strength。
- other_keywords — 这包括经常采用但很难归类的关键词,如bootcamp,burnout,toning。
确定关键词列表的词干
在形成这些关键词列表之后,他们对它们提取词干。在词干提取操作过程确保计算机程序能够匹配具有相同含义的单词。
例如,单词abs和ab有相同的词干ab。
from nltk.stem import PorterStemmer
ps = PorterStemmer()
body_keywords = [full,total,abs,legs,butt,upper,arms,back,shoulders,chest,leg,biceps,thighs,glutes,core,triceps,hamstrings,lower,hips,booty]
body_keywords_set =set([ps.stem(tok)fortokinbody_keywords])stem the keywords (since the title is also stemmed.)body_keywords_dict = {ps.stem(tok):tokfortokinbody_keywords}use this dictionary to revert the stemmed words back to the original.workout_type_keywords = [cardio,stretch,strength,hiit,tabata,pilates,yoga]
workout_type_keywords_set =set([ps.stem(tok)fortokinworkout_type_keywords])stem the keywords (since the title is also stemmed.)workout_type_keywords_dict = {ps.stem(tok):tokfortokinworkout_type_keywords}use this dictionary to revert the stemmed words back to the original.other_keywords = [boot camp,bootcamp,burnout,conditioning,bodyweight,circuit,sculpt,agility,resistance,athlete,toned,toning,tone,boxing,kickboxing,plyo,sport,superset,workout,speed]
other_keywords_set =set(other_keywords)
对Youtube副标题展开分词和词干提取
除了关键词,他们还需要对副标题分词和提取词干。这些程序为进一步棋匹配准备了关键字和副标题的列表。
%%timefromnltkimportpos_tagfromnltk.stemimportPorterStemmer
ps = PorterStemmer()clean the titles.defprepare_title(desc):tokenize titles.tokens = word_tokenize(desc)stem words.stemmed_tokens = [ps.stem(tok).lower()fortokintokens]returnset(stemmed_tokens)
df_videos[title_word_set] = df_videos[title].map(prepare_title)
现在,他们已经准备好构建特点了!
第3步:特点工程建设
经过头脑风暴,他们想出了两种与Sydney的YouTube观看相关的主要类型的特点 — 基于关键词和基于时间。让他们一个一个来看。
基于关键词的特点
- 指标特点
由于前面的工作,他们现在有3个关键词列表和精简的副标题。他们现在能匹配它们来对音频展开分类。
对于body_keywords和workout_type_keywords,在一个音频中可能有多个关键词。因此,在匹配之前,他们还创建了两个特点area和锻炼类型。这些特点把所有的身体部位和锻炼类型拼接到一起,成为一个字符串。
例如,一个锻炼音频能同时做ab和leg,或者同时做cardio和strength。这个音频的部位特点是ab+leg,而锻炼类型是cardio+strength。
同时,他们也识别类似的关键字,如total和full,core和ab,并将它们分组。
最后,他们创建了三种不同类型的虚拟特点:
- is_{}_area用来识别一个音频是否包涵了一个特定的身体部分。
- is_{}_workout识别锻炼类型。
- *title_contains_{}*查看锻炼副标题是否包涵其他关键字。
需要说明的是,legs strength burnout workout的音频副标题应该是is_leg_area = True, is_strength_workout = True, title_contains_burnout = True,而其他指标都是False的。
请阅读下面的Python代码以赢得详细信息。
matching the title with the list of single-word keyword using intersectionreturn a string of workout type from the list of keyworddefbody_type(s):body_parts = s.intersection(body_keywords_set)
area_text =forbody_partinbody_parts:ifbody_part ==total:
area_text +=+fullelifbody_part ==core:
area_text +=+abelifbody_partin[glute,booti]:
area_text +=+buttelse:
area_text +=++ body_partifarea_text ==:returnfullreturnarea_text[1:]
df_videos[area] = df_videos[title_word_set].map(body_type)forareainbody_keywords_set:
df_videos[is_{}_area.format(area)] = df_videos[area].str.contains(area)defworkout_type(s):workout_types = s.intersection(workout_type_keywords_set)
num_types = len(workout_types)
workout_text =forworkout_typeinworkout_types:ifnum_types >1andworkout_type ==stretch:continueworkout_text +=++ workout_typeifworkout_text ==:cardio_match = s.intersection(set([sweat,fat]))iflen(cardio_match) >0:
workout_text =+cardioelse:
workout_text =+strengthreturnworkout_text[1:]
df_videos[workout_type] = df_videos[title_word_set].map(workout_type)forworkout_typeinworkout_type_keywords_set:
df_videos[is_{}_workout.format(workout_type)] = df_videos[workout_type].str.contains(workout_type)forotherinother_keywords_set:
df_videos[title_contains_{}.format(other)] = df_videos[title].str.lower().str.contains(other)
- 频率特点
除了这些指标之外,他们还创建了三个特点,分别是num_body_areas、num_workout_types和num_other_keywords。他们计算一个音频副标题中提到的关键词的数量。
举个例子,副标题abs and legs cardio strength workout的num_body_areas和num_workout_types都是2。
这些特点能协助他们确定音频中应该包涵的身体部位或锻炼类型的最佳数量。
area_cols = [colforcolindf_videos.columnsifcol.find(_area) >0]
df_videos[num_body_areas] = df_videos[area_cols].sum(axis=1)
workout_cols = [colforcolindf_videos.columnsifcol.find(_workout) >0]
df_videos[num_workout_types] = df_videos[workout_cols].sum(axis=1)
title_contains_cols = [cforcindf_videos.columnsifc.startswith(title_contains)]
df_videos[num_other_keywords] = np.sum(df_videos[title_contains_cols],axis=1)
- 燃烧率特点
最后但并非最不重要的是,他们创建了一个查看卡路里燃烧率的特点calories_per_min。
毕竟,他们都想要许多明确的(可量化的)锻炼目标。
df_videos[calories_per_min] = df_videos[calories]/df_videos[length]
在介绍基于时间的特点之前,他们还修复了许多分类错误的音频。这个操作过程是手动的,所以这里不包涵这个内容。
基于时间序列的特点
为了回答这个问题,他们还创建了许多基于时间序列的特点:
- num_same_area — 过去30天内发布的关注同一area的音频数量(包括当前的)。例如,当前的音频集中在上半身时,在过去的30天里还有5个上半身的锻炼,这个特点= 6。
- num_same_workout — 这个特点类似于num_same_area,只是计算了锻炼的类型。例如,当前的音频是HIIT锻炼时并且在过去30天内还有另外两个HIIT锻炼,这个特性= 3。
- last_same_area — 上个音频与当前音频关注的身体区域相同间隔的天数。例如,当前音频关注abs,之前的abs音频为10天前,该特点=10。
- last_same_workout — 这个功能类似于last_same_area,只是比较了不同的锻炼类型。
- num_unique_areas — 过去30天内不一样的身体部位的数量。
- num_unique_workouts — 过去30天内发布的不一样的锻炼类型的数量。
这些特点协助他们了解观众是喜欢相似的音频还是喜欢不同类型的音频。请看下面的特点工程建设的详细操作过程。它涉及到许多转换以适应pandas的函数。
prep for time seriesdf_videos = df_videos.sort_values(by=date).reset_index(drop=True)filter out the videos with no dates.msk = ~df_videos[date].isnull()
df_videos = df_videos[msk]start building time-based featuresareas = df_videos[area].unique()
d_areas = {}foriinrange(len(areas)):
d_areas[areas[i]] = iconvert the area, workout_type, workout_int to numeric feature first due to Pandas limitation, must do this for the rolling function.df_videos[area_int] = df_videos[area].replace(d_areas)
workouts = df_videos[workout_type].unique()
d_workouts = {}foriinrange(len(workouts)):
d_workouts[workouts[i]] = imust do this for the rolling function.df_videos[workout_int] = df_videos[workout_type].replace(d_workouts)feature engineering.ignore these rand features for now, they are for future usedf_videos[rand0] = np.random.rand(len(df_videos.index))
df_videos[rand1] = np.random.rand(len(df_videos.index))
df_videos[rand2] = np.random.rand(len(df_videos.index))
df_videos[yyyymmdd] = df_videos[date].dt.year*10000+ df_videos[date].dt.month*100+ df_videos[date].dt.day
df_videos[yyyymm] = (df_videos[yyyymmdd]/100).astype(int)
df_videos[month] = df_videos[date].dt.month_name()
df_videos[day_name] = df_videos[date].dt.day_name()
df_videos[day_of_month] = df_videos[date].dt.dayset the index to the date so we can use the rolling function.df_videos = df_videos.set_index(date)defnum_same_past(areas):
current_area = areas[-1]returnnp.sum(areas == current_area)within the past 30 days, number of workout of the same area/type as the current videodf_videos[num_same_area] = df_videos[area_int].rolling(timedelta(days=30)).apply(num_same_past,raw=True)
df_videos[num_same_workout] = df_videos[workout_int].rolling(timedelta(days=30)).apply(num_same_past,raw=True)deflast_same_past(t):
current_t = t[-1]
current_dte = t.index[-1]
past = t[:(len(t)-1)]
past2 = past[past == current_t]
days_ago = (current_dte - past2.index.max())/timedelta(days=1)ifdays_agoisnp.nan:return9999returndays_agowithin the past 30 days, number of dates the same area/type was posteddf_videos[last_same_area] = df_videos[area_int].rolling(timedelta(days=30)).apply(last_same_past,raw=False)
df_videos[last_same_workout] = df_videos[workout_int].rolling(timedelta(days=30)).apply(last_same_past,raw=False)defnum_unique_past(t):returnt.nunique(dropna=False)within the past 30 days, number of unique areas/workout typesdf_videos[num_unique_areas] = df_videos[area_int].rolling(timedelta(days=30)).apply(num_unique_past,raw=False)
df_videos[num_unique_workouts] = df_videos[workout_int].rolling(timedelta(days=30)).apply(num_unique_past,raw=False)
他们还过滤掉了最已经开始的30天的音频,因为它们缺乏足够的历史统计数据。
filtering out videos dont have effective 30 days windowsonly include the videos after February (the ones before were different).df_videos= df_videos[2018-03-01:2019-12-15]filter out stretches, yoga and non-workouts.msk= (~df_videos[workout_type].isin([none,stretch,yoga])) & (~df_videos[calories].isnull())df_videos= df_videos[msk]
多重共线性测试
多重共线性(又称共线性)是指多元回归模型中的一个预估变量能与其他预估变量展开线性预估,且预估精度相当高的一种现象。
至少在样本统计数据集中,多重共线性并不会降低整座模型的预估能力或可靠性,它只影响关于单个预估变量的计算。
在提出提议时,他们希望回答这些类型的问题。所以他们要确保他们的特点之间没有很强的共线性。
现在他们已经清楚了多重共线性测试的原因。让他们看一看应该用哪种方式。
他们经常采用成对相关来测试共线性,但有时这是不够的。多个特点(多于一对)可能同时存在共线性。
因此,他们采用了一种更复杂的方式。在高层次上,他们采用[K-fold交叉验证](https://machinelearningmastery.com/k- fold.cross -validation/)来同时实现这一点。
具体操作步骤如下:
- 根据他们的判断,选择一组关键特点展开共线性检验。
他们选择了下面的特点,因为它们对于预估YouTube音频的下载量至关重要。
group of critical features selectedcols= [‘length’, ‘calories’, ‘days_since_posted’, ‘area’, ‘workout_type’, ‘num_other_keywords’, ‘day_of_month’, ‘day_name’, ‘month’, ‘num_workout_types’, ‘num_body_areas’, ‘num_same_area’, ‘num_same_workout’, ‘num_unique_areas’, ‘num_unique_workouts’, ‘last_same_area’, ‘last_same_workout’, ‘rand0’, ‘rand1’, ‘rand2’]
正如你所看到的,他们还添加了三个由随机数组成的特点rand0、rand1、rand2。当比较特点之间的关系时,它们充当锚点。假如一个预估特点与这些随机特点相比不那么重要或相似,那么它就不是目标特点的重要预估因子。
- 为K-fold交叉验证准备这些特点。
在这个操作过程中,他们对类别特点和workout_type展开了转换。此转换确保每个类别至少有K个值。
workout_cnts=df_videos[‘workout_type’].value_counts()workout_small_cnts=workout_cnts[workout_cnts < 5].index.valuesd_workout_replace={}forw in workout_small_cnts:d_workout_replace[w]=‘other’area_cnts=df_videos[‘area’].value_counts()area_small_cnts=area_cnts[area_cnts < 5].index.valuesd_area_replace={}fora in area_small_cnts:d_area_replace[a]=‘other’
- 采用其中一个特点作为目标,其他特点作为预估变量来训练预估模型。
接下来,他们对每个特点展开循环,并采用其他特点展开预估拟合一个模型。他们采用了一个简单的模型Gradient model (GBM)和K-fold验证。
根据目标特点是数值的还是类别的,他们应用不同的模型和分数(模型预估能力评估指标)。
当目标特性是数值型时,他们采用Gradient Regressor模型和Root Mean Squared Error (RMSE),当目标特性是类别的,他们采用Gradient boost Classifier模型和Accuracy。
对于每个目标,他们打印出K-fold validation score(分数的平均值)和最重要的5个预估因子。
select numeric columnsdf_numeric = df_videos[cols].select_dtypes(include=[np.number])
numeric_cols = df_numeric.columns.valuesprint(numeric_cols)select non numeric columnsdf_non_numeric = df_videos[cols].select_dtypes(exclude=[np.number])
non_numeric_cols = df_non_numeric.columns.valuesprint(non_numeric_cols)testing for multi collinearity.numericreg = GradientBoostingRegressor(n_estimators=100, max_depth=5,
learning_rate=0.1, loss=ls,
random_state=1)categoricalclf = GradientBoostingClassifier(n_estimators=100, max_depth=5,
learning_rate=0.1, loss=deviance,
random_state=1)try to predict one feature using the rest of others to test collinearity, so its easier to interpret the resultsforc in cols:c is the thing to predict.ifcnotin [rand0,rand1,rand2]:
df_X = df_videos.replace(d_workout_replace).replace(d_area_replace)
df_X[calories] = df_X[calories].fillna(0)only calories should have missing values.X = df_X[cols].drop([c], axis=1)drop the thing to predict.X = pd.get_dummies(X)y= df_X[c]print(c)ifc in non_numeric_cols:
scoring =accuracymodel = clf
scores = cross_val_score(clf, X,y, cv=5, scoring=scoring)print(scoring +": %0.2f (+/- %0.2f)"% (scores.mean(), scores.std() *2))
elif c in numeric_cols:
scoring =neg_root_mean_squared_errormodel = reg
scores = cross_val_score(reg, X,y, cv=5, scoring=scoring)print(scoring.replace(neg_,) +": %0.2f (+/- %0.2f)"% (-scores.mean(), scores.std() *2))else:print(what is this?)
model.fit(X,y)
df_importances = pd.DataFrame(data={feature_name: X.columns,importance: model.feature_importances_}).sort_values(by=importance, ascending=False)
top5_features = df_importances.iloc[:5]print(top 5 features:)print(top5_features)print()
- 研究每个目标特点的得分和重要的预估因子。
他们研究每个目标特点及其与预估变量的关系。他们不会覆盖整座操作过程,只解释下面的两个例子。
他们发现音频长度和卡路里特点是相关的。这个发现很直观,因为锻炼的时间越长,消耗的卡路里越多。
他们能可视化这个关系。
trace=go.Scatter(x=df_videos[length],y=df_videos[calories],mode=markers)layout=dict(xaxis=dict(title=length),yaxis=dict(title=calories))fig=go.Figure(data=[trace], layout=layout)iplot(fig)
正如你所看到的,音频长度和卡路里之间是正相关的。但是相关性还没有强到能丢弃。40-45分钟的音频消耗的卡路里与30-35分钟、50-55分钟甚至60分钟以上的音频消耗的卡路里重叠。因此,他们保留了它们。
同时,他们发现num_same_area和area_full特点是相关的。这一发现有些令人惊讶。让他们来探究一下原因。
下面的图显示了num_same_area和area之间的关系。
trace=go.Scatter(x=df_videos[area],y=df_videos[num_same_area],mode=markers)layout=dict(xaxis=dict(title=area),yaxis=dict(title=num_same_area))fig=go.Figure(data=[trace], layout=layout)iplot(fig)
假设他们发现更高的num_same_area(>=10)确实会导致更高的YouTube访问量。他们无法晓得这是因为area_full还是num_same_area。因此,他们删除了num_same_area特点来防止这种情况。
除此之外,他们还采用类似的逻辑删除了num_same_workouts。
第4步:构建目标变量
你可能还记得,这个项目的目标是增加YouTube的访问量。他们应该仅仅采用浏览的数量作为他们的目标吗?
浏览的分布高度倾斜。音频的平均下载量为27641次,而大部分音频的下载量为130万次。这种偏差可能会给模型的解释带来问题。
因此,他们创建了特点views_quartile,而不是浏览。
他们将音频分为两类 —— 高浏览音频(高)和低浏览音频(低)。高被定义为下载量的75%分位数(35,578)或更高,低是其他。
通过这种方式,他们采用预估模型来寻找产生前25%浏览音频的特点组合。这个新目标提供了稳定的结果和更好的洞察力。
df_videos[views_pct_rank] = df_videos[views].rank(pct=True)
df_videos[views_quartile] = pd.cut(df_videos[views_pct_rank], bins=[0,0.75,1.0], labels=[Q1-Q3,Q4])
第5步:构建计算机程序
最后,他们拥有构建模型所需的一切!
他们在目标views_quartile上训练一个计算机程序模型。
为了避免过拟合,他们将叶子的最小样本数量设置为10。为了便于解释,他们将树的最大深度设置为8。
fromsklearn.treeimportDecisionTreeClassifierfromsklearn.externals.siximportStringIOfromIPython.displayimportImageimportsklearn.treeastreeimportpydotplus
features = df_videos.drop([title,posted_ago,views,link,title_word_set,num_same_workout,area_int,workout_int,views_pct_rank,views_quartile,yyyymmdd,yyyymm,rand0,rand1,rand2], axis=1).columns.values
target =views_quartiledf_X = df_videos[features].fillna(0)
X = df_X[features]
X = pd.get_dummies(X)
y = df_videos[target]
dt = DecisionTreeClassifier(max_depth=8, min_samples_leaf=10)max_depth is maximum number of levels in the treedt.fit(X, y)
dot_data = StringIO()
tree.export_graphviz(dt,
out_file=dot_data,
class_names=[...low,.high],
feature_names=X.columns,the feature names.filled=True,Whether to fill in the boxes with colours.rounded=True,Whether to round the corners of the boxes.special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
Image(graph.create_png())
第6步:理解计算机程序
在最后一步棋中,他们研究并总结了导致高下载量或低下载量的分支。
他们发现的主要见解是什么?
洞察1:每分钟燃烧的卡路里是最重要的特点
是的,卡路里是最重要的特点。人们似乎不太关心锻炼的类型或身体的部位。
在每分钟燃烧热量更高的锻炼中(≥12.025),51/(34+51)=60%的音频有更高的观看率。
而每分钟消耗热量较少(≤9.846)的音频则远不如其他音频受欢迎。只有12/(154+12)= 7.2%的高下载量。
对于每分钟燃烧中等卡路里的音频(9.846到12.025之间),其他因素已经开始起作用。
当然,每个人都想高效地燃烧卡路里!
洞察2:在不同的身体部位展开不同的锻炼并不能提升你的下载量
这种见解与他们想象的有些不同。各种各样的锻炼不是更好吗?
在过去的一个月中,当不一样身体区域的数量(num_unique_area)较高(≥10)时,音频的下载量往往较低。即使每分钟燃烧的卡路里很高,这种说法也是正确的。
结合前两种观点,42/(12+42)= 78%的音频会有更多的观看次数,当:
- 每分钟消耗的热量高(≥12.025)
- 过去一个月中锻炼的不一样的区域数量较少(< 10)
最近一个月提到的太多身体部位可能会让观众感到困惑。
洞察3:臀部锻炼很受欢迎
当一段音频消耗的卡路里较少(calories_per_min ≤9.846)时,5/(10+5)= 33%的人只要是在做臀部锻炼,就会赢得较高的观看率, 然而,只有7/(144+7)= 4.6%的非臀部锻炼有高的下载量。
他们在计算机程序上看不到其他特定的身体部位非常的重要,Sydney的观众想要锻炼的是臀部区域!
获取更多浏览的许多可行的提议
那么,他们有什么策略能推荐给Sydney呢?
策略1:燃烧更多的卡路里
正如他们所看到的,每分钟燃烧的卡路里是最重要的特点。每分钟燃烧12.025卡路里似乎是一个神奇的数字。
下表是一个很好的起点,不同长度的音频应该燃烧多少卡路里:
- 30分钟的锻炼:361卡路里
- 40分钟的锻炼:481卡路里
- 50分钟的锻炼:601卡路里
- 60分钟的锻炼:722卡路里
他们怀疑显示出来的数字(音频长度和卡路里)是心理上的。人们可能喜欢看到卡路里的前两位数比音频长度要大得多。
策略2:少用不同的身体部位
有时少就是多。
人们不喜欢锻炼副标题中描述的太多不一样的身体部位。根据他们的模型,一个月内专注于少于10个身体部位的组合会更好。
他们注意到Sydney在她最近的音频中采用了更少的身体部位关键词。最明显的一个是她一直在采用arms或upper body,而不是biceps或back这样的词。
策略3:更多的臀部锻炼
Sydney的订阅者可能更多是女性,她们更关注臀部的锻炼,而不是肌肉发达的手臂。人们愿意牺牲燃烧更少的卡路里来赢得更健美的臀部。也许Sydney 应该在燃烧更少卡路里的音频中加入许多臀部运动。
额外的策略
除了上述策略外,还有其他值得进一步棋研究的思路。
例如,Sydney能尝试:
- 在月初发起新的活动本月初发布的音频更有可能赢得更高的下载量。也许人们喜欢设定新的目标来已经开始新的一个月。
- 避免在5天内发布相同类型的锻炼。
这是一个他们正在尝试探索的应用,以提升YouTube的下载量。有许多限制:
- 这些提议是根据过去的经验提出的。YouTube用户倾向于尝试过去常规之外的创新想法。考虑到这一点,他们能将机器学习应用到他们的竞争对手身上,从而赢得真正的洞察。
- 他们只对副标题展开分析。有其他统计数据,比如音频的字幕能被截取。它们也可能包涵有价值的见解。
- 他们的统计数据比YouTube电音频道的所有者少。还有其他关键信息,比如用户统计统计数据。可能会有更多的特点,更多的见解,以及对这些见解的更好的解释。
英文原文:https://www.justintodata.com/get-more-youtube-views-with-machine-learning/