1. 程式人生 > 實用技巧 >spark之手機基站定位資料的商圈分析

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); } }