Spark实现电商消费者画像案例

作者/朱季谦

故事得从这一张图开始说起——

可怜的打工人准备下班时,突然收到领导发来的一份电商消费者样本数据,数据内容是这样的——

消费者姓名|年龄|性别|薪资|消费偏好|消费领域|常用购物平台|常用支付方式|单次购买商品数量|优惠券获取情况|购物动机

Mario Johnston,53,男,12510,性价比,母婴用品,网易考拉,信用卡,2,折扣优惠,兴趣爱好
Daniel Cooper,28,男,11891,社交影响,图书音像,京东,信用卡,1,折扣优惠,兴趣爱好
Amber Powell,28,女,3365,环保可持续,食品饮料,苏宁易购,货到付款,1,折扣优惠,日常使用
Olivia Fletcher,32,女,3055,环保可持续,食品饮料,天猫,银联支付,7,满减优惠,日常使用
William Wood,32,男,13492,创新设计,电子产品,网易考拉,货到付款,9,有优惠券,商品推荐
Sarah Bell,36,男,17791,创新设计,家居用品,亚马逊,微信支付,1,免费赠品,商品推荐
Cynthia Grant MD,65,男,17847,品牌追求,服装,唯品会,支付宝,3,有优惠券,跟风购买
......

这份数据样本总共五千多条,打工人害怕弄丢了,他决定先上传到百度网盘,放在这个网盘地址里——

链接: 百度网盘 请输入提取码 提取码: wjgw

存好数据后,打工人去跟领导讨论一下需要分析哪些画像,领导给了一下几个思路——

年龄和性别画像:根据用户的年龄和性别信息,了解不同年龄段和性别分布情况。
购物平台和支付方式画像:了解用户首选的电商平台和支付方式,有助于针对不同渠道进行个性化的营销活动。
优惠偏好画像:通过用户在折扣优惠、免费赠品等方面的选择,可以了解其在购物时最看重哪些优惠方式。
商品类别偏好画像:根据用户对汽车配件、珠宝首饰、图书音像等不同商品类别的选择,可以推测用户的兴趣爱好和消费倾向。
购物目的画像:通过用户对商品的描述,如性价比、时尚潮流、环保可持续等,推断其购物的目的和价值观。

接下来,就是基于这些数据和分析目标,开始基于Spark实现电商用户画像案例讲解。

在线上生产环境里,样本数据一般会放到HDFS或者HBase等地方,这些数据可能还会进一步清洗后同步到Hive里,方便直接Hive SQL或者Spark-SQL方式读取到做计算。本次代码案例里,暂时不需要涉及那么复杂的存储,只需了解真实生产线上数据是放HDFS、HBase等仓库存储即可。

一、本地样本文件的存放和读取清洗

把样本文件consumers.csv放到项目里路径为src/main/resources/consumers.csv,通过Spark读取到内存当中,顺便打印看下读取到的数据情况——

def main(args: Array[String]): Unit = {
  val conf = new SparkConf().setMaster("local").setAppName("consumer")
  val ss = SparkSession.builder().config(conf).getOrCreate()
  val filePath: String = "src/main/resources/consumers.csv"
  val fileRDD = ss.sparkContext.textFile(filePath)
}

打印的结果如下所示——

Gary Mcpherson,37,女,11936,个性定制,食品饮料,京东,支付宝,4,折扣优惠,兴趣爱好
Molly Stone,31,女,14962,时尚潮流,汽车配件,拼多多,微信支付,3,无优惠券,商品推荐
Amy Wright,65,女,12855,时尚潮流,运动健身,唯品会,信用卡,3,满减优惠,日常使用
Anna Christensen,35,男,8201,创新设计,图书音像,亚马逊,货到付款,3,满减优惠,跟风购买
Samuel Santana,23,男,5061,创新设计,汽车配件,京东,支付宝,10,折扣优惠,跟风购买
Robert Williams,25,女,3038,环保可持续,食品饮料,网易考拉,支付宝,6,有优惠券,日常使用
Christopher Brown,40,女,9087,社交影响,服装,天猫,货到付款,5,折扣优惠,跟风购买
Dale Vazquez,40,女,14648,社交影响,食品饮料,亚马逊,信用卡,2,满减优惠,兴趣爱好
......

可见,Spark读取到内存里的数据,还是原始数据格式,我们需要对其进行切割,最简单的方式,就是通过Spark的map算子,将每一行的字符串,切割后存入到数组结构里,转换的情况如下图所示——

只需要一行代码就可以实现将原始样本每一行字符数据转成数组结构——

val consumerRDD = fileRDD.map(_.split(","))

转换生成的consumerRDD里每一行数据,可以理解成是一个数组,数组索引0~10对应的字段类型如下——

原始样本处理成上图情况,后续的操作,其实就纯粹可以通过类似SQL形式来计算需要的结果了。

二、画像数据分析的实现

2.1、商品类别偏好画像

根据用户对汽车配件、珠宝首饰、图书音像等不同商品类别的选择,可以推测用户的兴趣爱好和消费倾向。

针对这个需求,可以通过以下代码实现——

def main(args: Array[String]): Unit = {
  val conf = new SparkConf().setMaster("local").setAppName("consumer")
  val ss = SparkSession.builder().config(conf).getOrCreate()
  val filePath: String = "src/main/resources/consumers.csv"
  val fileRDD = ss.sparkContext.textFile(filePath)
  val consumerRDD = fileRDD.map(_.split(","))
  consumerRDD.map(x => (x.apply(5), 1)).reduceByKey(_ + _).sortBy(_._2, false).foreach(println)
}

打印结果如下,可见这批样本里,受消费者消费倾向最多的前TOP3,分别是服装、家居用品、图书音像——

(服装,553)
(家居用品,542)
(图书音像,539)
(珠宝首饰,535)
(母婴用品,530)
(美妆护肤,526)
(汽车配件,523)
(电子产品,506)
(食品饮料,500)
(运动健身,492)

实现的核心是通过这行代码consumerRDD.map(x => (x.apply(5), 1)).reduceByKey(_ + ).sortBy(._2, false)。

consumerRDD.map(x => (x.apply(5), 1))中的x.apply(5)是对应【消费领域】字段,表示将consumerRDD中每行元素里的消费字段做一个映射,值设置为1,代表一个人关注的消费领域。

reduceByKey(_ + _)表示将具有相同键的键值对进行合并,将键相同的值相加,生成一个新的RDD,其中每个键关联着其对应的累加值,例如服装这个key,最后累加得到553值。

sortBy(.2, false)表示是按照累加的值大小降序排序。

结合以上函数,就可以实现将consumerRDD中的数据按照【消费领域】字段,聚合出每个领域的消费者数量。

2.2、优惠偏好画像

通过用户在折扣优惠、免费赠品、品牌忠诚等方面的选择,可以了解其在购物时最看重哪些消费习惯。

def main(args: Array[String]): Unit = {
  val conf = new SparkConf().setMaster("local").setAppName("consumer")
  val ss = SparkSession.builder().config(conf).getOrCreate()
  val filePath: String = "src/main/resources/consumers.csv"
  val fileRDD = ss.sparkContext.textFile(filePath)
  val consumerRDD = fileRDD.map(_.split(","))
  consumerRDD.map(x => (x.apply(10), 1)).reduceByKey(_ + _).sortBy(_._2, false).foreach(println)
}

打印结果如下,可以看到,在这批消费者样本里,基于日常使用、礼物赠送、商品推荐等消费方式受众最多,那么可以基于商品消费做进一步优化——

(日常使用,777)
(礼物赠送,773)
(商品推荐,762)
(兴趣爱好,750)
(品牌忠诚,750)
(跟风购买,724)
(促销打折,710)

2.3、优惠券获取情况和购物动机的关系

观察优惠券获取情况和购物动机之间的联系,探索消费者是否更倾向于使用优惠券进行购物

def main(args: Array[String]): Unit = {
  val conf = new SparkConf().setMaster("local").setAppName("consumer")
  val ss = SparkSession.builder().config(conf).getOrCreate()
  val filePath: String = "src/main/resources/consumers.csv"
  val fileRDD = ss.sparkContext.textFile(filePath)
  val consumerRDD = fileRDD.map(_.split(","))
  //以下实现将RDD转换成类似关系型数据库表的形式
  val rowRDD = consumerRDD.map {
    x => Row(x.apply(0), x.apply(1).toInt, x.apply(2), x.apply(3).toInt, x.apply(4), x.apply(5), x.apply(6), x.apply(7), x.apply(8).toInt, x.apply(9), x.apply(10))
  }
  //Row里0~10索引数据映射的字段
  val schema = StructType(Seq(
    StructField("consumerName", StringType),
    StructField("age", IntegerType),
    StructField("gender", StringType),
    StructField("monthlyIncome", IntegerType),
    StructField("consumptionPreference", StringType),
    StructField("consumptionArea", StringType),
    StructField("shoppingPlatform", StringType),
    StructField("paymentMethod", StringType),
    StructField("quantityOfItemsPurchased", IntegerType),
    StructField("couponAcquisitionStatus", StringType),
    StructField("shoppingMotivation", StringType)
​
  ))
  val df = ss.createDataFrame(rowRDD, schema).toDF()
 //按照【优惠券获取情况】和【购物动机】分组统计
  val analysisResult = df.groupBy("couponAcquisitionStatus", "shoppingMotivation")
    .agg(count("*").alias("MotivationCount"))
    .orderBy(desc("MotivationCount"))
​
  analysisResult.show()
}

打印结果如下,可见,当商品同时做【折扣优惠】和【商品推荐】时,消费者数量是最多的,其次就是购买消费有【免费赠品】及出于【兴趣爱好】动机消费。针对这类情况,可以做进一步分析,进而调整营销策略。

+-----------------------+------------------+---------------+
|couponAcquisitionStatus|shoppingMotivation|MotivationCount|
+-----------------------+------------------+---------------+
|               折扣优惠|          商品推荐|            168|
|               免费赠品|          兴趣爱好|            167|
|               免费赠品|          礼物赠送|            166|
|               满减优惠|          日常使用|            166|
|               无优惠券|          兴趣爱好|            165|
|               免费赠品|          商品推荐|            162|
|               免费赠品|          跟风购买|            160|
|               免费赠品|          日常使用|            159|
|               折扣优惠|          跟风购买|            158|
|               有优惠券|          礼物赠送|            157|
|               免费赠品|          促销打折|            157|
|               折扣优惠|          品牌忠诚|            157|
|               无优惠券|          日常使用|            156|
|               有优惠券|          日常使用|            156|
|               满减优惠|          礼物赠送|            155|
|               有优惠券|          品牌忠诚|            154|
|               免费赠品|          品牌忠诚|            154|
|               满减优惠|          商品推荐|            154|
|               无优惠券|          跟风购买|            153|
|               折扣优惠|          礼物赠送|            151|
+-----------------------+------------------+---------------+

以上是一些简单的实现,在真实环境里,并不会这么简单,可能还会涉及一系列数据的清洗和join处理,进而通过一些模型及算法,计算出更多有价值的画像数据。

样本处理完后,原以为这个故事结束了,打工人可以下班了,没想到——

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/787970.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用各向异性滤波器和图像处理方法进行脑肿瘤检测(MATLAB)

医学图像分割一直以来都是计算机辅助诊断领域的研究热点。在医学图像的处理和分析中,对图像中感兴趣区域的准确分割尤其关键。要对感兴趣区域进行分类识别,首先要从图像中把感兴趣区域精确分割出来,然后有针对性地对感兴趣区域提取特征并分类…

使用clion刷leetcode

如何优雅的使用clion刷leetcode 安装插件:LeetCode Editor) 插件配置: 这样我们每打开一个项目,就会创建类似的文件 我们的项目结构: 我们在题解文件中导入头文件myHeader.h并将新建的文件添加到cmakelists.txt文件,…

初识CPlusPlus

前言 也是好久没写博客了,那些天也没闲着,去练题去了。实际上练题也可以写练题的博客,但是觉得太简单了些,于是就没有继续写下去。如今又回来写博客,是因为有整理了新的知识C。内容不算多,大多数都是书本上…

接口测试工具Apifox使用以及多环境的配置

下载 Apifox - API 文档、调试、Mock、测试一体化协作平台 - 接口文档工具,接口自动化测试工具,接口Mock工具,API文档工具,API Mock工具,API自动化测试工具 安装 正常安装 , 微信扫码注册 apifox中创建项目 安装idea插…

数学建模美赛入门

数学建模需要的学科知识 高等数学线性代数 有很多算法的掌握是需要高等数学和线代的相关知识 如:灰色预测模型需要微积分知识;神经网络需要用到导数知识;图论和层次分析法等都需要用到矩阵计算的相关知识等; 概率论与数理统计&am…

Xubuntu24.04之设置高性能模式两种方式(二百六十一)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+AOSP…

YOLOv8改进 在通道维度上引入注意力机制CPCAttention

一、CPCAttention论文 论文地址:2306.05196 (arxiv.org) 二、CPCAttention结构 Channel prior convolutional attention (CPCA)用于图像分类和目标检测任务中。CPCA能够在卷积神经网络中引入通道相关性,并通过自适应地学习到每个通道的权重,从而提升模型的性能。 CPCA的关…

纯前端如何实现Gif暂停、倍速播放

前言 GIF 我相信大家都不会陌生&#xff0c;由于它被广泛的支持&#xff0c;所以我们一般用它来做一些简单的动画效果。一般就是设计师弄好了之后&#xff0c;把文件发给我们。然后我们就直接这样使用&#xff1a; <img src"xxx.gif"/>这样就能播放一个 GIF …

通过rpmbuild构建Elasticsearch-7.14.2-search-guard的RPM包

系列文章目录 rpmbuild从入门到放弃 search-guard插件使用入门手册 文章目录 系列文章目录前言一、资源准备二、spec文件1.基础信息2.%prep3.%Install4.%file5.%post6.%postun 三、成果演示1.执行构建过程图示例2.执行安装RPM包示例3.进程检查4.访问esApi 总结 前言 不管是源…

Linux--深入理与解linux文件系统与日志文件分析

一、文件与存储系统的 inode 与 block 1.1 硬盘存储 最小存储单位:扇区( sector )每个扇区存储大小:512 字节1.2 文件存取--block block(块),每个 block 块大小为:4k由连续的八个扇区组成一个 block 块是文件索引最小的单位每个 block 块中包括:文件数据文件数据:就…

LeetCode(2)-反转链表、删除链表中等于val的节点、返回链表中的中间节点

一、反转链表 . - 力扣&#xff08;LeetCode&#xff09; 解法1&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ typedef struct ListNode ListNode; struct ListNode* reverseList(struct ListN…

ORA-12537: TNS:连接关闭/Io 异常: Got minus one from a read call

在另外一个数据库建立dblink的时候&#xff0c;发现执行命令报错&#xff1a; 被连接的数据库我也上去过&#xff0c;用工具尝试登陆也报错&#xff1a; IO Error: Got minus one from a read call, connect lapse 1 ms., Authentication lapse 0 ms. Got minus one from a …

Redis过期策略

过期的key集合 Redis会将每个设置了过期时间的key放入到一个独立的字典中&#xff0c;以后会定时遍历这个字典来删除到期的key。除了定时遍历之外&#xff0c;他还会使用惰性策略来删除过期的key&#xff0c;所谓惰性策略就是在客户端访问这个key的时候&#xff0c;redis对key…

生成随机密码

生成8位无重复的密码&#xff08;可以包含数字、大小写字母&#xff09; import random import string character string.digits string.ascii_letters password .join(random.sample(character, 8)) print(f"生成的随机密码为:{password}")

品牌策划秘籍:掌握这些技巧,让你的品牌一炮而红!

作为一名文案策划老司机&#xff0c;这么多年了&#xff0c;总会有一些经验的&#xff0c;这里分享出来&#xff0c;希望能够帮助后来人少走弯路吧。 想要做好品牌和文案策划&#xff0c;首先得做好“侦查”工作。 深入市场&#xff0c;了解行业动态&#xff0c;研究竞争对手…

智能遥测终端机RTU-精确监控 智能运维

智能遥测终端机RTU是物联网领域中一种重要的设备&#xff0c;它的出现无疑为远程监控和数据采集提供了强大的支持。计讯物联智能遥测终端机RTU具备数据采集、处理、通信和控制功能的设备&#xff0c;可以实现对远程设备的监控与控制。它在物联网系统中扮演着桥梁的角色&#xf…

【从零开始实现stm32无刷电机FOC】【理论】【3/6 位置、速度、电流控制】

目录 PID控制滤波单独位置控制单独速度控制单独电流控制位置-速度-电流串级控制 上一节&#xff0c;通过对SVPWM的推导&#xff0c;我们获得了控制电机转子任意受力的能力。本节&#xff0c;我们选用上节得到的转子dq轴解耦的SVPWM形式&#xff0c;对转子受力进行合理控制&…

AE-关键帧

目录 关键帧操作步骤&#xff08;以位置变化为例&#xff09; 1.确定动画起点 2.设置起点的位置属性 3.为起点打上关键帧 4.确定动画终点 5.设置终点的位置属性 改变动画速度 1.选中所有关键帧 2.拖拽 时间反向关键帧 1.选中要反向的关键帧 2.使用时间反向关键帧 …

Websocket 替代方案:如何使用 Firestore 监听实时事件

大家好,我是CodeQi! 一位热衷于技术分享的码仔。 ​在现代 Web 开发中,实时更新功能对于许多应用程序(如聊天应用、协作工具和在线游戏)都是必不可少的。虽然 WebSocket 是一种常用的实时通信技术,但 Google 的 Firestore 也提供了一种强大的替代方案,使得实时监听变得…

数字信号处理教程(3)——z变换

在连续时间域中的每一种分析方法&#xff0c;在离散时间域中想必也能得到对应一种分析方法。连续傅里叶变换对应着离散傅里叶变换&#xff08;DFT&#xff09;&#xff0c;而在拉普拉斯变换则是对应着z变换。z变换能够将信号表示成离散复指数函数的线性组合。连续傅里叶变换可以…