什么是 CTR 曲线以及如何用 Python 计算它?
已发表: 2022-03-22点击率曲线,或者换句话说基于位置的有机点击率,是显示搜索引擎结果页面 (SERP) 上有多少蓝色链接根据其位置获得点击率的数据。 例如,大多数时候,SERP 中的第一个蓝色链接获得的点击率最高。
在本教程结束时,您将能够根据其目录计算您网站的 CTR 曲线,或根据 CTR 查询计算自然 CTR。 我的 Python 代码的输出是一个描述站点 CTR 曲线的有见地的箱形图和条形图。
如果您是初学者并且不知道 CTR 的定义,我将在下一节中详细解释。
什么是自然点击率或自然点击率?
点击率来自于将自然点击次数划分为展示次数。 例如,如果 100 人搜索“苹果”,30 人点击第一个结果,则第一个结果的 CTR 为 30 / 100 * 100 = 30%。
这意味着从每 100 次搜索中,您可以获得 30% 的搜索。 请务必记住,Google Search Console (GSC) 中的展示次数并非基于您的网站链接在搜索者视口中的外观。 如果结果出现在搜索者 SERP 上,则每次搜索都会获得一次展示。
CTR曲线的用途是什么?
搜索引擎优化的重要主题之一是自然流量预测。 为了提高某些关键字的排名,我们需要分配成千上万的美元来获得更多的份额。 但公司营销层面的问题通常是:“我们分配这笔预算是否具有成本效益?”。
此外,除了 SEO 项目的预算分配主题外,我们还需要估计我们未来的自然流量增加或减少。 例如,如果我们看到我们的一个竞争对手试图在我们的 SERP 排名位置上取代我们,这将花费我们多少钱?
在这种情况或许多其他情况下,我们需要我们网站的 CTR 曲线。
为什么我们不使用 CTR 曲线研究并使用我们的数据?
简单地说,在 SERP 中没有任何其他网站具有您的网站特征。
不同行业和不同 SERP 功能的 CTR 曲线有很多研究,但是当您有数据时,为什么您的网站不计算 CTR 而不是依赖第三方来源?
让我们开始这样做吧。
使用 Python 计算 CTR 曲线:入门
在深入了解Google基于位置的点击率计算过程之前,您需要了解基本的Python语法,并对常见的Python库(如Pandas)有基本的了解。 这将帮助您更好地理解代码并以您的方式对其进行自定义。
此外,对于这个过程,我更喜欢使用 Jupyter notebook 。
为了根据位置计算有机点击率,我们需要使用这些 Python 库:
- 熊猫
- 情节
- 万花筒
此外,我们将使用这些 Python 标准库:
- 操作系统
- json
正如我所说,我们将探索两种不同的计算 CTR 曲线的方法。 两种方法的一些步骤是相同的:导入 Python 包、创建绘图图像输出文件夹和设置输出绘图大小。
# 为我们的流程导入所需的库 导入操作系统 导入json 将熊猫导入为 pd 将 plotly.express 导入为 px 将 plotly.io 导入为 pio 进口万花筒
在这里,我们创建一个输出文件夹来保存我们的绘图图像。
# 创建绘图图像输出文件夹 如果不是 os.path.exists('./output plot images'): os.mkdir('./输出绘图图像')
您可以更改下面输出绘图图像的高度和宽度。
# 设置输出绘图图像的宽度和高度 pio.kaleido.scope.default_height = 800 pio.kaleido.scope.default_width = 2000
让我们从第一种基于查询 CTR 的方法开始。
第一种方法:根据查询CTR计算整个网站或特定URL属性的CTR曲线
首先,我们需要获取所有查询及其点击率、平均排名和展示次数。 我更喜欢使用过去一个月的一整月数据。
为此,我从 Google Data Studio 中的 GSC 网站印象数据源获取查询数据。 或者,您可以以任何您喜欢的方式获取此数据,例如 GSC API 或“搜索表格分析”Google 表格插件。 这样,如果您的博客或产品页面具有专用的 URL 属性,您可以将它们用作 GDS 中的数据源。
1. 从 Google Data Studio (GDS) 获取查询数据
去做这个:
- 创建报告并向其中添加表格图表
- 将您的网站“网站印象”数据源添加到报告中
- 维度选择“query”,metric选择“ctr”、“average position”和“'impression”
- 通过创建过滤器过滤掉包含品牌名称的查询(包含品牌的查询会有更高的点击率,这会降低我们数据的准确性)
- 右键单击表,然后单击导出
- 将输出另存为 CSV
2. 加载我们的数据并根据它们的位置标记查询
为了操作下载的 CSV,我们将使用 Pandas。
我们项目文件夹结构的最佳实践是有一个“数据”文件夹,我们在其中保存所有数据。
在这里,为了教程的流畅性,我没有这样做。
query_df = pd.read_csv('./downloaded_data.csv')
然后我们根据查询的位置标记查询。 我创建了一个“for”循环来标记位置 1 到 10。
例如,如果查询的平均位置是 2.2 或 2.9,它将被标记为“2”。 通过操纵平均位置范围,您可以达到您想要的精度。
对于范围内的 i (1, 11): query_df.loc[(query_df['平均位置'] >= i) & ( query_df['平均位置'] < i + 1), '位置标签'] = i
现在,我们将根据查询的位置对查询进行分组。 这有助于我们在接下来的步骤中以更好的方式操作每个位置查询数据。
query_grouped_df = query_df.groupby(['位置标签'])
3. 根据数据过滤查询以进行 CTR 曲线计算
计算 CTR 曲线的最简单方法是使用所有查询数据并进行计算。 然而; 不要忘记考虑那些在您的数据中位置 2 有一次展示的查询。
根据我的经验,这些查询会对最终结果产生很大影响。 但最好的方法是自己尝试。 根据数据集,这可能会改变。
在我们开始这一步之前,我们需要为我们的条形图输出创建一个列表,并为存储我们操作的查询创建一个 DataFrame。
# 创建一个 DataFrame 用于存储 'query_df' 操作数据 modified_df = pd.DataFrame() # 为我们的条形图保存每个位置平均值的列表 mean_ctr_list = []
然后,我们遍历query_grouped_df
组,并将基于展示次数的前 20% 查询附加到modified_df
数据帧。
如果仅根据展示次数最多的前 20% 的查询计算 CTR 对您来说不是最好的,您可以更改它。
为此,您可以通过操作.quantile(q=your_optimal_number, interpolation='lower')]
来增加或减少它,并且your_optimal_number
必须介于 0 到 1 之间。
例如,如果您想获得前 30% 的查询, your_optimal_num
是 1 和 0.3 (0.7) 之间的差值。
对于范围内的 i (1, 11): # 一个 try-except 用于处理目录中某些位置没有任何数据的情况 尝试: tmp_df = query_grouped_df.get_group(i)[query_grouped_df.get_group(i)['impressions'] >= query_grouped_df.get_group(i)['impressions'] .quantile(q=0.8, 插值='lower')] mean_ctr_list.append(tmp_df['ctr'].mean()) modified_df = modified_df.append(tmp_df, ignore_index=True) 除了 KeyError: mean_ctr_list.append(0) # 删除 'tmp_df' DataFrame 以减少内存使用 删除 [tmp_df]
4.绘制箱线图
这一步是我们一直在等待的。 要绘制绘图,我们可以使用 Matplotlib、seaborn 作为 Matplotlib 的包装器或 Plotly。
就个人而言,我认为使用 Plotly 最适合喜欢探索数据的营销人员。
与 Mathplotlib 相比,Plotly 非常易于使用,只需几行代码,您就可以绘制出漂亮的绘图。
# 1. 箱线图 box_fig = px.box(modified_df, x='位置标签', y='网站点击率', title='根据位置查询点击率分布', points='all', color='position label', labels={'position label': 'Position', 'Site CTR': 'CTR'}) # 显示所有十个 x 轴刻度 box_fig.update_xaxes(tickvals=[i for i in range(1, 11)]) # 将 y 轴刻度格式更改为百分比 box_fig.update_yaxes(tickformat=".0%") # 将绘图保存到“输出绘图图像”目录 box_fig.write_image('./output plot images/Query box plot CTR curve.png')
只需这四行,您就可以获得漂亮的箱线图并开始探索您的数据。
如果要与此列交互,请在新单元格中运行:
box_fig.show()
现在,您在输出中有一个有吸引力的交互式箱线图。
当您将鼠标悬停在输出单元格中的交互式绘图上时,您感兴趣的重要数字是每个位置的“人”。
这显示了每个位置的平均点击率。 正如您所记得的,由于平均重要性,我们创建了一个包含每个位置的平均值的列表。 接下来,我们将继续下一步,根据每个位置的平均值绘制条形图。
5.绘制条形图
就像箱线图一样,绘制条形图非常容易。 您可以通过修改px.bar()
的title
参数来更改图表的title
。
# 2. 条形图 bar_fig = px.bar(x=[pos for pos in range(1, 11)], y=mean_ctr_list, title='查询基于位置的平均点击率分布', 标签={'x': '位置', 'y': '点击率'}, text_auto=True) # 显示所有十个 x 轴刻度 bar_fig.update_xaxes(tickvals=[i for i in range(1, 11)]) # 将 y 轴刻度格式更改为百分比 bar_fig.update_yaxes(tickformat='.0%') # 将绘图保存到“输出绘图图像”目录 bar_fig.write_image('./output plot images/Queries bar plot CTR curve.png')
在输出中,我们得到这个图:
与箱线图一样,您可以通过运行bar_fig.show()
与此图进行交互。
而已! 只需几行代码,我们就可以根据查询数据的位置获得自然点击率。
如果您的每个子域或目录都有一个 URL 属性,则可以获取这些 URL 属性查询并计算它们的 CTR 曲线。
[案例研究] 通过日志文件分析提高排名、自然访问量和销售额
第二种方法:根据每个目录的着陆页 URL 计算 CTR 曲线
在第一种方法中,我们根据查询 CTR 计算了自然 CTR,但是通过这种方法,我们获取了所有着陆页数据,然后计算我们选择的目录的 CTR 曲线。
我喜欢这种方式。 如您所知,我们产品页面的点击率与我们的博客文章或其他页面的点击率大不相同。 每个目录都有基于位置的自己的点击率。
以更高级的方式,您可以对每个目录页面进行分类,并根据一组页面的位置获得 Google 的自然点击率。
1.获取登陆页面数据
与第一种方法一样,有多种方法可以获取 Google Search Console (GSC) 数据。 在这种方法中,我更喜欢从 GSC API Explorer 获取登录页面数据:https://developers.google.com/webmaster-tools/v1/searchanalytics/query。
对于这种方法所需的内容,GDS 不提供可靠的登录页面数据。 此外,您可以使用“搜索表格分析”Google 表格插件。
请注意,Google API Explorer 非常适合那些数据页数少于 25K 的网站。 对于较大的站点,您可以获取部分登录页面数据并将它们连接在一起,编写带有“for”循环的 Python 脚本以从 GSC 中获取所有数据,或使用第三方工具。
要从 Google API Explorer 获取数据:
- 导航到“搜索分析:查询”GSC API 文档页面:https://developers.google.com/webmaster-tools/v1/searchanalytics/query
- 使用页面右侧的 API Explorer
- 在“siteUrl”字段中,插入您的 URL 属性地址,例如
https://www.example.com
。 此外,您可以按如下方式插入域属性sc-domain:example.com
- 在“请求正文”字段中添加
startDate
和endDate
。 我更喜欢获取上个月的数据。 这些值的格式是YYYY-MM-DD
- 添加
dimension
并将其值设置为page
- 创建一个“dimensionFilterGroups”并过滤掉带有品牌变体名称的查询(用您的品牌名称 RegExp 替换
brand_variation_names
) - 添加
rawLimit
并将其设置为 25000 - 最后按下“执行”按钮
您还可以复制并粘贴下面的请求正文:
{ "开始日期": "2022-01-01", "endDate": "2022-02-01", “方面”: [ “页” ], “维度过滤器组”:[ { “过滤器”:[ { “维度”:“查询”, "表达式": "brand_variation_names", “操作员”:“EXCLUDING_REGEX” } ] } ], “行限制”:25000 }
请求执行后,我们需要保存它。 由于响应格式的原因,我们需要创建一个 JSON 文件,复制所有 JSON 响应,并使用downloaded_data.json
的_data.json 文件名保存它。
如果您的站点很小,例如 SASS 公司站点,并且您的目标网页数据少于 1000 页,您可以轻松地在 GSC 中设置日期,并将“PAGES”选项卡的目标网页数据导出为 CSV 文件。
2.加载登陆页面数据
在本教程中,我假设您从 Google API Explorer 获取数据并将其保存在 JSON 文件中。 为了加载这些数据,我们必须运行以下代码:
# 为下载的数据创建一个DataFrame 使用 open('./downloaded_data.json') 作为 json_file: 着陆数据 = json.loads(json_file.read())['rows'] Landings_df = pd.DataFrame(landings_data)
此外,我们需要更改列名以赋予其更多含义,并应用一个函数直接在“着陆页”列中获取着陆页 URL。
# 将“keys”列重命名为“landing page”列,并将“landing page”列表转换为 URL Landings_df.rename(columns={'keys': '登陆页面'}, inplace=True) 登陆_df['登陆页'] = 登陆_df['登陆页'].apply(lambda x: x[0])
3.获取所有登陆页面根目录
首先,我们需要定义我们的站点名称。
# 在引号之间定义您的站点名称。 例如,“https://www.example.com/”或“http://mydomain.com/” 站点名称 = ''
然后我们在登录页面 URL 上运行一个函数来获取它们的根目录并在输出中查看它们以选择它们。
# 获取每个登陆页面(URL)目录 登陆_df['目录'] = 登陆_df['登陆页面'].str.extract(pat=f'((?<={site_name})[^/]+)') # 为了获取输出中的所有目录,我们需要操作 Pandas 选项 pd.set_option("display.max_rows", 无) # 网站目录 登陆_df['目录'].value_counts()
然后,我们选择需要获取哪些目录的点击率曲线。
将目录插入important_directories
变量中。
例如, product,tag,product-category,mag
。 用逗号分隔目录值。
重要目录 = '' important_directories = important_directories.split(',')
4. 标记和分组登陆页面
与查询一样,我们也根据着陆页的平均位置标记着陆页。
# 标记着陆页位置 对于范围内的 i (1, 11): Landings_df.loc[(landings_df['位置'] >= i) & ( Landings_df['位置'] < i + 1), '位置标签'] = i
然后,我们根据着陆页的“目录”对着陆页进行分组。
# 根据“目录”值对登录页面进行分组 登陆_grouped_df = 登陆_df.groupby(['目录'])
5. 为我们的目录生成箱形图和条形图
在之前的方法中,我们没有使用函数来生成绘图。 然而; 为了自动计算不同着陆页的点击率曲线,我们需要定义一个函数。
# 创建和保存每个目录图表的功能 def each_dir_plot(dir_df, key): # 根据“位置标签”值对目录登录页面进行分组 dir_grouped_df = dir_df.groupby(['位置标签']) # 创建一个用于存储 'dir_grouped_df' 操作数据的 DataFrame modified_df = pd.DataFrame() # 为我们的条形图保存每个位置平均值的列表 mean_ctr_list = [] ''' 循环遍历 'query_grouped_df' 组并将基于展示次数的前 20% 查询附加到 'modified_df' DataFrame。 如果仅根据展示次数最多的前 20% 的查询计算 CTR 对您来说不是最好的,您可以更改它。 要更改它,您可以通过操作 '.quantile(q=your_optimal_number, interpolation='lower')]' 来增加或减少它。 “you_optimal_number”必须介于 0 到 1 之间。 例如,如果您想获得前 30% 的查询,'your_optimal_num' 是 1 和 0.3 (0.7) 之间的差值。 ''' 对于范围内的 i (1, 11): # 一个 try-except 用于处理目录中某些位置没有任何数据的情况 尝试: tmp_df = dir_grouped_df.get_group(i)[dir_grouped_df.get_group(i)['impressions'] >= dir_grouped_df.get_group(i)['impressions'] .quantile(q=0.8, 插值='lower')] mean_ctr_list.append(tmp_df['ctr'].mean()) modified_df = modified_df.append(tmp_df, ignore_index=True) 除了 KeyError: mean_ctr_list.append(0) # 1. 箱线图 box_fig = px.box(modified_df, x='位置标签', y='ctr', title=f'{key}目录CTR分布基于位置', points='all', color='position label', labels={'position label': 'Position', 'ctr': 'CTR'}) # 显示所有十个 x 轴刻度 box_fig.update_xaxes(tickvals=[i for i in range(1, 11)]) # 将 y 轴刻度格式更改为百分比 box_fig.update_yaxes(tickformat=".0%") # 将绘图保存到“输出绘图图像”目录 box_fig.write_image(f'./output plot images/{key}目录-Box plot CTR curve.png') # 2. 条形图 bar_fig = px.bar(x=[pos for pos in range(1, 11)], y=mean_ctr_list, title=f'{key} 目录基于位置的平均点击率分布', 标签={'x': '位置', 'y': '点击率'}, text_auto=True) # 显示所有十个 x 轴刻度 bar_fig.update_xaxes(tickvals=[i for i in range(1, 11)]) # 将 y 轴刻度格式更改为百分比 bar_fig.update_yaxes(tickformat='.0%') # 将绘图保存到“输出绘图图像”目录 bar_fig.write_image(f'./output plot images/{key}目录-条形图点击率曲线.png')
在定义了上述函数之后,我们需要一个“for”循环来遍历我们想要获取其 CTR 曲线的目录数据。
# 遍历目录并执行 'each_dir_plot' 函数 对于键,landings_grouped_df 中的项目: 如果在重要目录中键入: each_dir_plot(项目,键)
在输出中,我们在output plot images
文件夹中获取绘图。
进阶提示!
您还可以使用查询登录页面计算不同目录的 CTR 曲线。 通过对功能进行一些更改,您可以根据其登录页面目录对查询进行分组。
您可以使用下面的请求正文在 API Explorer 中发出 API 请求(不要忘记 25000 行限制):
{ "开始日期": "2022-01-01", "endDate": "2022-02-01", “方面”: [ “询问”, “页” ], “维度过滤器组”:[ { “过滤器”:[ { “维度”:“查询”, "表达式": "brand_variation_names", “操作员”:“EXCLUDING_REGEX” } ] } ], “行限制”:25000 }
使用 Python 自定义 CTR 曲线计算的技巧
为了获得更准确的数据来计算 CTR 曲线,我们需要使用第三方工具。
例如,除了知道哪些查询具有特色片段外,您还可以探索更多 SERP 功能。 此外,如果您使用第三方工具,您可以根据 SERP 功能获取具有该查询的着陆页排名的查询对。
然后,使用其根(父)目录标记登录页面,根据目录值对查询进行分组,考虑 SERP 功能,最后根据位置对查询进行分组。 对于 CTR 数据,您可以将 GSC 中的 CTR 值合并到其对等查询中。