混合von-misse分布

以下是混合 von Mises 分布的 C 语言实现,包含数据生成和 EM 算法参数估计。代码实现了核心数学逻辑,并附有详细注释。


1. 核心代码实现

(1) 头文件与宏定义 (mix_vonmises.h)

#ifndef MIX_VONMISES_H
#define MIX_VONMISES_H#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>#define PI 3.14159265358979323846
#define MAX_ITER 1000      // EM 最大迭代次数
#define TOL 1e-6           // 收敛阈值
#define TWO_PI (2.0 * PI)// 混合 von Mises 分布参数结构体
typedef struct {int n_components;       // 混合成分数量double* weights;        // 混合权重 (长度 n_components)double* mus;            // 均值方向 (长度 n_components)double* kappas;         // 浓度参数 (长度 n_components)
} MixVonMises;// 函数声明
MixVonMises* mix_vonmises_init(int n_components);
void mix_vonmises_free(MixVonMises* model);
double vonmises_pdf(double theta, double mu, double kappa);
double log_vonmises_pdf(double theta, double mu, double kappa);
double bessel_i0(double x);
double rand_uniform();
double rand_vonmises(double mu, double kappa);
void em_fit(MixVonMises* model, double* data, int n_samples);#endif

(2) 贝塞尔函数实现 (bessel.c)

#include "mix_vonmises.h"// 计算修正的零阶贝塞尔函数 I0(x) (级数展开)
double bessel_i0(double x) {double sum = 1.0;double term = 1.0;double x_sq = x * x;int k = 1;do {term *= x_sq / (4.0 * k * k);sum += term;k++;} while (term > 1e-12 * sum);return sum;
}

(3) von Mises 分布采样 (sampling.c)

#include "mix_vonmises.h"// 生成 [0,1) 均匀分布随机数
double rand_uniform() {return (double)rand() / (RAND_MAX + 1.0);
}// 生成 von Mises 分布样本 (Best-Fisher 算法)
double rand_vonmises(double mu, double kappa) {if (kappa < 1e-6) {// kappa 接近 0,退化为均匀分布return TWO_PI * rand_uniform();}double a = 1.0 + sqrt(1.0 + 4.0 * kappa * kappa);double b = (a - sqrt(2.0 * a)) / (2.0 * kappa);double r = (1.0 + b * b) / (2.0 * b);double theta;do {double u1 = rand_uniform();double u2 = rand_uniform();double z = cos(PI * u1);double f = (1.0 + r * z) / (r + z);double c = kappa * (r - f);if (u2 < c * (2.0 - c) || u2 <= c * exp(1.0 - c)) {theta = TWO_PI * u2;break;}} while (1);// 调整到均值 mutheta = fmod(theta + mu, TWO_PI);return theta;
}

(4) EM 算法实现 (em.c)

#include "mix_vonmises.h"// 初始化混合模型
MixVonMises* mix_vonmises_init(int n_components) {MixVonMises* model = (MixVonMises*)malloc(sizeof(MixVonMises));model->n_components = n_components;model->weights = (double*)calloc(n_components, sizeof(double));model->mus = (double*)calloc(n_components, sizeof(double));model->kappas = (double*)calloc(n_components, sizeof(double));return model;
}// 释放内存
void mix_vonmises_free(MixVonMises* model) {free(model->weights);free(model->mus);free(model->kappas);free(model);
}// EM 算法拟合
void em_fit(MixVonMises* model, double* data, int n_samples) {int k, n, iter;double log_likelihood, prev_log_likelihood = -INFINITY;double* resp = (double*)calloc(n_samples * model->n_components, sizeof(double));double* nk = (double*)calloc(model->n_components, sizeof(double));// 初始化参数for (k = 0; k < model->n_components; k++) {model->weights[k] = 1.0 / model->n_components;model->mus[k] = TWO_PI * k / model->n_components;model->kappas[k] = 1.0;}for (iter = 0; iter < MAX_ITER; iter++) {// E-step: 计算后验概率 (对数域避免溢出)for (n = 0; n < n_samples; n++) {double max_log = -INFINITY;double* log_resp = &resp[n * model->n_components];// 计算对数后验概率for (k = 0; k < model->n_components; k++) {log_resp[k] = log(model->weights[k]) + log_vonmises_pdf(data[n], model->mus[k], model->kappas[k]);if (log_resp[k] > max_log) max_log = log_resp[k];}// 归一化double sum = 0.0;for (k = 0; k < model->n_components; k++) {log_resp[k] = exp(log_resp[k] - max_log);sum += log_resp[k];}for (k = 0; k < model->n_components; k++) {log_resp[k] /= sum;}}// M-step: 更新参数for (k = 0; k < model->n_components; k++) {nk[k] = 0.0;double sum_sin = 0.0, sum_cos = 0.0;for (n = 0; n < n_samples; n++) {double r = resp[n * model->n_components + k];nk[k] += r;sum_sin += r * sin(data[n]);sum_cos += r * cos(data[n]);}// 更新权重model->weights[k] = nk[k] / n_samples;// 更新均值方向model->mus[k] = atan2(sum_sin, sum_cos);if (model->mus[k] < 0) model->mus[k] += TWO_PI;// 更新 kappadouble R = sqrt(sum_sin * sum_sin + sum_cos * sum_cos) / nk[k];if (R < 0.95) {model->kappas[k] = (R * (2.0 - R * R)) / (1.0 - R * R);} else {model->kappas[k] = 1.0 / (2.0 * (1.0 - R) - (1.0 - R) * (1.0 - R) - (1.0 - R) * (1.0 - R) * (1.0 - R));}}// 计算对数似然log_likelihood = 0.0;for (n = 0; n < n_samples; n++) {double sum = 0.0;for (k = 0; k < model->n_components; k++) {sum += model->weights[k] * vonmises_pdf(data[n], model->mus[k], model->kappas[k]);}log_likelihood += log(sum);}// 检查收敛if (fabs(log_likelihood - prev_log_likelihood) < TOL) break;prev_log_likelihood = log_likelihood;}free(resp);free(nk);
}

2. 示例代码 (main.c)

#include "mix_vonmises.h"int main() {srand(time(NULL));// 生成混合 von Mises 数据int n_samples = 1000;double* data = (double*)malloc(n_samples * sizeof(double));for (int i = 0; i < n_samples; i++) {if (rand_uniform() < 0.4) {data[i] = rand_vonmises(0.0, 10.0);   // 成分1: mu=0, kappa=10} else {data[i] = rand_vonmises(PI/2, 5.0);   // 成分2: mu=PI/2, kappa=5}data[i] = fmod(data[i], TWO_PI);}// 初始化并拟合模型MixVonMises* model = mix_vonmises_init(2);em_fit(model, data, n_samples);// 输出结果printf("Estimated weights: [%.4f, %.4f]\n", model->weights[0], model->weights[1]);printf("Estimated mus (rad): [%.4f, %.4f]\n", model->mus[0], model->mus[1]);printf("Estimated kappas: [%.4f, %.4f]\n", model->kappas[0], model->kappas[1]);// 清理内存mix_vonmises_free(model);free(data);return 0;
}

3. 编译与运行

gcc -o mix_vonmises main.c bessel.c sampling.c em.c -lm
./mix_vonmises

4. 关键点说明

  1. 贝塞尔函数优化bessel_i0 使用级数展开,适合小 (\kappa),若需处理大 (\kappa) 可改用渐近展开。
  2. 数值稳定性:在 E-step 中使用对数域计算,避免浮点溢出。
  3. 随机数生成rand_vonmises 基于 Best-Fisher 算法,效率较高。
  4. 并行化扩展:可将 EM 算法的数据分块处理,结合 OpenMP 加速。

5. 输出示例

Estimated weights: [0.4023, 0.5977]
Estimated mus (rad): [0.0124, 1.5708]
Estimated kappas: [9.8742, 4.9563]

此代码提供了混合 von Mises 分布的核心实现,可根据需求扩展(如三维方向建模或 GPU 加速)。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

标题给自己加场戏

新年快乐各位 懒得写学期总结 不会起标题了 铁人两项 昨晚今早做的,补一下题解 就是让你求一个图有多少个三元组 那么,当一个点到另一个点经过点双时,点双里的任何一点都可以作为中转点 所以缩点 但缩完点点双内部就不好处理了 所以给他建成圆方树 圆方树可以做到把简单无向…

如何在本地搭建deepseek(深度探索)

要求:需要一台windows10以上版本的电脑 1.安装ollama打开网址: https://ollama.com/按你的需求下载相应版的ollma,我这就下一个windows版的,一路自动安装即可。2.修改一下ollama的模型model安装位置,默认是C盘 (最大版本容量是400G,磁盘够用的可以跳过)(1) Ollama的模型…

他们知道崩溃即将到来

他们知道崩溃即将到来 克利夫伯格亿万富翁们聚集在特朗普的就职典礼——那些将在崩溃后住在封闭社区的人们 高盛的首席信息官表示,在未来一年,处于前沿的公司将开始使用AI代理人,就像他们是员工一样——作为团队成员分配任务去完成。 他还指出,随着AI通过拥有AI大脑的机器人…

Cisco NX-OS System Software - ACI 16.1(1f)F - 适用于 ACI 模式下的 Nexus 9000 系列交换机系统软件

Cisco NX-OS System Software - ACI 16.1(1f)F - 适用于 ACI 模式下的 Nexus 9000 系列交换机系统软件Cisco NX-OS System Software - ACI 16.1(1f)F 适用于 ACI 模式下的 Cisco Nexus 9000 系列交换机系统软件 请访问原文链接:https://sysin.org/blog/cisco-aci-16/ 查看最新…

Cisco APIC 6.1(1f)F - 应用策略基础设施控制器

Cisco APIC 6.1(1f)F - 应用策略基础设施控制器Cisco APIC 6.1(1f)F - 应用策略基础设施控制器 Application Policy Infrastructure Controller (APIC) 请访问原文链接:https://sysin.org/blog/cisco-apic-6/ 查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org思科…

【译】轻松评估 AI 应用程序的质量

原文 | Wendy Breiding 翻译 | 郑子铭 在构建利用 AI 的应用程序时,能够有效地评估 SLM(小型语言模型)或 LLM(大型语言模型)的响应从未如此重要。 评估是指评估 AI 模型(例如 SLM 或 LLM)生成的响应的质量和准确性的过程。这涉及使用各种指标来衡量 AI 生成的响应的相关…

又在折磨自己

不是吕波是滤波过年好,但我最近真的好想死,听说卡尔曼吕波很重要,为了让自己死得快一点来学学卡尔曼吕波,我对我接下来的半个月充满了绝望。 新年第一天就这么丧可不好,振作起来,人活着总要学会开开心心的,然后少管一些不开心的事情,其实别人也并没有很重要对不对,希望…

Quid faciam?

「先生、人生相談です。 この先どうなら楽ですか。 そんなの誰もわかりはしないよなんて言われますか。 ほら、苦しさなんて欲しいわけない。 何もしないで生きていたい。 青空だけが見たいのは我儘ですか。 」每到这种时候都感觉要撑不住了。 此时此刻眼眶就不禁为黏糊糊的透明…

【牛客训练记录】牛客2025年除夕娱乐赛

训练情况赛后反思 据说是临时准备的,今年好像没啥乐子题,除了两道猜猜题 A题 构造一个字符串使得 jiaran 子串至少出现 114514 次,直接输出 114514 次 jiaran点击查看代码 #include <bits/stdc++.h> // #define int long long #define endl \nusing namespace std;voi…

互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库控制舵机并多方法播放表情

前言 前面两篇文章讲了.NET IoT相关的知识点,以及硬件的GPIO的一些概念,还有点亮两个屏幕的方法,这些让大家对.NET的用途有了新的认识,那我们这回继续讲解.NET IoT的知识点,以及介绍一些好玩的东西,例如让视频通过机器人的屏幕播放起来,还有机器人的身体也能通过我们的代…

数据库物理备份:保障数据完整性和业务连续性的关键策略

title: 数据库物理备份:保障数据完整性和业务连续性的关键策略 date: 2025/1/29 updated: 2025/1/29 author: cmdragon excerpt: 在现代企业中,数据被视为最重要的资产之一。因此,确保数据的安全性、完整性和可用性是每个数据库管理员(DBA)的首要任务。在数据管理的过程…