Fork me on GitHub

spark之手机基站定位数据的商圈分析

一.目的

基于基站定位数据的商圈分析
移动通信网络会记录用户手机的相关信息,比如手机所处的基站区域编号,所处基站的时间等。根据这些数据可以进行商圈划分,目的是
为了研究潜在的顾客的分布以制定适宜的商业对策。如:可划分商业区、住宅区以及工作区

二.数据

数据来源【Python数据分析与挖掘实战(第14章基于基站定位数据的商圈分析)】,可自行搜索下载。

原始数据集没有找到,找到的数据是被统计,转换,过滤过的数据:
这四个特征的统计方法是:
对于某个基站(观测窗口为L天,基站N个,用户M个;
某个用户i在j天在某个基站的 =》 工作日上班时间停留时间为weekday,凌晨停留时间为night,周末停留时间weekend,是否停留为stay【1:停留;0:无停留】):

工作日上班时间人均停留时间(9:00-18:00)
凌晨人均停留时间(00:00-07:00)
周末人均停留时间
日均人流量

基站编号,工作日上班时间人均停留时间,凌晨人均停留时间,周末人均停留时间,日均人流量
  36902,  78,                     521,           602,           2863
  36903,  144,                    600,           521,           2245
  36904,  95,                     457,           468,           1283
  36905,  69,                     596,           695,           1054

三.代码

通过提取和处理特征,利用聚类方法聚成几个区域,并对区域进行分析。详细代码:手机基站定位数据的商圈分析(https://github.com/jiangnanboy/spark_tutorial)

public static void businessCircleStatistics(SparkSession session) {
        String path = PropertiesReader.get("intermediate_business_circle_csv");
        /**
         * +--------+--------------------------+----------------+----------------+----------+
         * |基站编号 |工作日上班时间人均停留时间   |凌晨人均停留时间  |周末人均停留时间  |日均人流量|
         * +--------+--------------------------+----------------+----------------+----------+
         * |   36902|                        78|             521|             602|      2863|
         * |   36903|                       144|             600|             521|      2245|
         * |   36904|                        95|             457|             468|      1283|
         * |   36905|                        69|             596|             695|      1054|
         * |   36906|                       190|             527|             691|      2051|
         * +--------+--------------------------+----------------+----------------+----------+
         *  |-- 基站编号: integer (nullable = true)
         *  |-- 工作日上班时间人均停留时间: integer (nullable = true)
         *  |-- 凌晨人均停留时间: integer (nullable = true)
         *  |-- 周末人均停留时间: integer (nullable = true)
         *  |-- 日均人流量: integer (nullable = true)
         */
        Dataset<Row> dataset = session.read()
                .option("sep", ",")
                .option("header", "true")
                .option("inferSchema", "true")
                .csv(path);

        /**
         * 转为特征向量
         * +---------+--------------------+
         * |stationID|            features|
         * +---------+--------------------+
         * |    36902|[78.0,521.0,602.0...|
         * |    36903|[144.0,600.0,521....|
         * |    36904|[95.0,457.0,468.0...|
         * |    36905|[69.0,596.0,695.0...|
         * |    36906|[190.0,527.0,691....|
         * +---------+--------------------+
         */
        dataset = dataset.map((MapFunction<Row,Row>) row -> {
            int stationID = row.getInt(0);
            double weekdayAvg = (double) row.getInt(1);
            double nightAvg = (double) row.getInt(2);
            double weekendAvg = (double) row.getInt(3);
            double stayAvg = (double) row.getInt(4);
            return RowFactory.create(stationID, Vectors.dense(new double[]{weekdayAvg, nightAvg, weekendAvg, stayAvg}));
        }, RowEncoder.apply(new StructType(new StructField[]{
                new StructField("stationID", DataTypes.IntegerType,false, Metadata.empty()),
                new StructField("features", SQLDataTypes.VectorType(), false, Metadata.empty())
        })));

        /**
         * 数据标准化
         */
        MinMaxScalerModel featureScaler = new MinMaxScaler()
                .setInputCol("features")
                .setOutputCol("scaledFeatures")
                .fit(dataset);
        /**
         *+---------+--------------------+--------------------+
         * |stationID|            features|      scaledFeatures|
         * +---------+--------------------+--------------------+
         * |    36902|[78.0,521.0,602.0...|[0.10386473429951...|
         * |    36903|[144.0,600.0,521....|[0.26328502415458...|
         * |    36904|[95.0,457.0,468.0...|[0.14492753623188...|
         * |    36905|[69.0,596.0,695.0...|[0.08212560386473...|
         * |    36906|[190.0,527.0,691....|[0.37439613526570...|
         * +---------+--------------------+--------------------+
         */
        Dataset<Row> scaledData = featureScaler.transform(dataset);

        /**
         * 轮廓系统确定簇数,可以看出分为3类最佳
         * k: 2 silhouette: 0.5063659448997802
         * k: 3 silhouette: 0.629019144457301
         * k: 4 silhouette: 0.32319167016337247
         * k: 5 silhouette: 0.30681655682008674
         * k: 6 silhouette: 0.39947777279975305
         * k: 7 silhouette: 0.31054738863541337
         * k: 8 silhouette: 0.3417574406084828
         * k: 9 silhouette: 0.30133745097199804
         * k: 10 silhouette: 0.12586962519806658
         */
        int k = selectOptimalK(scaledData, 10);

        //model,利用层次聚类
        BisectingKMeans bkm = new BisectingKMeans().setFeaturesCol("scaledFeatures")
                .setK(k) //簇数
                .setSeed(1);
        BisectingKMeansModel model = bkm.fit(scaledData);
        /**
         * 预测结果,后面根据聚类结果划分出不同的商圈,对3类数据中的4个特征进行分析,定义3类商圈的不定定位进行商业活动,具体可看《python数据分析与挖掘实战》一书中的第14章。
         * 根据3类数据的活动并异,可划分商业区、住宅区以及工作区
         * +---------+--------------------+--------------------+----------+
         * |stationID|            features|      scaledFeatures|prediction|
         * +---------+--------------------+--------------------+----------+
         * |    36902|[78.0,521.0,602.0...|[0.10386473429951...|         1|
         * |    36903|[144.0,600.0,521....|[0.26328502415458...|         1|
         * |    36904|[95.0,457.0,468.0...|[0.14492753623188...|         1|
         * |    36905|[69.0,596.0,695.0...|[0.08212560386473...|         1|
         * |    36906|[190.0,527.0,691....|[0.37439613526570...|         1|
         * +---------+--------------------+--------------------+----------+
         */

        Dataset<Row> predictions  = model.transform(scaledData);
        predictions.show(5);

        /**
         * 聚类中心
         * [0.13227119317053798,0.04483188044831879,0.19956941131772793,0.7100471677339725]
         * [0.1886016451233843,0.8021375921375923,0.7629929621455044,0.09096028267984407]
         * [0.8643640466871185,0.048015925680159235,0.12134333562021299,0.3287583779747489]
         */

        Vector[] centers = model.clusterCenters();
        for(Vector center : centers) {
            System.out.println(center);
        }

    }
posted @ 2020-11-22 10:25  石头木  阅读(739)  评论(0编辑  收藏  举报