基于距离的离群点检测算法C++实现

参考博客:参考

算法简介: 该算法比较简单,需要人为设置两个阈值,一个是距离阈值distance,一个是分数阈值score。算法伪代码如下:

âDistance-based outlier detectionâçå¾çæç´¢ç»æ

 

C++实现(支持多维数据,会对数据进行归一化操作,归一化参考):

#include <iostream>
#include <vector>
#include <cmath>

// support multidimensional data
std::vector<double> OutlierDetect(double* src, int src_rows, int src_cols) {
  // save data to vector
  std::vector<double> vec_src;
  for(int i = 0; i < src_rows; ++i) {
    int shift = i * src_cols;
    for(int j = 0; j < src_cols; ++j) {
      vec_src.push_back(src[shift + j]);
    }
  }

  // get the max and the min in each col
  std::vector<double> vec_max(src_cols, -1000);
  std::vector<double> vec_min(src_cols, 1000);
  for(int i = 0; i < src_cols; ++i) {
    for(int j = 0; j < src_rows; ++j) {
      int shift = j * src_cols;
      if(vec_src[shift + i] > vec_max[i]) {
        vec_max[i] = vec_src[shift + i];
      }
      if(vec_src[shift + i] < vec_min[i]) {
        vec_min[i] = vec_src[shift + i];
      } // end if
    } // end for loop
  } // end for loop

  // normalized: min-max
  for(int i = 0; i < src_cols; ++i) {
    for(int j = 0; j < src_rows; ++j) {
      int shift = j * src_cols;
      vec_src[shift + i] =
        (vec_src[shift + i] - vec_min[i]) / (vec_max[i] - vec_min[i]);
    } // end if
  } // end for loop

/**********************distance-based outlier detection********************/
  double distance = 0.01;
  double score = 0.5;              // 0 < score < 1
  std::vector<double> outliers;
  std::vector<int> outliers_index;
  std::vector<double> inliers;
  std::vector<int> inliers_index;

  int count_temp;
  int shift_i;
  int shift_j;
  for(int i = 0; i < src_rows; ++i) {
    count_temp = 0;
    for(int j = 0; j < src_rows; ++j) {
      if(i == j) {
        continue;
      }
      shift_i = i * src_cols;
      shift_j = j * src_cols;
      double dist = 0;
      for(int k = 0; k < src_cols; ++k) {
        double dist_temp = vec_src[shift_i + k] - vec_src[shift_j + k];
        dist += pow(dist_temp, 2);                      // Euclidean distance
      }
      if(sqrt(dist) < distance) {
        count_temp++;
      }
    }

    // save outliers and its index
    if(count_temp < score * src_rows) {
      outliers_index.push_back(i);
      for(int l = 0; l < src_cols; ++l) {
        outliers.push_back(vec_src[shift_i + l]);
      }
    }
    else {
      inliers_index.push_back(i);
      for(int l = 0; l < src_cols; ++l) {
        inliers.push_back(vec_src[shift_i + l]);
      }
    }
  } // end for loop
/**********************distance-based outlier detection********************/

  return inliers;
//  return outliers;
}

代码未经验证,仅供参考。

聚类是一种常用的数据分析方法,可以帮助我们发现数据中的一些模式和规律。基于聚类的离群点检测是一种常见的离群点检测方法,它基于聚类的结果来判断哪些数据点可能是离群点。下面简单介绍一下如何在C++实现基于聚类的离群点检测。 一般来说,基于聚类的离群点检测可以分为两个步骤:聚类和离群点检测。聚类可以使用常见的聚类算法,比如K-means、层次聚类等。离群点检测可以使用一些统计方法,比如Z-score、箱线图等。下面以K-means为例,简单介绍一下如何实现基于聚类的离群点检测。 首先需要使用一个K-means算法对数据进行聚类,得到每个数据点所属的簇。然后对于每个簇,可以计算出该簇中所有数据点的平均值和标准差,然后对于每个数据点,计算它与所属簇的平均值的距离(例如欧氏距离),并将该距离除以该簇的标准差得到一个Z-score值。如果该Z-score值大于某个阈值,就可以认为该数据点是一个离群点。 下面是一个简单的基于聚类的离群点检测C++代码示例: ```cpp #include <iostream> #include <vector> #include <cmath> #include <algorithm> #include <numeric> using namespace std; // 欧氏距离 double euclidean_distance(const vector<double>& a, const vector<double>& b) { double dist = 0.0; for (size_t i = 0; i < a.size(); ++i) { double diff = a[i] - b[i]; dist += diff * diff; } return sqrt(dist); } // K-means聚类 vector<int> kmeans(const vector<vector<double>>& data, int k) { // 初始化聚类中心 vector<vector<double>> centers(k); for (int i = 0; i < k; ++i) { centers[i] = data[i]; } // 迭代聚类 vector<int> labels(data.size()); while (true) { // 分配数据点到最近的聚类中心 bool updated = false; for (size_t i = 0; i < data.size(); ++i) { double min_dist = numeric_limits<double>::max(); int label = 0; for (int j = 0; j < k; ++j) { double dist = euclidean_distance(data[i], centers[j]); if (dist < min_dist) { min_dist = dist; label = j; } } if (labels[i] != label) { labels[i] = label; updated = true; } } if (!updated) { break; } // 更新聚类中心 for (int j = 0; j < k; ++j) { vector<double> new_center(data[0].size(), 0.0); int count = 0; for (size_t i = 0; i < data.size(); ++i) { if (labels[i] == j) { new_center = new_center + data[i]; ++count; } } if (count > 0) { new_center = new_center / count; } centers[j] = new_center; } } return labels; } // 基于聚类的离群点检测 vector<bool> outlier_detection(const vector<vector<double>>& data, int k, double threshold) { // 聚类 vector<int> labels = kmeans(data, k); // 计算每个簇的平均值和标准差 vector<vector<double>> centers(k); vector<vector<double>> stds(k); for (int j = 0; j < k; ++j) { vector<double> center(data[0].size(), 0.0); int count = 0; for (size_t i = 0; i < data.size(); ++i) { if (labels[i] == j) { center = center + data[i]; ++count; } } if (count > 0) { center = center / count; } centers[j] = center; vector<double> std(data[0].size(), 0.0); for (size_t i = 0; i < data.size(); ++i) { if (labels[i] == j) { for (size_t d = 0; d < data[i].size(); ++d) { std[d] += pow(data[i][d] - center[d], 2.0); } } } if (count > 1) { for (size_t d = 0; d < std.size(); ++d) { std[d] = sqrt(std[d] / (count - 1)); } } stds[j] = std; } // 判断每个数据点是否为离群点 vector<bool> outliers(data.size(), false); for (size_t i = 0; i < data.size(); ++i) { int label = labels[i]; double dist = euclidean_distance(data[i], centers[label]); double std = stds[label][0]; // 假设所有维度的标准差相等 double z_score = (dist - centers[label][0]) / std; if (z_score > threshold) { outliers[i] = true; } } return outliers; } int main() { // 生成一些随机数据 constexpr int n = 100; constexpr int d = 2; vector<vector<double>> data(n, vector<double>(d)); for (int i = 0; i < n; ++i) { for (int j = 0; j < d; ++j) { data[i][j] = static_cast<double>(rand()) / RAND_MAX; } } // 基于聚类的离群点检测 constexpr int k = 5; constexpr double threshold = 2.0; vector<bool> outliers = outlier_detection(data, k, threshold); // 输出结果 for (size_t i = 0; i < data.size(); ++i) { if (outliers[i]) { cout << "Outlier: "; } else { cout << "Inlier: "; } for (int j = 0; j < d; ++j) { cout << data[i][j] << " "; } cout << endl; } return 0; } ``` 在这个示例中,我们生成了一些随机数据,并使用基于聚类的离群点检测方法来检测其中的离群点。具体来说,我们将数据分为了5个簇,计算了每个簇的平均值和标准差,并使用Z-score值来判断每个数据点是否为离群点。如果Z-score值大于2.0,就认为该数据点是一个离群点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值