做電子商務(wù)網(wǎng)站需要什么軟件愛站網(wǎng)seo查詢
一.算法介紹
核密度估計(jì)(Kernel Density Estimation)是一種用于估計(jì)數(shù)據(jù)分布的非參數(shù)統(tǒng)計(jì)方法。它可以用于多種目的和應(yīng)用,包括:
- 數(shù)據(jù)可視化:核密度估計(jì)可以用來繪制平滑的密度曲線或熱力圖,從而直觀地表示數(shù)據(jù)的分布情況。它可以幫助我們觀察數(shù)據(jù)集中的高密度區(qū)域、低密度區(qū)域以及變化趨勢。
- 異常檢測:通過核密度估計(jì),我們可以識別數(shù)據(jù)中的異常點(diǎn)或離群值。異常點(diǎn)通常表現(xiàn)為低密度區(qū)域或與其他數(shù)據(jù)點(diǎn)明顯不同的區(qū)域。
- 概率密度計(jì)算:核密度估計(jì)可以用于計(jì)算給定數(shù)值的概率密度。通過將新數(shù)據(jù)點(diǎn)帶入核密度估計(jì)函數(shù),可以估計(jì)出該點(diǎn)在數(shù)據(jù)分布中的密度。
- 模式識別:核密度估計(jì)可以用于識別數(shù)據(jù)中的模式或聚類。通過觀察密度最高的區(qū)域,可以推斷數(shù)據(jù)的聚類情況或潛在的模式。
- 預(yù)測建模:核密度估計(jì)可以用于構(gòu)建概率模型,進(jìn)而進(jìn)行預(yù)測。例如,在分類問題中,可以使用核密度估計(jì)來估計(jì)每個類別的概率密度,然后根據(jù)新的數(shù)據(jù)點(diǎn)所屬的密度來進(jìn)行分類預(yù)測。
根據(jù)具體的應(yīng)用需求,我們可以靈活地使用核密度估計(jì)來分析和理解數(shù)據(jù)集的特征和結(jié)構(gòu),可能的用途包括針對社區(qū)規(guī)劃分析房屋密度或犯罪行為,或探索道路或公共設(shè)施管線如何影響野生動物棲息地。
每個點(diǎn)位可以設(shè)置 weight 字段賦予某些要素比其他要素更大的權(quán)重,該字段還允許使用一個點(diǎn)表示多個觀察對象。例如,一個地址可以表示一棟六單元的公寓,或者在確定總體犯罪率時可賦予某些罪行比其他罪行更大的權(quán)重。
二.算法計(jì)算原理
本算法以四次核函數(shù)為基礎(chǔ),四次核函數(shù)的特點(diǎn)是具有平滑的曲線形狀,具有較寬的窗口,對數(shù)據(jù)點(diǎn)的貢獻(xiàn)在距離較遠(yuǎn)時會迅速減小。由于其平滑性和較大的支持范圍,四次核函數(shù)在核密度估計(jì)中被廣泛使用。
在核密度估計(jì)中,通過將核函數(shù)應(yīng)用于每個數(shù)據(jù)點(diǎn),并對所有數(shù)據(jù)點(diǎn)的貢獻(xiàn)進(jìn)行求和,可以計(jì)算出在每個位置上的密度估計(jì)值。四次核函數(shù)的結(jié)果可視為在核密度估計(jì)中每個位置的密度貢獻(xiàn)權(quán)重。較大的結(jié)果表示該位置的密度較高,而較小或接近零的結(jié)果表示該位置的密度較低。
本算法中主要利用核密度公式計(jì)算空間范圍內(nèi)的核密度值,根據(jù)核密度值生成 png 或 jpg 格式的熱力圖,或者將整個空間切割成網(wǎng)格,用網(wǎng)格中心點(diǎn)參與核密度計(jì)算生成 geojson 文件,以供進(jìn)一步空間探索分析。
/*** 計(jì)算單個核密度* @param radius 半徑* @param dist 兩點(diǎn)的距離* @param weight 權(quán)重* @return*/public static double computeKernel(double radius, double dist, double weight){return (3 / Math.PI) * weight * Math.pow((1 - Math.pow(dist / radius,2)), 2);}
創(chuàng)新性說明:
- 1.算法會自適應(yīng)數(shù)據(jù)中的空間點(diǎn)位范圍,此范圍可根據(jù)參數(shù)bufferSize 設(shè)置緩沖區(qū)擴(kuò)展,以獲取數(shù)據(jù)范圍外的點(diǎn)參與計(jì)算。
- 2.根據(jù)空間范圍每隔特定步長創(chuàng)建虛擬點(diǎn)位或劃分網(wǎng)格,靈活性較高,步長越小則結(jié)果在地圖分布上的精度越高,步長參數(shù)step(米) 可選,如果沒有設(shè)置, 則默認(rèn)在空間范圍內(nèi)自適應(yīng)創(chuàng)建一百萬左右虛擬點(diǎn)或網(wǎng)格。
- 3.采用多線程的方式進(jìn)行核密度計(jì)算,速度更快。
- 4.可將結(jié)果值進(jìn)行歸一化處理,核密度計(jì)算出來的結(jié)果值主要用于觀察數(shù)據(jù)分布,但是各個結(jié)果值之間相差范圍較大,不易觀察數(shù)據(jù)分布,歸一化后能更清晰觀察不同區(qū)域間的分布情況。
- 5.可根據(jù)核密度值的大小根據(jù)不同需求生成熱力圖或 geojson 文件。可在geojson文件上做進(jìn)一步探索。
三.算法程序
1. 核心流程代碼
從csv中獲取源數(shù)據(jù)點(diǎn)信息, 獲取坐標(biāo)范圍,如果需要緩沖區(qū), 則設(shè)置緩沖區(qū), 獲取步長長度(默認(rèn)一百萬個像素點(diǎn)或網(wǎng)格),然后根據(jù)核密度信息創(chuàng)建圖片或geojson
// 輸入文件路徑String inputPath ="D:\\測試數(shù)據(jù).csv";// 輸出文件路徑String outPath ="D:\\測試數(shù)據(jù).geojson";// String outPath ="D:\\測試數(shù)據(jù).jpg";// 經(jīng)度字段String lonKey = "lon";// 緯度字段String latKey = "lat";// 權(quán)重字段String weightKey = "";// 影響半徑double radius = 300.0;// 緩沖區(qū)double bufferSize = 0.1;// 生成的網(wǎng)格長度(單位: 米)int step = 0;int type;if (outPath.endsWith("png") || outPath.endsWith("jpg")){type = 0;}else if (outPath.endsWith("geojson")){type = 1;}else {throw new RuntimeException("輸出文件格式只能是 png、jpg 或者 geojson");}// 從csv中獲取源數(shù)據(jù)點(diǎn)信息List<EntryPoint> entryPoints = EntryPoint.formatToEntryPoints(inputPath, lonKey, latKey, weightKey, radius);// 獲取坐標(biāo)范圍double[] coordsScope = KernelUtils.getCoordsScope(entryPoints);// 如果需要緩沖區(qū), 則設(shè)置緩沖區(qū)if (bufferSize != 0){coordsScope = KernelUtils.getBufferScope(coordsScope[0], coordsScope[1], coordsScope[2], coordsScope[3], bufferSize);}// 獲取默認(rèn)的步長長度, 默認(rèn)一百萬個像素點(diǎn)或網(wǎng)格if (step ==0){step = KernelUtils.getDefaultSize(coordsScope);}// 根據(jù)核密度信息創(chuàng)建圖片或geojsonkernel(coordsScope, entryPoints, step, radius, type, outPath);
/*** 核密度方法* @param coordsScope 坐標(biāo)范圍* @param entryPoints 從csv中獲取源數(shù)據(jù)點(diǎn)信息* @param step 步長長度* @param radius 影響半徑* @param type 輸出文件類型*/public static void kernel(double[] coordsScope, List<EntryPoint> entryPoints, int step, double radius, int type, String path){// 獲取網(wǎng)格坐標(biāo)系的lon, lat的列表List<Double[]> coords = KernelUtils.getKennelPointCoords(coordsScope[0], coordsScope[1],coordsScope[2],coordsScope[3], step);Progress.progress( progress++);int width = coords.get(0).length;int high = coords.get(1).length;if (type == 1){// 生產(chǎn) geojson 網(wǎng)格結(jié)果generatorGridGeojson(coords, entryPoints, width-1, high-1, radius, path, step);}else {// 生產(chǎn)熱力圖圖片generatorThermalMap(coords, entryPoints, width, high, radius, path, step);}}
2.創(chuàng)建面的 geojson 文件
/*** 根據(jù)核密度信息創(chuàng)建面的 geojson 文件* @param coords 虛擬數(shù)據(jù)點(diǎn)經(jīng)緯度列表* @param entryPoints 數(shù)據(jù)點(diǎn)* @param width 橫向點(diǎn)位數(shù)量* @param high 縱向點(diǎn)位數(shù)量* @param radius 影響半徑*/public static void generatorGridGeojson(List<Double[]> coords, List<EntryPoint> entryPoints,int width, int high, double radius, String path, int step){// 獲取所有中心點(diǎn)位的數(shù)據(jù)List<PixelPoint> pixelPoints = KernelUtils.getGridCenters(coords);// 進(jìn)行核密度計(jì)算, 并記錄受到影響的網(wǎng)格信息KernelResult kernelResult = kernelCompute(entryPoints, pixelPoints, width, high, radius);Double[][] matrix = kernelResult.getMatrix();Double max = kernelResult.getMax();Double min = kernelResult.getMin();// 生產(chǎn)面的 geojson 文件writeToFile(KernelUtils.jointGridGeojson(matrix, max, min, coords), path);System.out.println(String.format("計(jì)算完成, 生成 geojson 文件, 參與計(jì)算網(wǎng)格 %d 個, 受影響網(wǎng)格 %d 個, 相鄰網(wǎng)格間距 %s 米",pixelPoints.size(), KernelUtils.effectiveGrid, step));}
3.熱力圖圖片
/*** 根據(jù)核密度信息創(chuàng)建熱力圖圖片* @param coords 虛擬數(shù)據(jù)點(diǎn)經(jīng)緯度列表* @param entryPoints 數(shù)據(jù)點(diǎn)* @param width 橫向點(diǎn)位數(shù)量* @param high 縱向點(diǎn)位數(shù)量* @param radius 影響半徑*/public static void generatorThermalMap(List<Double[]> coords, List<EntryPoint> entryPoints,int width, int high, double radius, String path, int step){// 獲得所有點(diǎn)位List<PixelPoint> pixelPoints = KernelUtils.spliceKennelPoints(coords);// 進(jìn)行核密度計(jì)算, 并記錄受到影響的網(wǎng)格信息KernelResult kernelResult = kernelCompute(entryPoints, pixelPoints, width, high, radius);Double[][] matrix = kernelResult.getMatrix();Double max = kernelResult.getMax();Double min = kernelResult.getMin();// 生產(chǎn)熱力圖ImageGenerator.generatorImage(matrix, max, min, path);System.out.println(String.format("計(jì)算完成, 生成圖片 像素: %d x %d, 相鄰像素點(diǎn)實(shí)際代表距離 %s 米", width, high, step));}
4.計(jì)算所有點(diǎn)位的核密度
/*** 計(jì)算所有點(diǎn)位的核密度* @param entryPoints 數(shù)據(jù)點(diǎn)信息* @param pixelPoints 創(chuàng)建的虛擬像素點(diǎn)* @param radius 影響半徑* @return*/public static KernelResult kernelCompute(List<EntryPoint> entryPoints, List<PixelPoint> pixelPoints, int width, int high, double radius){List<Double> values = new ArrayList<>();double affectLat = KernelUtils.getLatDist(radius);// 記錄受到影響的網(wǎng)格Double[][] matrix = new Double[high][width];// 建立線程池ThreadPoolExecutor threadPool = new ThreadPoolExecutor(30, 30, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(Integer.MAX_VALUE));// 線程等待計(jì)數(shù)器CountDownLatch countDownLatch = new CountDownLatch(pixelPoints.size());// 創(chuàng)建鎖, 使計(jì)算數(shù)據(jù)具有線程間可見性Lock lock = new ReentrantLock();int stepPosition = pixelPoints.size() / 75;for (int i = 0; i < pixelPoints.size(); i++){PixelPoint pixelPoint = pixelPoints.get(i);Double kennelLon = pixelPoint.getLon();Double kennelLat = pixelPoint.getLat();threadPool.execute(() -> {// 開始計(jì)算每個網(wǎng)格受到其他所有點(diǎn)所影響的核密度double kernel = 0.0;for (int j = 0; j < entryPoints.size(); j++){EntryPoint entryPoint = entryPoints.get(j);double lon = entryPoint.getLon();double lat = entryPoint.getLat();if (Math.abs(lon - kennelLon) > entryPoint.getAffectLon() || Math.abs(lat - kennelLat) > affectLat){continue;}// 獲取權(quán)重, 默認(rèn)為 1.0double weight = 1.0;if (entryPoint.getWeight() != null){weight = entryPoint.getWeight();}// 計(jì)算網(wǎng)格中心點(diǎn)與源數(shù)據(jù)點(diǎn)的距離double distance = KernelUtils.getDistance(lon, lat, kennelLon, kennelLat);// 影響半徑大于距離的點(diǎn)直接去掉if (distance <= radius){// 計(jì)算每個網(wǎng)格所受影響的核密度kernel += computeKernel(radius, distance, weight);}}lock.lock();// 為中心點(diǎn)實(shí)體類賦予核密度的值Double value = 1 / Math.pow(radius, 2) * kernel;matrix[pixelPoint.getI()][pixelPoint.getJ()] = value;values.add(value);lock.unlock();countDownLatch.countDown();if (countDownLatch.getCount() % stepPosition == 0 && progress < 80){Progress.progress(progress++);}});}// 等待所有任務(wù)執(zhí)行完畢try {countDownLatch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}// 關(guān)閉線程池threadPool.shutdown();return new KernelResult(matrix, Collections.max(values), Collections.min(values));}
5.可執(zhí)行 jar 包
該程序可打?yàn)榭蓤?zhí)行jar包, 文件夾中的: kernel.jar
運(yùn)行環(huán)境: jdk 1.8
執(zhí)行示例:
java -jar kernel.jar 杭州市超市營業(yè)額.csv 杭州市超市營業(yè)額熱力.jpg 經(jīng)度 緯度 利潤 2000.0 0.1 0
java -jar kernel.jar 杭州市超市營業(yè)額.csv 杭州市超市營業(yè)額分布.geojson 經(jīng)度 緯度 利潤 2000.0 0.1 0
java -jar kernel.jar 測試數(shù)據(jù).csv 測試數(shù)據(jù).jpg lon lat "" 300.0 0.1 0
java -jar kernel.jar 測試數(shù)據(jù).csv 測試數(shù)據(jù).geojson lon lat "" 300.0 0.1 0
參數(shù) | 參數(shù)位置 | 參數(shù)說明 |
---|---|---|
inputPath | 1 | 輸入的csv文件路徑 |
outPath | 2 | 輸出的文件路徑,程序根據(jù)文件后綴選擇生產(chǎn)的文件類型,只允許 jpg、png、geojson 三種文件。 |
lonKey | 3 | 輸入文件中的經(jīng)度字段名 |
latKey | 4 | 輸入文件中的緯度字段名 |
weightKey | 5 | 輸入文件中的權(quán)重字段名,沒有則輸入”” |
radius | 6 | 影響半徑,單位米,影響半徑越長,周圍空間受該數(shù)據(jù)的影響越廣,需根據(jù)不同的輸入數(shù)據(jù)情況調(diào)整 |
bufferSize | 7 | 空間緩沖區(qū),可擴(kuò)大數(shù)據(jù)空間范圍,一般0.1即可,即擴(kuò)大 10% 的區(qū)域 |
step | 8 | 空間劃分步長,步長越小則參與計(jì)算的空間點(diǎn)數(shù)據(jù)越多,計(jì)算量越大,結(jié)果數(shù)據(jù)越精確, 需根據(jù)不同的輸入數(shù)據(jù)情況調(diào)整,當(dāng)值為0時,程序則適配生成一百萬個點(diǎn)或網(wǎng)格參與計(jì)算,注:盡量不要在城市級別范圍設(shè)置過低步長 |
四.執(zhí)行結(jié)果展示
熱力圖示例:
平臺分析示例:
杭州市超市營業(yè)額區(qū)域性分析-熱力圖:
杭州市超市營業(yè)額區(qū)域性分析-平臺分析:
五、應(yīng)用場景
-
金融風(fēng)險評估:核密度算法可以用于評估某種投資方式的風(fēng)險程度。將歷史數(shù)據(jù)輸入核密度估計(jì)器中,可以得出該投資方式在不同風(fēng)險水平下的收益概率密度分布。這有助于金融機(jī)構(gòu)更好地了解風(fēng)險和收益之間的平衡。
-
生態(tài)學(xué):核密度算法可用于研究動植物的棲息地和遷徙模式。將動植物的觀察數(shù)據(jù)輸入核密度估計(jì)器中,可以得出它們在不同地點(diǎn)出現(xiàn)的概率密度分布,幫助科學(xué)家更好地了解動植物的棲息地范圍和活動規(guī)律。
-
交通流量預(yù)測:核密度算法可以用于預(yù)測道路上的交通流量。將歷史交通流量數(shù)據(jù)輸入核密度估計(jì)器中,可以得出在不同時間段內(nèi)和不同位置上的交通流量概率密度分布。這有助于交通管理人員更好地規(guī)劃道路、優(yōu)化路線和管理交通擁堵。
-
模式識別:核密度算法可以使用于人臉識別、圖像處理等領(lǐng)域。將輸入數(shù)據(jù)的特征值輸入核密度估計(jì)器中,可以得出不同特征值下相應(yīng)數(shù)據(jù)的概率密度分布。這可用于識別圖像中不同物體的特征值,例如人臉的輪廓和眼睛的位置,從而實(shí)現(xiàn)自動化識別。