spark之淘宝app一个月数据流量运营分析
一.统计指标
针对淘宝app一个月的数据进行流量运营分析,主要包括:
1.app流量分析
(1).pv页面浏览量
(2).uv独立访客
(3).访问深度
(4).每天访客数和成交量
(5).不同时段的访客数及成交量
(6).流失率
2.用户行为分析
(1).用户浏览活跃时段
(2).用户购买活跃时段
(3).用户浏览最多的类目
(4).用户收藏最多的类目
(5).用户加购最多的类目
(6).用户购买最多的类目
(7).最近 30 天购买次数
(8).最近 7 天的活跃天数
(9).复购率
3.商品分析
(1).浏览量最多和最少的 TOP5 类目
(2).收藏量最多和最少的 TOP5 类目
(3).加购量最多和最少的 TOP5 类目
(4).购买量最多和最少的 TOP5 类目
二.数据
数据集【taobao_persona.csv】来自和鲸社区 https://www.kesci.com/home/dataset/5ef7024363975d002c9235d3,
记录了 2014 年 11 月 18 日至 2014 年 12 月 18 日的电商 APP 部分用户行为记录,原始数据共 23291027 条,共有 6 个属性。
属性名 属性值
user_id 用户 ID,一个 ID 允许触发多个行为
item_id 商品 ID
behavior_type 用户行为类型,包括浏览=1,收藏=2,加入购物车=3,购买=4
user_geohash 用户地理位置
item_category 商品所属类目的 ID
time 用户行为发生的日期和时刻,值域为 2014/11/18-2014/12/18
三.代码(spark3.0,java1.8)
详细代码见:TrafficOperationAnalysis淘宝APP一个月数据的流量运营分析(https://github.com/jiangnanboy/spark_tutorial)
/** * 1.app流量分析 * 2.用户行为分析 * 3.商品分析 * * 从 30 天里 APP 的总浏览量、总独立访客量、访问深度、每天访客量及成交量、每个时段访客数及成交量、各环节的流失率分析近 30 天的 APP 流量,及时发现流量运营异常。 * * 从用户浏览活跃时段、用户购买活跃时段、用户浏览或收藏或加购或购买最多的类目、最近 30 天购买频次、最近 7 天活跃天数、复购率分析用户行为,了解用户喜好,以便进行后续的用户分类和商品推荐。 * * 从商品类目的浏览量、收藏量、加购量、成交量分析不同商品类目的受欢迎程度,定位主要盈利和较为冷门的商品类目。 * * 利用传统的 RFM 模型分析用户价值,由于原始数据缺少用户的消费金额,因此本项目只从 RF 划分用户群体。 * * 利用 ARIMA 模型预测未来七天(2014/12/19-2014/12/25)的访客量,包括平稳性检验、差分法平稳序列、拟合预测。 * * @param session */ public static void analysis(SparkSession session) { String path = PropertiesReader.get("taobao_persona_csv"); /** * 加载数据查看schema,样本数量为:23291027 * +--------+---------+-------------+------------+-------------+-------------+ * | user_id| item_id|behavior_type|user_geohash|item_category| time| * +--------+---------+-------------+------------+-------------+-------------+ * |10001082|285259775| 1| 97lk14c| 4076|2014-12-08 18| * |10001082| 4368907| 1| null| 5503|2014-12-12 12| * |10001082| 4368907| 1| null| 5503|2014-12-12 12| * |10001082| 53616768| 1| null| 9762|2014-12-02 15| * |10001082|151466952| 1| null| 5232|2014-12-12 11| * +--------+---------+-------------+------------+-------------+-------------+ * * |-- user_id: integer (nullable = true) * |-- item_id: integer (nullable = true) * |-- behavior_type: integer (nullable = true) * |-- user_geohash: string (nullable = true) * |-- item_category: integer (nullable = true) * |-- time: string (nullable = true) * */ Dataset<Row> dataset = session.read() .option("sep", ",") .option("header", "true") .option("inferSchema", "true") .csv(path); /** * 将time拆为两列date和time * +--------+---------+-------------+------------+-------------+----+----------+ * | user_id| item_id|behavior_type|user_geohash|item_category|time| date| * +--------+---------+-------------+------------+-------------+----+----------+ * |10001082|285259775| 1| 97lk14c| 4076| 18|2014-12-08| * |10001082| 4368907| 1| null| 5503| 12|2014-12-12| * |10001082| 4368907| 1| null| 5503| 12|2014-12-12| * |10001082| 53616768| 1| null| 9762| 15|2014-12-02| * |10001082|151466952| 1| null| 5232| 11|2014-12-12| * +--------+---------+-------------+------------+-------------+----+----------+ */ dataset = dataset.withColumn("date", functions.substring(col("time"),0, 10)); dataset =dataset.withColumn("time", functions.regexp_replace(col("time"), col("time"), functions.substring(col("time"),12, 2))); /** * 查看每列缺失值,可以看出user_geohash缺失较多,该列数据暂时用不上,故可删除 * +-------+-------+-------------+------------+-------------+----+----+ * |user_id|item_id|behavior_type|user_geohash|item_category|time|date| * +-------+-------+-------------+------------+-------------+----+----+ * | 0| 0| 0| 15911010| 0| 0| 0| * +-------+-------+-------------+------------+-------------+----+----+ */ String[] columnsName = dataset.columns(); Column[] columns = new Column[columnsName.length]; for(int index = 0;index < columnsName.length; index++) { columns[index] = functions.count(functions.when(functions.isnull(col(columnsName[index])), columnsName[index])).as(columnsName[index]); } //dataset.select(columns).show(); /**删除列user_geohash * +--------+---------+-------------+-------------+----+----------+ * | user_id| item_id|behavior_type|item_category|time| date| * +--------+---------+-------------+-------------+----+----------+ * |10001082|285259775| 1| 4076| 18|2014-12-08| * |10001082| 4368907| 1| 5503| 12|2014-12-12| * |10001082| 4368907| 1| 5503| 12|2014-12-12| * |10001082| 53616768| 1| 9762| 15|2014-12-02| * |10001082|151466952| 1| 5232| 11|2014-12-12| * +--------+---------+-------------+-------------+----+----------+ * |-- user_id: integer (nullable = true) * |-- item_id: integer (nullable = true) * |-- behavior_type: integer (nullable = true) * |-- item_category: integer (nullable = true) * |-- time: string (nullable = true) * |-- date: string (nullable = true) * */ dataset = dataset.drop("user_geohash"); /** * 增加一列,将一天24小时划分为:'凌晨','上午','中午','下午','晚上' * '凌晨':0-5 * '上午':5-10 * '中午':10-13 * '下午':13-18 * '晚上':18-24 * * +--------+---------+-------------+-------------+----+----------+----------+ * | user_id| item_id|behavior_type|item_category|time| date|time_slice| * +--------+---------+-------------+-------------+----+----------+----------+ * |10001082|285259775| 1| 4076| 18|2014-12-08| 晚上| * |10001082| 4368907| 1| 5503| 12|2014-12-12| 中午| * |10001082| 4368907| 1| 5503| 12|2014-12-12| 中午| * |10001082| 53616768| 1| 9762| 15|2014-12-02| 下午| * |10001082|151466952| 1| 5232| 11|2014-12-12| 中午| * +--------+---------+-------------+-------------+----+----------+----------+ */ dataset = dataset.map((MapFunction<Row, Row>) row -> { String timeSlice; int time = Integer.parseInt(row.getString(4).trim()); if(time >= 0 && time < 5) { timeSlice = "凌晨"; } else if (time >= 5 && time < 10) { timeSlice = "上午"; } else if (time >= 10 && time < 13) { timeSlice = "中午"; } else if (time >= 13 && time < 18) { timeSlice = "下午"; } else { timeSlice = "晚上"; } return RowFactory.create(row.getInt(0), row.getInt(1), row.getInt(2), row.getInt(3), row.getString(4), row.getString(5), timeSlice); }, RowEncoder.apply(new StructType(new StructField[]{ new StructField("user_id", DataTypes.IntegerType,false, Metadata.empty()), new StructField("item_id", DataTypes.IntegerType,false, Metadata.empty()), new StructField("behavior_type", DataTypes.IntegerType,false, Metadata.empty()), new StructField("item_category", DataTypes.IntegerType,false, Metadata.empty()), new StructField("time", DataTypes.StringType,false, Metadata.empty()), new StructField("date", DataTypes.StringType,false, Metadata.empty()), new StructField("time_slice", DataTypes.StringType,false, Metadata.empty()) }))); //app流量分析 appTrafficAnalysis(dataset); //用户行为分析 userBehaviorAnalysis(session, dataset); //商品分析 productAnalysis(dataset); }