销售与数据科学:使用Python进行竞争者分析的逐步指南

359 阅读10分钟

是什么让卖家在亚马逊或eBay等在线市场上取得成功?数据科学有助于回答这个问题。

像亚马逊或eBay这样的在线市场,每一步都充满了卖家之间的竞争。当其他人提供的产品与你的产品非常相似时,要提高销量并不容易。

你有没有想过,如果他们都提供几乎相同的东西,是什么让买家选择一个卖家而不是另一个?

你可能在想,这一切都归结于价格。

我也是这样想的,但后来我禁不住诱惑,想看看是否有其他因素在这里起作用。

在这篇文章中,我站在一个在线卖家的立场上,看看使用Python编程工具的数据驱动方法如何能帮助回答这个问题。

为了做到这一点,我采取了两个步骤。

第一步:找到一个在线市场,其中有丰富的关于销售历史的内容.这篇文章是出于教育目的而写的,所以我想对市场的名字保密。

第二步:想出一个可以比较不同报价的方法。这里的诀窍是找到一个有许多类似变体的产品,并由大量卖家销售。我为这项研究挑选的在线市场上最常销售的产品之一是我们都使用的东西。

智能手机屏幕保护膜

在这篇文章中,我将提出并回答4个问题。

Q1.我们的产品类型的平均价格是多少?

Q2.定价如何影响可销售性?

Q3.最受欢迎的屏幕保护器品牌有哪些?

Q4.哪些品牌是最有利可图的?

交易的工具

Python--我们在数据科学方面的首选编程语言。

Python工具:

  • Scrapy--这个网络抓取/爬行框架提供了方便的功能,如对字段值进行编排和预处理。你可以通过在线scrapinghub平台运行它,这有助于使你的抓取过程不那么费力。
  • Pandas--我将用它来把数据加载到表中(然后进行清理、处理和分析)。
  • Seaborn和Matplotlib - 这些是一些方便的Python数据可视化库。

数据挖掘和准备

1.获取数据

第一步是找到一个数据源。我需要选择一个能提供某种销售业绩指标的在线市场--这样我才能对照其他的报价功能来评估它。我挑选的平台提供最近100笔交易的信息。

注意:网络爬虫的代码内容相当多,对于不同的市场网站会有所不同,所以我决定在本文中不包括搜刮代码的例子。用于搜刮和网络爬行的Python框架Scrapy提供了大量的文档,其中有简单易懂的教程,如果需要,可以参考一下。

以下是关于我如何获得本文数据的简短描述。

首先,我在在线市场上手动搜索智能手机屏幕保护器,并从那里开始抓取过程。通常情况下,搜索模式以某种报价清单开始,每个清单都指向一个有更多信息的项目专用页面,甚至可能是过去购买的清单。

请注意,你通常可以在搜索结果列表中收获关于产品介绍的有价值的信息(如卖家的状态、积分、过去购买的数量)。毕竟,这是客户第一次接触到该产品,可能会影响他们的决策过程。

在抓取之后,我最终得到了两个Pandas表。主表(df)有所有的产品信息,每一行对应一个项目。另一个表(sale_history),存储了关于过去购买的信息,每个产品包括许多行的单独销售事件数据。

稍后我将向你展示这些表的例子。

2.处理数据

在数据提取步骤之后,是时候做一些清洗和数据准备了。除了所有的常规步骤(去除空值,将列转换成正确的数据类型,等等),还有几个有趣的步骤,我想在这里提一下--还是那句话,不谈细节。

作为第一步,我倾向于用Pandas unique()方法来检查各个列。这样我就可以看到这些值是否一致和合理--并抓住任何潜在的问题。然后,我通过对作为特定项目唯一标识符的列进行分组来检查数据的重复性--在本例中,我使用了product_id。

我注意到的第一件事是,一些产品页面被链接到搜索结果页面的多个列表中(巧合吗?)我去掉了这些重复的信息,但决定保留这些信息进行分析。因此,我先创建了一个新的列,列出了每个商品的列表数量,然后删除了除一个以外的副本。

df['same_offer_count'] = df.groupby('product_id')['product_id'].transform('count')
df = df.drop_duplicates(subset='product_id', keep='first')

另一个有趣的问题是处理整个市场上使用的多种货币。我的原始数据表包含了光秃秃的价格字符串值和所引用的货币符号(例如,'US 1.09C1.09'或'C 2.42'),所以我需要提取数字值,并通过将它们转换为美元来统一所有的价格货币。下面是一些转换前的例子行。

这是我用来转换的代码:

import re

from currency_converter import CurrencyConverter

cc = CurrencyConverter() currency_shortcuts = {'C':'CAD', 'US':'USD', 'AU':'AUD'} # first I checked only these occur... regx_str=r'(\\w+\\s\*)\\$[ ]?(\\d+[.|,]?\\d+)' # note the two ‘re’ groups! df[['currency', 'quoted_price']] = df['current_price'].str.extract(pat=regx_str) df['currency'] = df['currency'].str.replace(' ', '') df['currency'] = df['currency'].map(currency_shortcuts) df['price_USD'] = df['quoted_price'].copy() for currency in [ c for c in df['currency'].unique() if c not in ['USD']]: fltr = df['currency'].isin([currency]) df.loc[fltr, 'price_USD'] = df.loc[fltr, 'quoted_price']\\ .apply(lambda x: cc.convert(x, currency, 'USD')) 

这导致了。

接下来,我处理了销售历史表(sale_history)。我进行了一些基本的类型修正,提取并转换了价格和货币,并填写了空值(代码未显示)。最后我得到了这个表(同样,它只是一个行的快照)。

为了使它对我的分析和绘图有用,我按日期(当然还有产品ID)汇总了这些条目,并计算了已售商品的数量和每日销售率。把所有这些都包在一个函数中,可以把它逐行应用到数据框中。

def calculate_sale_history_stats(df):
    “””Calculates statistics on sale history, returns new dataframe”””    
    delta = df['purchase_date'].max() - df['purchase_date'].min()
    days = int(delta.days)
    values = list(df['quantity_sold'])
    earnings = list(df['total_price'])
    sold_count = sum(values)
    
    if len(values) < days:
        values.extend([0]*(len(values) - days))
        earnings.extend([0]*(len(earnings) - days))
    
    res = pd.Series(        [sold_count, np.mean(values), np.std(values), np.mean(earnings), np.std(earnings)], 
        index=['Sold_count',                
'Mean_daily_sold_count', 'Sold_count_St.Dev',                
'Daily_earnings', 'Daily_earnings_St.Dev']    )  
    return round(res, 2)

并将其应用于sale_history数据帧:

sale_history_stats = sale_history.groupby('brand').apply(calculate_sale_history_stats)

结果是:

最后,我把汇总的销售统计数字(sale_history_stats)合并到主df表中:

df = pd.merge(
    how='left',
    on='product_id',
    left=aggreg_sale_history,
    right=df[['product_id','shipping_cost', 'shipping_from', 'top_rating_badge',
              'seller_feedback_score', 'seller_feedback_perc',]]
)

下面是产生的df表(同样,只显示了一部分列)。

现在我们可以开始了。所以,让我们开始我们的竞争对手分析。

Q1:我们产品类型的平均价格是多少?

让我们看看我们能从屏幕保护器中获得多少利润,一般来说。卖家对这种类型的产品一般收取多少钱?

我可以分析一下市场上的价格,看看顾客通常为这样的智能手机屏幕保护器支付多少钱。

import matplotlib.pyplot as plt import seaborn as sns
prices = df['price_USD']

sns.distplot(df['price_USD'], ax=ax, bins=200)

paid_prices = sale_history['sell_price']

sns.distplot(paid_prices, ax=ax, bins=100)

这里是两个产生的直方图,上面覆盖了额外的信息(代码未显示):

正如你所看到的,大多数屏幕保护膜的价格约为1.15美元(平均3.9美元)。然而,似乎客户往往喜欢在购买时多花几块钱(平均5美元,中位数~3.8美元)。在这里,'越便宜越好'的规则并不适用。

基于这种洞察力,我们可以假设,选择将我们的产品定价在4美元左右就能完成任务。

问题2:定价如何影响可销售性?

定价可能是客户决策过程中最重要的因素。卖家通常认为,高价可能会使消费者不愿意购买他们的产品。在盈利性和可负担性之间取得适当的平衡可能成为一项挑战。

让我们检查一下售出的商品数量和每日收入与单价的匹配情况(作为每日平均值)。

# The daily earnings vs price:
sns.lmplot(x='sell_price', y='Daily_earnings', 
           data=df[['sell_price', 'Daily_earnings']])

# Plot the sales frequency vs price:
sns.lmplot(x='sell_price', y='Mean_daily_sold_count', 
           data=df[['sell_price', 'Mean_daily_sold_count']],)

正如预期的那样,较高的价格意味着平均较少的销售。但是当我们看每天的收入时,似乎利润往往随着价格的提高而增加。

在这一点上,找出定价是否反映了产品的质量和/或声誉是很有趣的。不幸的是,这已经超出了本研究的范围。

Q3.最受欢迎的屏幕保护器品牌有哪些?

让我们仔细看看品牌名称。有一个指 "没有品牌 "的价值谱。

所以我们先把这个乱七八糟的东西清理一下,把它们都标为 "无品牌":

df['brand'] = df['brand'].apply(
     lambda s: 'Unbranded' if s in          
['Does not apply', 'Does Not Apply', 'Unbranded/Generic', ‘unbranded']   else s)

现在我可以把数据放到工作中,得到一个显示品牌名称的饼状图。它表明,在我们的在线市场上提供的大多数产品(约60%)根本没有品牌(或没有表明品牌)。

消费者可能希望坚持使用一个可识别的名字,因此,让我们暂时忽略未命名的产品,而是关注市场上提供的每日销售数量最多的前20个品牌。

为此,我将使用我们的带有所有交易数据的sale_history表。

让我们创建一个包含市场上提供的品牌信息的表:

sold_brands = sale_history.groupby('brand').apply(calculate_sale_history_stats)

接下来,让我们看看到目前为止记录了最高销售数量的前10个品牌--创建一个表格并像这样绘制:

top_sold_brands = sold_brands.sort_values(
    by=['Sold_count', 'Daily_earnings', 'Mean_daily_sold_count'], 
    ascending=False).reset_index()

sns.barplot(data=top_sold_brands.iloc[1:21], x='brand', y='Sold_count')

一眼就能看出,所有未命名的品牌加起来都积累了最高的销售数量。然而,Spigen似乎是这个类别的亚军,在命名品牌产品中占据了市场。

Q4.哪些品牌最有利可图?

哪些屏幕保护器品牌在最短的时间内为卖家带来最高的收入?让我们把非品牌产品带回到桌面上,因为在收益方面,情况可能会略有不同。

most_profitable_brands = sold_brands.sort_values(    
by=['Daily_earnings', 'Mean_daily_sold_count', 'Sold_count'],    
ascending=False).reset_index()
most_profitable_brands = most_profitable_brands[[    
'brand', 'Daily_earnings', 'Daily_earnings_St.Dev','Sold_count',     'Mean_daily_sold_count', 'Mean_Sold_count_St.Dev']]

我得到这个表:

让我们在柱状图上这样可视化一下:

plt.bar(x, y, width=0.85, yerr=y_err, alpha=0.7, color='darkgrey', ecolor='black')

这应该会产生下面的图表:

现在很明显,无品牌的产品并不那么有利可图。请注意,当我们比较收入而不是销售商品的总数时,品牌的顺序发生了很大的变化。具有中档价格的品牌现在排在榜首(如价格约为9.5美元的PureGear)。而这是在他们相对不频繁的日销售率(约每天1-2件)的情况下。

回答这4个问题让我们看到,"质量高于数量 "可能是制定在线市场销售策略的最明智的方式。

---

在这篇文章中,我重点带大家了解了数据挖掘和准备过程,最终回答了关于我为这项研究选择的网上市场销售趋势的四个关键问题。

以下是我可以从数据中回答的一些其他问题

  • 运输成本是否影响客户的决定?
  • 有多少卖家为其产品打折?
  • 折扣是否会带来更高的销售额?
  • 对顾客来说,从哪里购买产品有什么区别吗?
  • 卖家的反馈分数如何影响销售?
  • 拥有Top Rated徽章是否能促进产品销售?

幸运的是,我已经做了这些。