spark的学习(2)之计算最受欢迎美食种类然后画词云

上一篇文章主要讲的是spark如何进行词频统计,数据集为自己创建的,本篇主要使用上一篇的逻辑在实际应用中进行扩展—计算广州美食中最受欢迎的美食类别,然后把数据画成词云。

本篇是上一篇spark的学习(1)之使用spark进行WordCount词数统计的扩展,所以本篇没有涉及到更多的API,主要基于原本的API。重点在于思路,至于spark的后续知识点会在后续博文中说明,(^_−)☆ 关注博主不走丢

如果进行大数据处理,首先我们需要先明白数据,本文中的数据集是从和鲸社区中下载的,下载地址如下

https://www.heywhale.com/mw/dataset/5ee30becb772f5002d75a965/content

把数据集下载下来后,解压到idea中data目录下

读取数据

创建FoodsCount类,注意是Object类型,然后创建main方法,方法中编写spark,编写的方式和之前类似

第一步:创建Spark上下文

第二步:读取数据

第三步:转换数据

第四步:计算数据格式

这里我们先开始写第一步,读取数据

object FoodsCount {

  def main(args: Array[String]): Unit = {
	// 创建spark上下文
    val spark = new SparkContext("local",
      "food")

    // 读取数据,A.csv就是刚下载的文件,我这里之前对文件进行重命名,自己用的时候注意改下
    val data = spark.textFile("data/A.csv")

    // 打印数据看下效果
    // take(10) 返回数据中10条记录
    // foreach(println(_)) 遍历数据,输出每一条  
    data.take(10).foreach(println(_))
  }

}

输出结果如下

名称,评论数,人均价格,类别,商圈,地址,推荐1,推荐2,推荐3,口味评分,环境评分,服务评分,星级,店铺ID,网址
极炙·台灣精致炭火烤肉,3551,211元,日本料理,天河城/体育中心,天河路178-188号新天河宾馆院内综合楼3楼,极上和牛套餐,特选牛舌,元贝,9.1,8.5,9.2,五星商户,66250176,http://www.dianping.com/shop/66250176
大滷爺(正佳店),151,54元,粤菜,天河城/体育中心,体育东路正佳广场五楼广正街,滷爺鹅肉饭,生蚝沙锅粥,卤水鹅肝饭,9.3,9.1,9.1,五星商户,id110266597,http://www.dianping.com/shop/110266597
白天鹅宾馆·玉堂春暖餐厅,2018,312元,粤菜,沙面,沙面南街1号白天鹅宾馆3楼,沙琪玛,葵花鸡,招牌虾饺,8.9,9.3,9,五星商户,id520094,http://www.dianping.com/shop/520094
Mr.Fish鱼鲜生海鲜放题(高德置地冬广场店),7703,354元,自助餐,高德置地/花城汇,珠江新城花城大道85号高德置地冬广场5楼507-512铺,刺身新鲜,新西兰鳌虾,燕窝哈根达斯雪糕,8.8,9,8.7,准五星商户,id32501719,http://www.dianping.com/shop/32501719
漫活堂·健康有机西餐厅(高志店),1174,148元,西餐,兴盛路/跑马场,黄埔大道西120号高志大厦首层107铺,低温慢煮牛小排,青苹果焦糖核桃沙拉,鲜虾墨鱼汁意大利面配参巴海鲜酱,9.1,9,9,五星商户,id76972044,http://www.dianping.com/shop/76972044
点都德(花城店),5424,88元,茶餐厅,珠江新城,花城大道16号,金沙红米肠,金牌鲜虾饺皇,百合蒸酱凤爪,9,8.9,8.4,准五星商户,id56985236,http://www.dianping.com/shop/56985236
点都德(骏和楼店),1393,79元,茶餐厅,市桥,市桥街捷进二路1号骏和广场三楼,金沙红米肠,金牌鲜虾饺皇,沙爹金钱肚,9.1,9,8.8,五星商户,id69100250,http://www.dianping.com/shop/69100250
松月自慢料理,1348,382元,日本料理,珠江新城,珠江西路15号珠江城大厦商业4层,生烤牛肉,刺身拼盘,牛油果虾手卷,9,9.3,9.1,五星商户,id92411666,http://www.dianping.com/shop/92411666
串八·炉端烧,70,178元,日本料理,兴盛路/跑马场,马场西路黄埔大道西668号马会酒店大堂内,牛舌,牛肉鹅肝卷,豚肉芦笋卷,9.3,9,9,五星商户,id98948970,http://www.dianping.com/shop/98948970

从打印的数据中可以看出,目前程序正常,然后查看数据集,数据集本身是CSV文件,该类型文件,一般第一行作为标题,每一个数据之间使用逗号作为间隔,从打印数据的第一行中我们可以得出数据集主要涵盖饭店的名称,类别,人均等信息。

明白数据后,我们开始回归到本身的问题:计算广州美食中最受欢迎的美食类别

当我们拿到一个问题后,需要把问题转换成使用数字可以解决的问题,在这个问题中我们可以简单算为,餐厅类型最多的就是最受人喜欢的,因为喜欢,客户量大,才有老板开这个类型的饭店,所谓我们可以把原问题转换为 广州美食中餐厅类别数量

理清思路后,我们就需要把数据集中的数据,转换成便于计算的格式

转换&计算数据

此时数据的格式还是全有逗号隔开

极炙·台灣精致炭火烤肉,3551,211元,日本料理,天河城/体育中心,天河路178-188号新天河宾馆院内综合楼3楼,极上和牛套餐,特选牛舌,元贝,9.1,8.5,9.2,五星商户,66250176,http://www.dianping.com/shop/66250176

在这里面我们只需要类别这一个值,并且计算最后多出现的数量,这其实有点类似于之前词频统计了,不同的是统计的是类别中的数据,并且数据集接近于实际数据,但是道理是一样的。

为方便计算,我们需要把数据转换成

(日本料理,1),(粤菜,1)....

最后统计相同key值就好了,具体代码如下

    ...
    val foodTypes = data.map(
      line => {
      	// 针对数据进行切分
        val arr = line.split(",")
        // 因为只需要类型,所以取切分后数组下标为3的数据
        (arr(3),1)
      }
    )
	// 还是和之前统计词频一样的方式,countByKey()统计相同key的数量
    val result = foodTypes.countByKey()
    result.foreach(println(_))

结果输出如下

(新疆菜,1)
(咖啡厅,12)
(西北菜,1)
(东南亚菜,7)
......

此时绘画成词云,更便于查看

绘画词云

词云是文字组件的一种,支持自定义文本的内容、颜色、绘制形状等,支持多系列颜色配置,支持根据权重值映射文本大小,能够以词云的形式在可视化应用中展示较多数量的文本。

scala本身不支持词云,在这里我们使用java的kumo去生成词云。

首先在当下项目pom文件下,导入依赖

		<dependency>
            <groupId>com.kennycason</groupId>
            <artifactId>kumo-core</artifactId>
            <version>1.13</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-lang3</artifactId>
                    <groupId>org.apache.commons</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>com.kennycason</groupId>
            <artifactId>kumo-tokenizers</artifactId>
            <version>1.12</version>
        </dependency>

在项目下创建utils包,用于存放相关类。

创建MyAngleGenerator类继承AngleGenerator,这里主要是为了自定义词云排列的横纵比,避免大多数单词纵状排列,直接复制下就好

public class MyAngleGenerator extends AngleGenerator {

    private static final Random RANDOM = new Random();
    private final int steps;
    private final double[] thetas;
    private int next;

    public MyAngleGenerator() {
        this.steps = 3;
        this.thetas = this.calculateThetas(-90.0D, 90.0D);
    }

    @Override
    public double randomNext() {
        // 0.8 水平 0.2 垂直
        int i = RANDOM.nextInt(10);
        if (i < 2) { // 这里修改概率
            i = RANDOM.nextInt(2);
            if (i < 1) {
                return thetas[0];
            } else {
                return thetas[2];
            }
        } else {
            return this.thetas[1];
        }
    }

    private double[] calculateThetas(double to, double from) {
        double stepSize = (to - from) / (double)(this.steps - 1);
        double[] thetas = new double[this.steps];

        for(int i = 0; i < this.steps; ++i) {
            thetas[i] = this.degreesToRadians(from + (double)i * stepSize);
        }

        return thetas;
    }

    private double degreesToRadians(double degrees) {
        return 3.141592653589793D * degrees / 180.0D;
    }

}

创建词云生成的工具类WordCloudUtil,用于生成词云

public class WordCloudUtil {

    /**
     * 根据集合生成圆形词云
     * @param wordFrequencies WordFrequency 的集合对象
     *                        WordFrequency(单词,单词数量)
     */
    public static void createWordCloud(List<WordFrequency> wordFrequencies){
		// 设置图片大小
        Dimension dimension = new Dimension(300, 300);

        //设置图片相关的属性,这边是大小和形状,更多的形状属性,可以从CollisionMode源码里面查找
        WordCloud wordCloud = new WordCloud(dimension, CollisionMode.PIXEL_PERFECT);
        wordCloud.setPadding(2);

        //这边要注意,是设置中文字体的,如果不设置,得到的将会是乱码,
        java.awt.Font font = new java.awt.Font("STSong-Light", 2, 40);
        wordCloud.setKumoFont(new KumoFont(font));
        // 设置背景色
        wordCloud.setBackgroundColor(new Color(255, 255, 255));
        // 设置圆的半径
        wordCloud.setBackground(new CircleBackground(150));
        // 设置颜色
        wordCloud.setColorPalette(new LinearGradientColorPalette(Color.RED, Color.BLUE, Color.GREEN, 30, 30));
        wordCloud.setFontScalar(new SqrtFontScalar(12, 45));
        // 自定义横纵比例
        wordCloud.setAngleGenerator(new MyAngleGenerator());

        //将文字写入图片
        wordCloud.build(wordFrequencies);
        //生成图片
        wordCloud.writeToFile("output/foods.png");
    }

}

然后接下来就是scala中的调用了,在原来scala main方法下

...
	// 创建词云数据
    var wordFrequencies = ArrayBuffer[WordFrequency]()
    // 遍历result,把对应数据存入词云数据中
    result.foreach{
      case(str,num) => {
        wordFrequencies = wordFrequencies :+ (new WordFrequency(str,num.toInt))
      }
    }
    // 开始调用,注意提前导入import scala.collection.JavaConverters._
    // 因为要使用asJava方法把scala对象转换为java对象
    WordCloudUtil.createWordCloud(wordFrequencies.asJava)
...

运行完成后可以在当前项目下的output目录中看到生成图片如下

在这里插入图片描述

从词云中可以看出,目前最受欢迎的属于西餐,日本料理和粤菜。

以上就是文章所有内容,代码在以下地址中

https://gitee.com/lihao2/blog-code

本文主要是一些思路,spark简单处理,Spark中关于数据的操作还有很多,我们将在后续文章中去讲,( ̄︶ ̄)↗ 关注博主不走丢

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值