核密度分析

一.算法介绍

核密度估计(Kernel Density Estimation)是一种用于估计数据分布的非参数统计方法。它可以用于多种目的和应用,包括:

  • 数据可视化:核密度估计可以用来绘制平滑的密度曲线或热力图,从而直观地表示数据的分布情况。它可以帮助我们观察数据集中的高密度区域、低密度区域以及变化趋势。
  • 异常检测:通过核密度估计,我们可以识别数据中的异常点或离群值。异常点通常表现为低密度区域或与其他数据点明显不同的区域。
  • 概率密度计算:核密度估计可以用于计算给定数值的概率密度。通过将新数据点带入核密度估计函数,可以估计出该点在数据分布中的密度。
  • 模式识别:核密度估计可以用于识别数据中的模式或聚类。通过观察密度最高的区域,可以推断数据的聚类情况或潜在的模式。
  • 预测建模:核密度估计可以用于构建概率模型,进而进行预测。例如,在分类问题中,可以使用核密度估计来估计每个类别的概率密度,然后根据新的数据点所属的密度来进行分类预测。

根据具体的应用需求,我们可以灵活地使用核密度估计来分析和理解数据集的特征和结构,可能的用途包括针对社区规划分析房屋密度或犯罪行为,或探索道路或公共设施管线如何影响野生动物栖息地。
每个点位可以设置 weight 字段赋予某些要素比其他要素更大的权重,该字段还允许使用一个点表示多个观察对象。例如,一个地址可以表示一栋六单元的公寓,或者在确定总体犯罪率时可赋予某些罪行比其他罪行更大的权重。

二.算法计算原理

本算法以四次核函数为基础,四次核函数的特点是具有平滑的曲线形状,具有较宽的窗口,对数据点的贡献在距离较远时会迅速减小。由于其平滑性和较大的支持范围,四次核函数在核密度估计中被广泛使用。

在这里插入图片描述

在核密度估计中,通过将核函数应用于每个数据点,并对所有数据点的贡献进行求和,可以计算出在每个位置上的密度估计值。四次核函数的结果可视为在核密度估计中每个位置的密度贡献权重。较大的结果表示该位置的密度较高,而较小或接近零的结果表示该位置的密度较低。
本算法中主要利用核密度公式计算空间范围内的核密度值,根据核密度值生成 png 或 jpg 格式的热力图,或者将整个空间切割成网格,用网格中心点参与核密度计算生成 geojson 文件,以供进一步空间探索分析。

    /**
     *  计算单个核密度
     * @param radius 半径
     * @param dist 两点的距离
     * @param weight 权重
     * @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);
    }

创新性说明:

  • 1.算法会自适应数据中的空间点位范围,此范围可根据参数bufferSize 设置缓冲区扩展,以获取数据范围外的点参与计算。
  • 2.根据空间范围每隔特定步长创建虚拟点位或划分网格,灵活性较高,步长越小则结果在地图分布上的精度越高,步长参数step(米) 可选,如果没有设置, 则默认在空间范围内自适应创建一百万左右虚拟点或网格。
  • 3.采用多线程的方式进行核密度计算,速度更快。
  • 4.可将结果值进行归一化处理,核密度计算出来的结果值主要用于观察数据分布,但是各个结果值之间相差范围较大,不易观察数据分布,归一化后能更清晰观察不同区域间的分布情况。
  • 5.可根据核密度值的大小根据不同需求生成热力图或 geojson 文件。可在geojson文件上做进一步探索。

三.算法程序

1. 核心流程代码

从csv中获取源数据点信息, 获取坐标范围,如果需要缓冲区, 则设置缓冲区, 获取步长长度(默认一百万个像素点或网格),然后根据核密度信息创建图片或geojson

        // 输入文件路径
        String inputPath ="D:\\测试数据.csv";
        // 输出文件路径
        String outPath ="D:\\测试数据.geojson";
        // String outPath ="D:\\测试数据.jpg";
        // 经度字段
        String lonKey = "lon";
        // 纬度字段
        String latKey = "lat";
        // 权重字段
        String weightKey = "";
        // 影响半径
        double radius = 300.0;
        // 缓冲区
        double bufferSize = 0.1;
        // 生成的网格长度(单位: 米)
        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中获取源数据点信息
        List<EntryPoint> entryPoints = EntryPoint.formatToEntryPoints(inputPath, lonKey, latKey, weightKey, radius);
        
        // 获取坐标范围
        double[] coordsScope = KernelUtils.getCoordsScope(entryPoints);
        
        // 如果需要缓冲区, 则设置缓冲区
        if (bufferSize != 0){
            coordsScope = KernelUtils.getBufferScope(coordsScope[0], coordsScope[1], coordsScope[2], coordsScope[3], bufferSize);
        }

        // 获取默认的步长长度, 默认一百万个像素点或网格
        if (step ==0){
            step = KernelUtils.getDefaultSize(coordsScope);
        }
        
        // 根据核密度信息创建图片或geojson
        kernel(coordsScope, entryPoints, step, radius, type, outPath);
    /**
     * 核密度方法
     * @param coordsScope 坐标范围
     * @param entryPoints  从csv中获取源数据点信息
     * @param step 步长长度
     * @param radius 影响半径
     * @param type 输出文件类型
     */
    public static void kernel(double[] coordsScope, List<EntryPoint> entryPoints, int step, double radius, int type, String path){
        // 获取网格坐标系的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){
            // 生产 geojson 网格结果
            generatorGridGeojson(coords, entryPoints, width-1, high-1, radius, path, step);
        }else {
            // 生产热力图图片
            generatorThermalMap(coords, entryPoints, width, high, radius, path, step);
        }
    }

2.创建面的 geojson 文件

    /**
     *  根据核密度信息创建面的 geojson 文件
     * @param coords 虚拟数据点经纬度列表
     * @param entryPoints 数据点
     * @param width 横向点位数量
     * @param high 纵向点位数量
     * @param radius 影响半径
     */
    public static void generatorGridGeojson(List<Double[]> coords, List<EntryPoint> entryPoints,
                                            int width, int high, double radius, String path, int step){
        // 获取所有中心点位的数据
        List<PixelPoint> pixelPoints = KernelUtils.getGridCenters(coords);

        // 进行核密度计算, 并记录受到影响的网格信息
        KernelResult kernelResult = kernelCompute(entryPoints, pixelPoints, width, high, radius);
        Double[][] matrix = kernelResult.getMatrix();
        Double max = kernelResult.getMax();
        Double min = kernelResult.getMin();

        // 生产面的 geojson 文件
        writeToFile(KernelUtils.jointGridGeojson(matrix, max, min, coords), path);
        System.out.println(String.format("计算完成, 生成 geojson 文件, 参与计算网格  %d 个, 受影响网格 %d 个, 相邻网格间距 %s 米",
                pixelPoints.size(), KernelUtils.effectiveGrid, step));
    }

3.热力图图片

    /**
     * 根据核密度信息创建热力图图片
     * @param coords 虚拟数据点经纬度列表
     * @param entryPoints 数据点
     * @param width 横向点位数量
     * @param high 纵向点位数量
     * @param radius 影响半径
     */
    public static void generatorThermalMap(List<Double[]> coords, List<EntryPoint> entryPoints,
                                           int width, int high, double radius, String path, int step){
        // 获得所有点位
        List<PixelPoint> pixelPoints = KernelUtils.spliceKennelPoints(coords);

        // 进行核密度计算, 并记录受到影响的网格信息
        KernelResult kernelResult = kernelCompute(entryPoints, pixelPoints, width, high, radius);
        Double[][] matrix = kernelResult.getMatrix();
        Double max = kernelResult.getMax();
        Double min = kernelResult.getMin();

        // 生产热力图
        ImageGenerator.generatorImage(matrix, max, min, path);
        System.out.println(String.format("计算完成, 生成图片 像素: %d x  %d, 相邻像素点实际代表距离 %s 米", width, high, step));
    }

4.计算所有点位的核密度

    /**
     * 计算所有点位的核密度
     * @param entryPoints 数据点信息
     * @param pixelPoints 创建的虚拟像素点
     * @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);

        // 记录受到影响的网格
        Double[][] matrix = new Double[high][width];
        // 建立线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                30, 30, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(Integer.MAX_VALUE));
        // 线程等待计数器
        CountDownLatch countDownLatch = new CountDownLatch(pixelPoints.size());
        // 创建锁, 使计算数据具有线程间可见性
        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(() -> {
                        // 开始计算每个网格受到其他所有点所影响的核密度
                        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;
                            }

                            // 获取权重, 默认为 1.0
                            double weight = 1.0;
                            if (entryPoint.getWeight() != null){
                                weight = entryPoint.getWeight();
                            }
                            // 计算网格中心点与源数据点的距离
                            double distance = KernelUtils.getDistance(lon, lat, kennelLon, kennelLat);

                            // 影响半径大于距离的点直接去掉
                            if (distance <= radius){
                                // 计算每个网格所受影响的核密度
                                kernel += computeKernel(radius, distance, weight);
                            }
                        }

                        lock.lock();
                        // 为中心点实体类赋予核密度的值
                        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++);
                        }
                    }
            );
        }

        // 等待所有任务执行完毕
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 关闭线程池
        threadPool.shutdown();
        return  new KernelResult(matrix, Collections.max(values), Collections.min(values));
    }

5.可执行 jar 包

该程序可打为可执行jar包, 文件夹中的: kernel.jar
运行环境: jdk 1.8

执行示例:

java -jar kernel.jar 杭州市超市营业额.csv 杭州市超市营业额热力.jpg 经度 纬度 利润 2000.0 0.1 0
java -jar kernel.jar 杭州市超市营业额.csv 杭州市超市营业额分布.geojson 经度 纬度 利润 2000.0 0.1 0
java -jar kernel.jar 测试数据.csv 测试数据.jpg lon lat "" 300.0 0.1 0
java -jar kernel.jar 测试数据.csv 测试数据.geojson lon lat "" 300.0 0.1 0
参数参数位置参数说明
inputPath1输入的csv文件路径
outPath2输出的文件路径,程序根据文件后缀选择生产的文件类型,只允许 jpg、png、geojson 三种文件。
lonKey3输入文件中的经度字段名
latKey4输入文件中的纬度字段名
weightKey5输入文件中的权重字段名,没有则输入””
radius6影响半径,单位米,影响半径越长,周围空间受该数据的影响越广,需根据不同的输入数据情况调整
bufferSize7空间缓冲区,可扩大数据空间范围,一般0.1即可,即扩大 10% 的区域
step8空间划分步长,步长越小则参与计算的空间点数据越多,计算量越大,结果数据越精确, 需根据不同的输入数据情况调整,当值为0时,程序则适配生成一百万个点或网格参与计算,注:尽量不要在城市级别范围设置过低步长

四.执行结果展示

热力图示例:
在这里插入图片描述

平台分析示例:

在这里插入图片描述

杭州市超市营业额区域性分析-热力图:

在这里插入图片描述

杭州市超市营业额区域性分析-平台分析:
在这里插入图片描述

五、应用场景

  1. 金融风险评估:核密度算法可以用于评估某种投资方式的风险程度。将历史数据输入核密度估计器中,可以得出该投资方式在不同风险水平下的收益概率密度分布。这有助于金融机构更好地了解风险和收益之间的平衡。

  2. 生态学:核密度算法可用于研究动植物的栖息地和迁徙模式。将动植物的观察数据输入核密度估计器中,可以得出它们在不同地点出现的概率密度分布,帮助科学家更好地了解动植物的栖息地范围和活动规律。

  3. 交通流量预测:核密度算法可以用于预测道路上的交通流量。将历史交通流量数据输入核密度估计器中,可以得出在不同时间段内和不同位置上的交通流量概率密度分布。这有助于交通管理人员更好地规划道路、优化路线和管理交通拥堵。

  4. 模式识别:核密度算法可以使用于人脸识别、图像处理等领域。将输入数据的特征值输入核密度估计器中,可以得出不同特征值下相应数据的概率密度分布。这可用于识别图像中不同物体的特征值,例如人脸的轮廓和眼睛的位置,从而实现自动化识别。

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

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

相关文章

[HTML]Web前端开发技术27(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

C++力扣题目 647--回文子串 516--最长回文子序列

647. 回文子串 力扣题目链接(opens new window) 给定一个字符串&#xff0c;你的任务是计算这个字符串中有多少个回文子串。 具有不同开始位置或结束位置的子串&#xff0c;即使是由相同的字符组成&#xff0c;也会被视作不同的子串。 示例 1&#xff1a; 输入&#xff1a…

Velocity

引入 <dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version> </dependency> 加载 Test public void velo01() throws IOException {// 设置velocity资…

Flutter插件开发指南01: 通道Channel的编写与实现

Flutter插件开发指南01: 通道Channel的编写与实现 视频 https://www.bilibili.com/video/BV1ih4y1E7E3/ 前言 本文将会通过一个加法计算&#xff0c;来实现 Channel 的双向通讯&#xff0c;让大家有个一个体会。 Flutter插件 Flutter插件是Flutter应用程序与原生平台之间的桥…

测试环境搭建整套大数据系统(六:搭建sqoop)

一&#xff1a;下载安装包 https://archive.apache.org/dist/sqoop/ 二&#xff1a;解压修改配置。 tar -zxvf sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C /opt cd /opt mv sqoop-1.4.7.bin__hadoop-2.6.0/ sqoop-1.4.7修改环境变量 vi /etc/profile#SQOOP_HOME export SQOOP_…

远程连接 vscode 出错 “远程主机可能不符合 glibc 和 libstdc++ VS Code 服务器的先决条件”

原因&#xff1a; vscode 版本是 1.86&#xff0c;服务器上的 glibc 和 libstdc 版本不满足 要求(2.28 和 3.4.25)。 解决&#xff1a; 1、下载 1.85.2&#xff0c;解压直接运行 Code.exe。 2、回退 Remote-ssh 到 0.107.1。 参考&#xff1a; vscode 1.86版本远程ssh不兼容旧…

关于运行flutter app 运行到模拟器出现异常提示

Exception: Gradle task assembleDebug failed with exit code 1 解决方案&#xff1a; 1.讲当前文件的distributionUrl值改为 https://mirrors.cloud.tencent.com/gradle/gradle-7.4-all.zip

【论文解读】Uncertainty Quantification of Collaborative Detection for Self-Driving

Uncertainty Quantification of Collaborative Detection for Self-Driving 摘要引言方法问题定义方法概览Double-M 实验结论 摘要 在联网和自动驾驶汽车(CAVs)之间共享信息从根本上提高了自动驾驶协同目标检测的性能。然而&#xff0c;由于实际挑战&#xff0c;CAV 在目标检测…

$attrs

一、概念 vue官网定义如下: 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过v-bind="$attrs"传入内部组件——在创建…

C语言翻译环境:预编译+编译+汇编+链接详解

目录 翻译环境和运行环境 翻译环境 预处理&#xff08;预编译&#xff09; 编译 词法分析 语法分析 语义分析 汇编 链接 运行环境 ⭐翻译环境和运行环境 在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被…

Java并发基础:原子类之AtomicIntegerFieldUpdater全面解析

本文概要 AtomicIntegerFieldUpdater类提供了一种高效、简洁的方式来原子性地更新对象的volatile字段&#xff0c;无需使用重量级的锁机制&#xff0c;它通过基于反射的API实现了细粒度的并发控制&#xff0c;提升了多线程环境下的性能表现。 AtomicIntegerFieldUpdater核心概…

选择VR全景行业,需要了解哪些内容?

近年来&#xff0c;随着虚拟现实、增强现实等技术的持续发展&#xff0c;VR全景消费市场得以稳步扩张。其次&#xff0c;元宇宙行业的高速发展&#xff0c;也在进一步拉动VR全景技术的持续进步&#xff0c;带动VR产业的高质量发展。作为一种战略性的新兴产业&#xff0c;国家和…

【vue vue-seamless-scroll】解决vue-seamless-scroll鼠标悬浮才滚动或者只滚动一次就失效的问题

解决问题&#xff1a;使用vue-seamless-scroll发现只有鼠标悬浮上去才滚动&#xff0c;而且滚动一次停止了 目标效果&#xff1a; 解决方案&#xff1a; 最后发现是因为数据需要在页面挂载好就赋值&#xff0c;否则页面在加载完成后&#xff0c;数据无法自动滚动。但因为数据…

防火墙内容安全笔记

目录 DFI和DPI IDS和IPS 签名 AV URL过滤 HTTPS过滤 内容过滤 文件类型过滤 文件内容过滤 邮件过滤 VPN概述 DFI和DPI DFI和DPI技术 --- 深度检测技术 DPI DPI --- 深度包检测技术 --- 主要针对完整的数据包&#xff08;数据包分片&#xff0c;分段需要重组&#…

百亿美金的设计,深度剖析 GitLab 的 Postgres 数据库 schema

原文链接 这篇文章写于 2022 年&#xff0c;前一年 GitLab 刚好完成 IPO。目前 GitLab 市值超过 100 亿美金&#xff0c;它的所有收入都来源于同名产品 GitLab&#xff0c;而这篇文章就是全面分析 GitLab 这个产品的数据库 schema。 我花了一些时间研究 GitLab 的 Postgres sch…

【ArcGIS Pro二次开发】(82):玩个花活_控规指标块生成

一、要实现的效果 废话不多说&#xff0c;这次要实现的是类似控规指标块的标注&#xff1a; 这里只是示例&#xff0c;用了5个格子&#xff0c;做成9个格子也是可以的。 实现这个效果最关键的是要用到Pro中的复合标注。 关于复合标注的用法可以搜一下帮助里的【使用复合注释…

网站常见的攻击类型有什么,如何针对性防护

在互联网时代&#xff0c;几乎每个网站都存在着潜在的安全威胁。这些威胁可能来自人为失误&#xff0c;也可能源自网络犯罪团伙所发起的复杂攻击。无论攻击的本质如何&#xff0c;网络攻击者的主要动机通常是谋求经济利益。这意味着不管是什么网站类型潜在的威胁一直都存在。 在…

关于2025年的AMC8竞赛,你可能感兴趣的一些问题和信息

最近几天&#xff0c;我分享了一些历年的AMC8数学竞赛真题和解析&#xff0c;有一些家长和孩子第一次接触&#xff0c;产生了浓厚的兴趣&#xff0c;并且问了许多关于AMC8的问题。为了帮助更多家长和孩子了解这个比赛&#xff0c;我把常见的问题&#xff0c;以及大家可能感兴趣…

[java基础揉碎]封装

封装介绍 封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部&#xff0c;程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。 比如说我们用遥控器对电视的操作, 我们按电视机的开关键, 其实开关背后是一个复杂的过程,…

Codeforces Round 927 (Div. 3)

F. Feed Cats 题目大意 给一长度为的数轴&#xff0c;个区间在数轴上选取一些点作为特殊点在满足个区间中&#xff0c;每个区间内只能有一个特殊点问最多能选多少个特殊点 解题思路 对于每个点有放或不放两种状态考虑表示位置可能放或不放的最优结果若不放&#xff0c;若放…