如果你是一名数据分析师,要让你为你们公司的某类产品寻求市场增长点,你会怎么做呢?
下图是我用xmind整理的一个分析框架:
本次项目具体内容大家可以从1.1小节的项目背景开始进行了解,而前言这一部分是我这段时间在学习数据分析这一领域知识的过程中慢慢整理总结出来的,有任何错误还请大家不吝赐教。
前言这一部分是我这段时间在学习数据分析这一领域知识的过程中慢慢整理总结出来的,有任何错误还请大家不吝赐教。
其中这个数据采集排期的话中小公司用的比较多一点,而大公司是有自己的灰度发布系统的(已经埋好点了)。
另外,通过建模等分析后输出分析报告之后,也要再和产品经理反复沟通确定结论。
评判市场和品牌的发展趋势和增长情况,从宏观到微观,从大市场到细分市场:
这里大家也可以发现,这里很多的业务都是可以用分类的算法来实现的。
这里的相对市场份额我们可以理解为销售额。
我们可以把产品都分成四种类型:问题类(成长期)、明星类(成熟期)、奶牛类(稳定期)、瘦狗类(衰退期)。
我们拿到产品的数据后我们就可以判断产品是属于哪一类的,判断是不是有提升空间。
像腾讯旗下的手游王者荣耀就属于奶牛类产品,当它想要一些稳定的现金流的话,就可以出个活动,相当于挤挤奶,这就是奶牛类产品。
这里我们简单了解一下就可以了。
问题:销售额下降,怎么办?
这个问题其实很大,比方说电商类的产品方法有:优化老客户、扩大流量、提高转化率等等。这种问题也是需要我们一步步来拆分的。具体操作可以如下:
像上面提到的流量,还可以接着细分成站内流量和站外流量,而站内流量还可以分成全部流量和每个商品流量(详情页的访问),我们需要不断的拆分问题,直至不能拆分为止。
那下面我们开始正式介绍我们此次项目的背景啦。
接着我介绍一下本次项目的背景与其产品架构。
本次项目已有的数据十分齐全。
老规矩,先导包,设置一下中文编码。
import glob #读文件
import os #设置工作路径
import pandas as pd
import re #正则表达式
import numpy as np
import datetime as dt #时间包
from sklearn.linear_model import LinearRegression
import seaborn as sns
from matplotlib import pyplot as plt
import jieba #分词
import jieba.analyse
import imageio #配合做词云的
from wordcloud import WordCloud #词云
# 中文编码
plt.rcParams['font.sans-serif']='simhei'
plt.rcParams['axes.unicode_minus']=False
sns.set_style("darkgrid",{
"font.sans-serif":['simhei','Droid Sans Fallback']})
os.chdir('E:\Data-analysis-project\电商文本挖掘\data/') # 工作路径
os.chdir('./驱虫剂市场')
filenames = glob.glob('*市场近三年交易额.xlsx')
filenames
输出结果:
['灭鼠杀虫剂市场近三年交易额.xlsx',
'电蚊香套装市场近三年交易额.xlsx',
'盘香灭蟑香蚊香盘市场近三年交易额.xlsx',
'蚊香加热器市场近三年交易额.xlsx',
'蚊香液市场近三年交易额.xlsx',
'蚊香片市场近三年交易额.xlsx',
'防霉防蛀片市场近三年交易额.xlsx']
re.search(r'.*(?=市场)',"盘香灭蟑香蚊香盘市场近三年交易额.xlsx",).group() # 匹配市场之前的wenb
‘盘香灭蟑香蚊香盘’
def load_xlsx(filename):
#抽取子类目的名字
colname = re.search(r'.*(?=市场)',filename).group()
#读取文件
df = pd.read_excel(filename)
#修改日期的格式(原本是文本格式)
if df['时间'].dtypes == 'int64':
df['时间'] = pd.to_datetime(df['时间'],unit='D',origin=pd.Timestamp('1899-12-30')) # 系统默认的时间格式
#重命名列名为子类目名
df.rename(columns={
df.columns[1]:colname},inplace=True)
#设置时间列作为索引
df = df.set_index('时间')
return df
dfs = [load_xlsx(i) for i in filenames]
df = pd.concat(dfs,axis=1).reset_index() # 拼接一下数据
df.head()
抽取月份方便建模索引:
month = df['时间'].dt.month
month
输出结果如下:
0 10
1 9
2 8
3 7
4 6
5 5
6 4
7 3
8 2
9 1
10 12
11 11
12 10
13 9
14 8
15 7
16 6
17 5
18 4
19 3
20 2
21 1
22 12
23 11
24 10
25 9
26 8
27 7
28 6
29 5
30 4
31 3
32 2
33 1
34 12
35 11
Name: 时间, dtype: int64
for i in [11,12]:
# 抽取对月份的数据
dm = df[month == i] #2015.11 2016.11 2017.11
# 训练x是年份
xtrain = np.array(dm['时间'].dt.year).reshape(-1,1)
# 测试y是新增的行,对应的日期
ytest = [pd.datetime(2018,i,1)]
for j in range(1,len(dm.columns)):
# 训练y是指定的列
ytrain = np.array(dm.iloc[:,j]).reshape(-1,1)
# 回归建模
lm = LinearRegression().fit(xtrain,ytrain)
# 预测当测试x为2018时销售额 yhat
yhat = lm.predict(np.array([2018]).reshape(-1,1))
ytest.append(round(yhat[0][0],2))
#给预测结果赋值对应的列名
newrow = pd.DataFrame([dict(zip(df.columns,ytest))])
#预测结果行加在数据前,所以说用newrow来append,不是df来append
df = newrow.append(df)
df.head()
df.reset_index(drop=True,inplace=True)
# 上图中的索引是0 0 1 ,用drop=True去掉,而inplace=True的作用是不创建新的对象,直接对原始对象进行修改;
df = df[df['时间'].dt.year != 2015]
df.tail()
接下来我们可以进行以下操作:
df['colsums'] = df.sum(1) #交易金额总和列
df.head()
df.insert(1,'year',df['时间'].dt.year) #年份列
df.head()
byyear = df.groupby('year').sum().reset_index()
byyear
sns.relplot('year','colsums',kind='line',marker='o',data=byyear,height=4)
plt.title('近三年的市场趋势')
plt.xticks(byyear.year,rotation=45) # rotation是旋转角度
plt.xlabel('年份')
plt.ylabel('总交易额')
plt.show()
可以看出:近三年呈增长趋势,整个市场倾向于成长期和成熟期。
查看各类目市场三年内销售额总和的变化趋势:
# 图形大小
f,ax = plt.subplots(figsize=(10,6)) # f代表整个图像,ax代表坐标轴和画的图,保存图像时需要用到fig
#dashes=False 不区分线型
sns.lineplot(data=byyear.set_index('year').iloc[:,:-1],dashes=False,marker='^')
plt.title('近三年各类市场销售趋势')
plt.xticks(byyear.year,rotation=45)
#在指定位置加文本
for a,b in zip(byyear.year,byyear['灭鼠杀虫剂']):
plt.text(a,b,'%.3e'% b, ha='center',va='bottom',size=12)
plt.xlabel('年份')
plt.ylabel('总交易额')
plt.show()
直观的看灭鼠杀虫剂和蚊香液都有较大的机会。
g = sns.FacetGrid(byyear,height=5)
g.map(sns.barplot,'year','灭鼠杀虫剂',color='wheat')
g.map(sns.pointplot,'year','灭鼠杀虫剂')
for a,b in zip(range(len(byyear)),byyear['灭鼠杀虫剂']):
plt.text(a,b,'%.3e'% b, ha='center',va='bottom',size=12)
plt.xlabel('年份')
plt.ylabel('灭鼠杀虫剂近三年的增长趋势')
plt.xticks(rotation=45)
plt.show()
查看各类目市场三年内销售额总和的占比:
#计算每年每个子市场的比例
byyear_per = byyear.iloc[:,1:-1].div(byyear.colsums,axis=0)
byyear_per.index = byyear.year
byyear_per
#stacked=True
byyear_per.plot(kind='bar',stacked=True,figsize=(10,8),colormap='tab10')
for a,b in zip(range(len(byyear_per)),byyear_per['灭鼠杀虫剂']):
plt.text(a,b/2,f'{
b*100:.2f}%', ha='center',va='bottom',size=12,color='white')
plt.xlabel('年份')
plt.ylabel('总交易额占比')
plt.title('近三年各子类市场销量占比')
plt.show()
可见灭鼠杀虫剂和蚊香液可进一步扩展,就需要与甲方业务人员进一步沟通。
这里我们假设沟通后我们重点关注的是灭鼠杀虫剂。
byyear
#拿到中间7列
byyear0 = byyear.iloc[:,1:-1]
byyear0.diff()#一阶差分 17-16 18-17
#计算年增幅
byyear0 = byyear.iloc[:,1:-1]
byyear_diff = byyear0.diff().iloc[1:,:].reset_index(drop=True)/byyear0.iloc[:2,:]
byyear_diff.index = ['16-17','17-18']
byyear_diff
#作图查看
f,ax = plt.subplots(figsize=(10,8))
sns.lineplot(data=byyear_diff,dashes=False)
plt.title('近三年各子类市场销量年增幅')
plt.xlabel('年份')
plt.ylabel('总交易额年增幅')
plt.show()
可见除了灭鼠杀虫剂和蚊香液增幅比较稳定,其它都有下降甚至变负。
这里我们先介绍一下什么是垄断,以及常见的评估指标有哪些:
那接下来我们就来实现一下。
df1 = pd.read_excel('top100品牌数据.xlsx')
df1.isna().mean()
输出结果如下:
品牌 0.0
行业排名 0.0
交易指数 0.0
交易增长幅度 0.0
支付转化指数 0.0
操作 0.0
dtype: float64
df1.head()
df1.describe(include='all')
df1['交易指数占比'] = df1['交易指数']/df1['交易指数'].sum()
df1['交易指数占比']
输出结果如下:
0 0.035998
1 0.032237
2 0.027311
3 0.024488
4 0.023530
...
95 0.004603
96 0.004492
97 0.004465
98 0.004447
99 0.004425
Name: 交易指数占比, Length: 100, dtype: float64
df1.plot(x='品牌',y='交易指数占比',kind='bar',figsize=(15,5))
plt.show()
## HHI
HHI = sum(df1['交易指数占比']**2)
HHI
0.013546334007208914
计算得到:驱虫市场HHI指数:0.013546(或135.46),等效公司数:73.82。
os.chdir('..')#返回到上一级目录
os.chdir('./灭鼠杀虫剂细分市场')#进入灭鼠杀虫剂细分市场文件夹
filename1 = glob.glob('*.xlsx')
dfs1 = [pd.read_excel(i) for i in filename1]
df2 = pd.concat(dfs1,sort=False)
df2.info()
输出结果如下:
Int64Index: 6556 entries, 0 to 1742
Columns: 229 entries, 类别 to 产品名
dtypes: float64(129), int64(5), object(95)
memory usage: 11.7+ MB
#查看缺失值
df2.isna().mean()
输出结果如下:
类别 0.0
时间 0.0
页码 0.0
排名 0.0
链接 0.0
...
宝贝成份 1.0
规格: 1.0
樟脑 1.0
包装 1.0
产品名 1.0
Length: 229, dtype: float64
ind1 = df2.isna().mean()> 0.98
sum(ind1)
191
df20 = df2.loc[:,~ind1] #删除缺失值> 0.98的
df20.isna().mean()
输出结果如下:
类别 0.000000
时间 0.000000
页码 0.000000
排名 0.000000
链接 0.000000
主图链接 0.000000
主图视频链接 0.746797
宝贝标题 0.000000
宝贝ID 0.000000
销量(人数) 0.000000
售价 0.000000
预估销售额 0.005491
运费 0.000000
评价人数 0.022880
收藏人数 0.000000
下架时间 0.000000
类目 0.000000
地域 0.406955
旺旺 0.000000
店铺类型 0.000000
品牌 0.095333
型号 0.423276
净含量 0.421599
适用对象 0.279896
物理形态 0.286303
药品登记号 0.927090
产品名称 0.796980
农药登记证号 0.873093
生产企业 0.888957
农药生产许可证/批准文号 0.889262
农药产品标准证号 0.889262
农药名称 0.889262
剂型 0.882093
农药成分 0.885754
有效成分总含量 0.889262
毒性 0.873093
防治对象 0.889262
农药类型 0.973612
dtype: float64
ind2 = np.array([len(df20[i].unique()) == 1 for i in df20.columns])
df21 = df20.loc[:,~ind2]
df21.isna().mean()
输出结果如下:
类别 0.000000
时间 0.000000
页码 0.000000
排名 0.000000
链接 0.000000
主图链接 0.000000
主图视频链接 0.746797
宝贝标题 0.000000
宝贝ID 0.000000
销量(人数) 0.000000
售价 0.000000
预估销售额 0.005491
运费 0.000000
评价人数 0.022880
收藏人数 0.000000
下架时间 0.000000
地域 0.406955
旺旺 0.000000
店铺类型 0.000000
品牌 0.095333
型号 0.423276
净含量 0.421599
适用对象 0.279896
物理形态 0.286303
药品登记号 0.927090
产品名称 0.796980
农药登记证号 0.873093
生产企业 0.888957
农药生产许可证/批准文号 0.889262
农药产品标准证号 0.889262
农药名称 0.889262
剂型 0.882093
农药成分 0.885754
有效成分总含量 0.889262
毒性 0.873093
防治对象 0.889262
农药类型 0.973612
dtype: float64
#删除药品登记号 之后的属性
ind3 = df21.columns.get_loc('药品登记号')
df22 = df21.iloc[:,:ind3]
df22.isna().mean()
输出结果如下:
类别 0.000000
时间 0.000000
页码 0.000000
排名 0.000000
链接 0.000000
主图链接 0.000000
主图视频链接 0.746797
宝贝标题 0.000000
宝贝ID 0.000000
销量(人数) 0.000000
售价 0.000000
预估销售额 0.005491
运费 0.000000
评价人数 0.022880
收藏人数 0.000000
下架时间 0.000000
地域 0.406955
旺旺 0.000000
店铺类型 0.000000
品牌 0.095333
型号 0.423276
净含量 0.421599
适用对象 0.279896
物理形态 0.286303
dtype: float64
unless = ["时间","链接","主图链接","主图视频链接","宝贝标题","运费" ,"下架时间","旺旺" ,"页码","排名"]
unless
[‘时间’, ‘链接’, ‘主图链接’, ‘主图视频链接’, ‘宝贝标题’, ‘运费’, ‘下架时间’, ‘旺旺’, ‘页码’, ‘排名’]
df23 = df22.drop(columns=unless)
df23.isna().mean()
输出结果如下:
类别 0.000000
宝贝ID 0.000000
销量(人数) 0.000000
售价 0.000000
预估销售额 0.005491
评价人数 0.022880
收藏人数 0.000000
地域 0.406955
店铺类型 0.000000
品牌 0.095333
型号 0.423276
净含量 0.421599
适用对象 0.279896
物理形态 0.286303
dtype: float64
df23.dtypes
输出结果如下:
类别 object
宝贝ID int64
销量(人数) int64
售价 float64
预估销售额 float64
评价人数 float64
收藏人数 int64
地域 object
店铺类型 object
品牌 object
型号 object
净含量 object
适用对象 object
物理形态 object
dtype: object
df23 = df23.astype({
'宝贝ID':'object'}) #将宝贝ID转成object
df23.reset_index(drop=True,inplace=True)
df23.describe()
df23.head()
通过上述内容,我们可以得到以下结论:
byclass = df23['预估销售额'].groupby(df23['类别']).sum()
byclass
类别
杀虫 8207628.10
灭鼠 25686011.99
虱 4512886.01
螨 10886752.88
蟑螂 18037223.68
Name: 预估销售额, dtype: float64
byclass.plot.barh()
byclass.plot.pie(autopct='%.2f')
import plotly.graph_objects as go #交互图形 类似于PowerBI
fig = go.Figure(data=[go.Pie(labels=byclass.index,values=byclass.values)])
fig.show()
df24 = df23[df23['类别']== '灭鼠']
df24
df24['售价'].describe()
输出结果如下:
count 1523.000000
mean 49.018910
std 69.762057
min 0.010000
25% 15.800000
50% 27.700000
75% 52.600000
max 498.000000
Name: 售价, dtype: float64
df24['售价'].plot.hist()
#自定义分箱 销售额 将连续型变量转成分类型变量
bins = [0,50,100,150,200,250,300,500] #分界线
labels = ['0_50','50_100','100_150','150_200','200_250','250_300','300_500']#箱子的标题
#pd.cut (0,50] ---> [0,50]
df24['价格区间'] = pd.cut(df24['售价'],bins,labels=labels,include_lowest=True)
df24['价格区间'].value_counts()
输出结果如下:
0_50 1138
50_100 242
100_150 62
150_200 35
300_500 28
250_300 9
200_250 9
Name: 价格区间, dtype: int64
df24
#分类的依据----价格区间
by = '价格区间'
df = df24
#根据价格区间求和
df.groupby(by).sum()
#把预估销售额列抽出来
byc = pd.DataFrame(df.groupby(by).sum().loc[:,['预估销售额']])
byc
#销售额占比、宝贝数、宝贝数的占比、单个宝贝的平均销售额
byc['销售额占比'] = byc['预估销售额'] / byc['预估销售额'].sum()
byc['宝贝数'] = df.groupby(by).nunique()['宝贝ID']
byc['宝贝数占比'] = byc['宝贝数'] / byc['宝贝数'].sum()
byc['单宝贝平均销售额'] = byc['预估销售额']/byc['宝贝数']
byc
byc['相对竞争度'] = 1- (byc['单宝贝平均销售额']-byc['单宝贝平均销售额'].min())/(
byc['单宝贝平均销售额'].max()-byc['单宝贝平均销售额'].min())
byc
# 自定义函数
def byfun(df,by,sort='单宝贝平均销售额'):
byc = pd.DataFrame(df.groupby(by).sum().loc[:,['预估销售额']])
#销售额占比、宝贝数、宝贝数的占比、单个宝贝的平均销售额
byc['销售额占比'] = byc['预估销售额'] / byc['预估销售额'].sum()
byc['宝贝数'] = df.groupby(by).nunique()['宝贝ID']
byc['宝贝数占比'] = byc['宝贝数'] / byc['宝贝数'].sum()
byc['单宝贝平均销售额'] = byc['预估销售额']/byc['宝贝数']
byc['相对竞争度'] = 1- (byc['单宝贝平均销售额']-byc['单宝贝平均销售额'].min())/(
byc['单宝贝平均销售额'].max()-byc['单宝贝平均销售额'].min())
if sort:
byc.sort_values(sort,ascending=False,inplace=True)
return byc
byprices = byfun(df24,'价格区间')
byprices
def mcplot(bydf,figsize=(10,4)):
ax = bydf.plot(y='相对竞争度',linestyle='-',marker='o',figsize=figsize)
bydf.plot(y='销售额占比',kind='bar',alpha=0.8,color='wheat',ax=ax)
plt.show()
mcplot(byprices)
结果依单宝贝销售额降序,即依竞争度升序,这里销售额占比可以理解为市场份额。
可见0-50容量大,竞争大,大容量市场(对比的是50-100,容量小,竞争稍小)
200-250,竞争小,做高价市场的优先选择,属于机会点。
可见我们喜欢的类目是:市场份额高(表示更适合大众),相对竞争度低(没人抢)。也就是找到闷声发大财的那些个分类去分蛋糕。
df25 = df24[df24['价格区间']=='0_50']
df25['售价'].plot.hist()
#自定义分箱 销售额 将连续型变量转成分类型变量
bins_01 = [0,10,20,30,40,50] #分界线
labels_01 = ['0_10','10_20','20_30','30_40','40_25']#箱子的标题
#pd.cut (0,50] ---> [0,50]
df25['价格子区间'] = pd.cut(df25['售价'],bins_01,labels=labels_01,include_lowest=True)
byprices_01 = byfun(df25,'价格子区间')
byprices_01
mcplot(byprices_01)
200-250细分市场也是同样的分析思路。
df25.head()
bystore = byfun(df25,'店铺类型')
bystore
mcplot(bystore)
bytype = byfun(df25,'型号')
#预估销售额 前5%的型号
bytype1 = bytype[bytype['预估销售额']>=bytype['预估销售额'].quantile(0.95)]
bytype1
mcplot(bytype1)
可见虽然粘鼠板市场份额普遍较高,但是0005、MT007在竞争度上有明显的优势。
byshape = byfun(df25,'物理形态')
byshape
mcplot(byshape)
可见市场份额最高的是固体,竞争度也偏高,而胶水虽然竞争度低,但是市场份额较低,基本可以认为常见的物理形态就是固体。
通过上述分析我们可以得出以下结论:
依据之前的top100品牌数据,分析市场份额前三的商家:拜耳,科凌虫控,安速。
使用商品销售数据分析各家的产品类别的分布:
os.chdir('./商品销售数据/')
filename2 = glob.glob('*.xlsx')
filename2
[‘安速家居近30天销售数据.xlsx’, ‘拜耳近30天销售数据.xlsx’, ‘科凌虫控旗舰店近30天销售数据.xlsx’]
df3 = pd.read_excel(filename2[2])
df3.head(1)
# 删除无用特征
def load_xlsx_title(filename):
df = pd.read_excel(filename)
unless = ['序号','店铺名称','商品名称','主图链接','商品链接']
df.drop(columns=unless,inplace=True)
return df
df3bai = load_xlsx_title(filename2[1])
df3bai.head()
df3an = load_xlsx_title(filename2[0])
df3an.head()
df3kl = load_xlsx_title(filename2[2])
df3kl.head()
bai31 = df3bai.groupby('类目').sum()
bai31
an31 = df3an.groupby('类目').sum()
an31
kl31 = df3kl.groupby('类目').sum()
kl31
#饼图 [0,1,2]
fig,axes = plt.subplots(1,3,figsize=(10,6))
ax = axes[0] #第一个拜耳
bai31['销售额'].plot.pie(autopct='%.f',title='拜耳',startangle=30,ax=ax)
ax.set_ylabel('')
ax = axes[1] #第二个安速
an31['30天销售额'].plot.pie(autopct='%.f',title='安速',startangle=60,ax=ax)
ax.set_ylabel('')
ax = axes[2] #第三个科凌虫控
kl31['30天销售额'].plot.pie(autopct='%.f',title='科凌虫控',startangle=90,ax=ax)
ax.set_ylabel('')
plt.show()
可见拜耳只有一个市场,其他的有不同市场,但主要市场都是灭鼠杀虫剂。
分析各家的适用对象的分布:
bai32 = df3bai.groupby('使用对象').sum()
bai32
an32 = df3an.groupby('适用对象').sum()
an32
kl32 = df3kl.groupby('适用对象').sum()
kl32
#饼图 [0,1,2]
fig,axes = plt.subplots(1,3,figsize=(10,6))
ax = axes[0] #第一个拜耳
bai32['销售额'].plot.pie(autopct='%.f',title='拜耳',startangle=30,ax=ax)
ax.set_ylabel('')
ax = axes[1] #第二个安速
an32['30天销售额'].plot.pie(autopct='%.f',title='安速',startangle=60,ax=ax)
ax.set_ylabel('')
ax = axes[2] #第三个科凌虫控
kl32['30天销售额'].plot.pie(autopct='%.f',title='科凌虫控',startangle=90,ax=ax)
ax.set_ylabel('')
plt.show()
拜耳的主要对象是蟑螂,而另外两家除此之外还有螨,鼠;
而从之前的分析看灭鼠和蟑螂的整体市场份额都大;应该开拓新市场,尤其是灭鼠,也考察其他两家都开拓的螨市场。
os.chdir('..')
os.chdir('./商品交易数据')
filename3 = glob.glob('*.xlsx')
filename3
[‘安速全店商品交易数据.xlsx’, ‘拜耳全店商品交易数据.xlsx’, ‘科凌虫控全店商品交易数据.xlsx’]
使用商品交易数据,每个竞争者分开分析,先分析拜耳的数据。
df4bai = pd.read_excel(filename3[1])
df4bai.head()
df4bai.info()
输出结果如下:
RangeIndex: 142 entries, 0 to 141
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 品牌 142 non-null object
1 时间 142 non-null datetime64[ns]
2 商品 142 non-null object
3 行业排名 142 non-null int64
4 交易指数 142 non-null int64
5 交易增长幅度 142 non-null float64
6 支付转化指数 142 non-null int64
7 操作 142 non-null object
8 交易金额 142 non-null float64
dtypes: datetime64[ns](1), float64(2), int64(3), object(3)
memory usage: 10.1+ KB
df4bai['商品'].value_counts().count()
44
#自定义分类汇总函数
def byproduct(df):
dfb = df.groupby('商品').mean().loc[:,['交易增长幅度']] #交易增长幅度做均值
dfb['交易金额'] = df.groupby('商品').sum()['交易金额']
dfb['交易金额占比'] = dfb['交易金额']/dfb['交易金额'].sum()
dfb['商品个数'] = df.groupby('商品').count()['交易金额']
dfb.reset_index(inplace= True)
return dfb
bai4 = byproduct(df4bai)
bai4.head()
其中交易增长幅度可表示市场发展率,交易金额占比可表示市场份额。
bai4.describe(percentiles=[0.1,0.9,0.99])
def block(x):
qu = x.quantile(.9)
out = x.mask(x>qu,qu) #当大于90%分位数的进行替换
return(out)
def block2(df):
df1 = df.copy()
df1['交易增长幅度'] = block(df1['交易增长幅度']) #使用盖帽法进行替换交易增长幅度
df1['交易金额占比'] = block(df1['交易金额占比']) #使用盖帽法进行替换交易增长幅度
return df1
bai41 = block2(bai4)
bai41.describe(percentiles=[0.1,0.9,0.99])
交易增长幅度和交易金额占比这两个指标的最大值都远大于3/4分位数,认为是异常值,考虑引入盖帽法,方便作图。
定义波士顿矩阵绘图函数 可以使用均值、中位数来分割(0.33 0.33) 作为波士顿矩阵的切割线。
# mean True 均值
# mean False 中位数来分割(0.33 0.33)
def plotBOG(df,mean = False,q1=0.5,q2=0.5):
f,ax = plt.subplots(figsize=(10,8))
ax = sns.scatterplot('交易金额占比','交易增长幅度',hue='商品个数',size='商品个数',
sizes=(20,200),palette='cool',legend='full',data=df)
#给所有的点加行索引,点对应的是行数据(对应商品),方便探索
for i in range(0,len(df)):
ax.text(df['交易金额占比'][i]+0.001,df['交易增长幅度'][i],i) #索引标注相对于x轴右移
if mean:
plt.axvline(df['交易金额占比'].mean())#垂线
plt.axhline(df['交易增长幅度'].mean())#水平线
else:
plt.axvline(df['交易金额占比'].quantile(q1))#垂线
plt.axhline(df['交易增长幅度'].quantile(q2))#水平线
plt.show()
plotBOG(bai41,mean=True)
点的大小为商品个数,以中位数作为波士顿矩阵的分隔线,拜耳的BOG图如下:
plotBOG(bai41,mean=False)
我们可以根据实际的业务选择区间的分隔线,由行业经验确定(例如认为增幅0.1在行业里算高,就可以作为分隔线)
从图可以看出:明星产品和奶牛产品的商品个数普遍比较多。
没有突出的明星产品,但是有快进入明星产品的问题产品。
查看各个产品结构的产品(除了瘦狗)
各种产品排序,关心点不同,排序依据不同
问题产品,潜力款,关心市场增长率,依交易增长幅度排序。
这里要查看实际数据,故使用盖帽前数据,拜耳明星产品如下:
def extractBOG(df,q1=0.5,q2=0.5,by='交易金额占比'):
# 明星产品
star = df.loc[(df['交易金额占比'] >= df['交易金额占比'].quantile(q1))#交易金额大于0.5
& (df['交易增长幅度'] >= df['交易增长幅度'].quantile(q2)),:] #交易增长幅度大于0.5
star = star.sort_values(by,ascending=False)
# 爆款产品
cow = df.loc[(df['交易金额占比'] >= df['交易金额占比'].quantile(q1))#交易金额大于0.5
& (df['交易增长幅度'] < df['交易增长幅度'].quantile(q2)),:] #交易增长幅度小于0.5
cow = cow.sort_values(by,ascending=False)
# 问题产品
que = df.loc[(df['交易金额占比'] < df['交易金额占比'].quantile(q1))#交易金额小于0.5
& (df['交易增长幅度'] >= df['交易增长幅度'].quantile(q2)),:] #交易增长幅度大于0.5
que = que.sort_values(by,ascending=False)
return star,cow,que
bai4star,bai4cow,bai4que = extractBOG(bai4)
bai4star
主要是除蟑和杀虫,但是占比不大,增幅一般。
bai4cow
可见占比最高的是除蟑,灭虫也占一部分,占比一般。
交易增长幅度最大的是灭鼠,而之前描述过灭鼠有最高的市场份额,可以作为下一步着力点。
总结:拜耳大部分产品集中在除蟑上,杀虫也有一定的规模,但是明星产品略乏力,可以进一步发展问题产品灭鼠为明星产品。
df4an = pd.read_excel(filename3[0])
df4an.head()
df4an['商品'].value_counts().count()
49
an4 = byproduct(df4an)
an4.head()
an4.describe()
an41 = block2(an4)
an41.describe(percentiles=[0.1,0.9,0.99])
分析方法和之前一致,故直接看图和产品:
plotBOG(an41)
可见奶牛产品足,明星产品部分有前途,问题产品部分有潜力,瘦狗产品不多。
anstar,ancow,anque = extractBOG(an4)
anstar
杀虫和除蟑表现都不错。
ancow.head()
主要是除蟑,和拜耳产生竞争。
anque.head()
前几款是灭蟑,除螨,杀虫,都有发展空间。
安速没有明显的灭鼠市场;拜耳和安速比较:拜耳杀虫是老爆款,灭蟑存在一定竞争。
df4ke = pd.read_excel(filename3[2])
df4ke.head()
df4ke['商品'].value_counts().count()
31
ke4 = byproduct(df4ke)
ke4.head()
ke4.describe()
ke41 = block2(ke4)
ke41.describe(percentiles=[0.1,0.9,0.99])
plotBOG(ke41)
可见奶牛产品足,明星产品少,大部分竞争力强,问题产品部分有潜力,瘦狗产品少。
kestar,kecow,keque = extractBOG(ke4)
kestar
kecow.head()
主要是除蟑,有很小部分灭虫和灭鼠。
keque.head()
有较大潜力的是除螨。
科凌虫控积极发展多个产品,然而每个产品结构相对独立(奶牛除蟑,明星灭鼠,潜力除螨),没有后续的支持,竞争力不是那么强。
流量急剧下降了,怎么分析:
聊完分析方法后,下面我们正式用数据来分析一下。
os.chdir('..')
os.chdir('./流量渠道数据')
filename4 = glob.glob('*.xlsx')
filename4
[‘安速家居旗舰店流量渠道.xlsx’, ‘拜耳官方旗舰店流量渠道.xlsx’, ‘科凌虫控旗舰店流量渠道.xlsx’]
df5bai = pd.read_excel(filename4[1])
df5bai.head(10)
# 只取交易指数排名前十的流量渠道
df0 = df5bai
top10 = df0.sort_values('交易指数',ascending=False).reset_index(drop=True).iloc[:10,:]
#计算交易指数占比,交易指数是销售额的反映
top10['交易指数占比'] = top10['交易指数']/top10['交易指数'].sum()
top10.set_index('流量来源',inplace=True)
top10
#把付费的渠道 进行标记
paid = ['付费流量','直通车','淘宝客']
ind = np.any([top10.index == i for i in paid],axis=0) #true 为付费的
ind
array([False, False, False, False, True, False, False, True, False, True])
自定义函数-流量结构说明:
def flow(df):
# 只取交易指数排名前十的流量渠道
df0 = df.copy()
top10 = df0.sort_values('交易指数',ascending=False).reset_index(drop=True).iloc[:10,:]
#计算交易指数占比
top10['交易指数占比'] = top10['交易指数']/top10['交易指数'].sum()
top10.set_index('流量来源',inplace=True)
#把付费的渠道 进行标记
paid = ['付费流量','直通车','淘宝客']
ind = np.any([top10.index == i for i in paid],axis=0) #true 为付费的
explode = ind * 0.1 #相当于往外爆0.1的距离
ax = top10['交易指数占比'].plot.pie(autopct='%.1f%%',
figsize=(8,8),colormap='cool',explode = explode)
ax.set_ylabel('')
plt.show()
#输出占比:总交易指数、付费流量占比、付费流量带来的交易指数
salesum = top10['交易指数'].sum() #总交易指数
paidsum = top10['交易指数占比'][ind].sum() #付费流量占比
paidsale = salesum * paidsum #付费流量带来的交易指数
print(f'前十流量中:总交易指数:{
salesum:.0f};付费流量占比:{
paidsum*100:.2f}%;付费流量带来的交易指数:{
paidsale:.0f}')
return top10
bai5 = flow(df5bai)
前10流量中:总交易指数:2334051;付费流量占比:21.85%;付费流量带来交易指数:509959。
df5an = pd.read_excel(filename4[0])
df5an.head(10)
# 只取交易指数排名前十的流量渠道
df0 = df5an
top10 = df0.sort_values('交易指数',ascending=False).reset_index(drop=True).iloc[:10,:]
#计算交易指数占比
top10['交易指数占比'] = top10['交易指数']/top10['交易指数'].sum()
top10.set_index('流量来源',inplace=True)
top10
#把付费的渠道 进行标记
paid = ['付费流量','直通车','淘宝客']
ind = np.any([top10.index == i for i in paid],axis=0) #true 为付费的
ind
array([False, False, False, True, False, False, False, True, False, False])
an5 = flow(df5an)
前10流量中:总交易指数:748539;付费流量占比:18.58%;付费流量带来交易指数:139048。
可见拜耳和安速的流量配比是差不多的,安速的整体流量小很多,即流量效果拜耳明显优于安速。
df5ke = pd.read_excel(filename4[2])
df5ke.head(10)
# 只取交易指数排名前十的流量渠道
df0 = df5ke
top10 = df0.sort_values('交易指数',ascending=False).reset_index(drop=True).iloc[:10,:]
#计算交易指数占比
top10['交易指数占比'] = top10['交易指数']/top10['交易指数'].sum()
top10.set_index('流量来源',inplace=True)
top10
#把付费的渠道 进行标记
paid = ['付费流量','直通车','淘宝客']
ind = np.any([top10.index == i for i in paid],axis=0) #true 为付费的
ind
array([False, False, False, True, False, False, False, True, True, False])
ke5 = flow(df5ke)
前10流量中:总交易指数:1918111;付费流量占比:25.51%;付费流量带来交易指数:489263。
下面开始正式复现上述流程。
os.chdir('..')
os.chdir('./评论舆情数据')
filename = glob.glob('*.xlsx')
filename
[‘安速.xlsx’, ‘德国拜耳.xlsx’, ‘科林虫控.xlsx’]
df6bai = pd.read_excel(filename[1])
df6bai
bai6 = list(df6bai['评论'])
bai6[:5] # 提取5条看一看
可见,我们需要一定的数据清洗:非中英文字符的不要、在分词前逗号、句号不要。
bai61 = [re.sub(r'[^a-z\u4E00-\u9Fa5]+',' ',i,
flags=re.I) for i in bai6]#中文字符 \u4E00-\u9Fa5 flags=re.I 不区分大小写
清洗完再来看一下:
bai61[:5]
接着我们来去掉停用词(百度的停用词库)。不过在此之前,我们得先分一下词,这里我们用的分词工具是jieba分词。先来看一下jieba的使用:
jieba.lcut('真心坑人啊 还没到 小时就凝固了 小强依然活跃')
输出结果如下:
['真心',
'坑人',
'啊',
' ',
'还',
'没到',
' ',
'小时',
'就',
'凝固',
'了',
' ',
'小强',
'依然',
'活跃']
接下来正式进行分词:
# 先读取停用词
stopwords = list(pd.read_csv('E:\Data-analysis-project\电商文本挖掘\data/百度停用词表.txt',
names=['stopwords'])['stopwords']) #指定列名转化为列表
stopwords.extend([' ', '蟑螂']) #把空格也去掉 蟑螂
bai62 = []
for i in bai61:
#对每条评论分析
seg1 = pd.Series(jieba.lcut(i))
ind1 = pd.Series([len(j) for j in seg1])>1 #长度大于1的保留
seg2 = seg1[ind1]
#去掉停用词 isin
ind2 = ~seg2.isin(pd.Series(stopwords))
seg3 = list(seg2[ind2].unique())#去重一下
if len(seg3)>0:
bai62.append(seg3)
bai62[0] #得到的是大列表套小列表
输出结果如下:
['收到',
'家里',
'厨房',
'小强',
'评价',
'销量',
'赶紧',
'三盒',
'管用',
'后续',
'效果',
'追加',
'多久',
'才能',
'消灭',
'干净',
'没法',
'做饭',
'进去',
'担心',
'挥发',
'很多',
'试试']
组合多个列表到一个列表:
bai63 = [y for x in bai62 for y in x]
bai63[:5]
[‘收到’, ‘家里’, ‘厨房’, ‘小强’, ‘评价’]
#词频统计
baifreq = pd.Series(bai63).value_counts()
baifreq[:10] # 看下前10个词
输出结果如下:
效果 541
蟑螂 409
双十 145
不错 144
评论 138
小强 114
收到 106
用户 100
填写 100
东西 95
dtype: int64
而构建一个词云所需要的数据 一个巨大字符串 (用空格分隔的词):
bai64 = ' '.join(bai63)
最后一个步骤,调用WordCloud模块生成词云:
#读取照片
mask = imageio.imread(r'E:\Data-analysis-project\电商文本挖掘\data/leaf.jpg')
#如果是中文的词云---字体
font = r'E:\Data-analysis-project\电商文本挖掘\data/SimHei.ttf'
wc = WordCloud(background_color='white',mask=mask,
font_path=font).generate(bai64)
plt.figure(figsize=(8,8))
plt.imshow(wc)
plt.axis('off')#不要坐标轴
plt.show()
基于 TF-IDF 算法的关键词抽取:
jieba.analyse.extract_tags(bai64,20,True)
输出结果如下:
[('效果', 0.29875695025833393),
('双十', 0.13410500058357974),
('评论', 0.08641902343506376),
('湿巾', 0.08395512199412308),
('填写', 0.08239762548761781),
('不错', 0.0823420504295694),
('好评', 0.07553937079103677),
('追评', 0.07069905010031417),
('没用', 0.06662667991833673),
('收到', 0.06542549350413418),
('用户', 0.06304136086139346),
('好用', 0.06195551748124191),
('尸体', 0.05744312738244686),
('划算', 0.057198916923431896),
('湿纸巾', 0.05523277943411569),
('家里', 0.04893045405589909),
('发货', 0.04800798233693402),
('期待', 0.0452573579284439),
('希望', 0.04377063232686934),
('hellip', 0.04308223365487895)]
最终我们可以把以上总结汇总一下:
分析角度 | 结论 |
---|---|
潜力分析 | 1.整体驱虫市场处于快速增长阶段,趋向于成长期到成熟期; 2.灭鼠杀虫剂市场份额较大(大于60%),约是第二名蚊香液的二倍,市场增长率接近40%,可以认为是明星产品类目,需要持续投资和重点关注; 3.驱虫市场不存在垄断,结构不集中,竞争相对激烈,即没有明显的来自大公司的压力。 |
市场机会点 | 1.灭鼠杀虫剂市场中,需要重点关注的产品类别是:灭鼠和蟑螂; 2.灭鼠产品: ○ 最大的市场集中在0-50的价格段,这个价格段竞争也很激烈; ○ 200-250这个价格段市场份额占10%左右,竞争度很低,是值得挖掘的高价市场; 3.灭鼠0-50价格段的产品市场中: ○ 10-20价格段市场容量大,竞争度低,值得进一步开发,20-30也不错; ○ 店铺类型方面天猫明显优于淘宝; ○ 市场份额高的型号是粘鼠板,然而型号0005市场份额还行,竞争度较低,值得开发; ○ 产品的物理形态基本都是固体,也是被大众认可的形态; ○ 当物理形态为固体,净含量为1时,市场份额高竞争度低,值得开发。 |
品类分布-产品类别 | 拜耳只有一个市场,其他的有不同市场,但主要市场都是灭鼠杀虫剂。 |
品类分布-适用对象 | 拜耳的主要对象是蟑螂,而另外两家除此之外还有螨,鼠; 而从之前的分析看灭鼠和蟑螂的整体市场份额都大;应该开拓新市场,尤其是灭鼠,也考察其他两家都开拓的螨市场。 |
产品结构 | 拜耳大部分产品集中在除蟑上,杀虫也有一定的规模,但是明星产品略乏力,可以进一步发展问题产品灭鼠为明星产品。 安速没有明显的灭鼠市场;拜耳和安速比较:拜耳杀虫是老爆款,灭蟑存在一定竞争。 科凌虫控积极发展多个产品,然而每个产品结构相对独立(奶牛除蟑,明星灭鼠,潜力除螨),没有后续的支持,竞争力不是那么强。 |
流量结构 | 拜耳和安速的流量配比是差不多的,不过安速的整体流量小很多; 科凌虫控和拜耳在流量上差不多,科凌虫控付费占比较高,可见拜耳在流量结构上是有优势的,要保持这个优势。 |
舆情分析 | 不管从词云还是关键词来看,评价偏好评,没有明显问题。 |
到这里,我们这一个项目也差不多结束啦,希望这篇文章对你能有所帮助!
CSDN@报告,今天也有好好学习