Python数据分析案例73——基于多种异常值监测算法探查内幕交易信息

背景

之前有监督模型案例都做烂了,现在来做一下无监督的模型吧,异常检测模型。

其实这个案例主要目的是为了展示这些异常值的无监督算法怎么使用的,本文是一个无监督算法的总结大全。只是恰巧有同学需要做这个内幕交易的数据,因此才使用这个数据作为展示异常时监测算法的使用罢了。

内部交易不可能是凭借几个数据就能检测出来的,因此本文的这个实际背景经济含义可以看看就行了,没啥真正的作用,主要还是展示怎么使用这些异常值检测算法。

其实大多数时候,异常时检测算法,由于基本是无监督模型,效果肯定是没有有监督好的。

那为什么还是有很多人会用?主要就是因为很多情况下我们都是没有标签的,在你不知道他是不是异常的情况下,你必须用一些方法去给他强行聚类出来,就得使用无监督的算法,将一些异常的点找出来。(虽然可能并不是你想要的异常点)


数据介绍

大体上就是一些公司,然后他们各自的财务数据,这些公司有的是阳性,也就是说他可能存在内幕交易,有的是阴性,那么就不存在内部交易。

特征X就是各种市场的数据,例如换手率,市盈率,市净率,还有一些资产负债表的数据以及上市股东的一些持仓市值等。

本来无监督学习不应该是有y的,也就是说不应该是有响应变量标签的。但是这里为了评估一下这个模型效果好不好,所以说我们还是把标签带上,用无监督方法锯出来的标签和这些真实的标签进行一个对比。

当然本次的数据和全部代码文件获取还是可以参考:内幕异常监测


算法介绍

无监督的方法其实没有有监督用的那么常见,所以知道的人不是很多,但是总体而言还是有不少的,例如下面十几种:

如何选择算法?

数据规模:

  • 小规模数据:KNN、LOF、One-Class SVM。
  • 大规模数据:HBOS、IForest、COPOD、ECOD。

数据维度:

  • 低维数据:KNN、LOF。
  • 高维数据:PCA、IForest、COPOD、AutoEncoder。

数据分布:

  • 线性分布:PCA。
  • 非线性分布:LOF、One-Class SVM、AutoEncoder。

是否需要调参:

  • 无需调参:COPOD、ECOD。
  • 需要调参:KNN、LOF、One-Class SVM。

而这些方法都可以很便捷的使用pyod进行获取对应写好的类,调包就行了。那些指望看手搓代码的兄弟就不用指望了。手搓这些异常时检测的代码可能搓到明年一个都写出不来.....出来了可能换个数据就会报错。我一直都是实用主义,能用就行了,明明别人已经写好的轮子,明明别人写好的,现成的封装的类更好用,干嘛还要自己手搓?.........98%的人写论文和研究都是掉包的。(当然需要真正创新的大佬当我没说)

普通人安装 pyod库就行了,不会安装可以问AI。反正都是PIP的方法。


代码实现

我们先导入这个现成的异常检测模型的类看一看:

python 复制代码
# 导入所有常用的 PyOD 模型
from pyod.models.knn import KNN
from pyod.models.pca import PCA
from pyod.models.hbos import HBOS
from pyod.models.lof import LOF
from pyod.models.iforest import IForest
from pyod.models.ocsvm import OCSVM
from pyod.models.copod import COPOD
from pyod.models.ecod import ECOD
from pyod.models.abod import ABOD
from pyod.models.feature_bagging import FeatureBagging
from pyod.models.lscp import LSCP

# 将所有模型类放入一个列表
models_dict = {
    "KNN": KNN,
    "PCA": PCA,
    "HBOS": HBOS,
    "LOF": LOF,
    "IForest": IForest,
    "One-Class SVM": OCSVM,
#     "COPOD": COPOD,
#     "ECOD": ECOD,
#     "ABOD": ABOD,
#     "Feature Bagging": FeatureBagging,
}
# 打印模型列表
for model in models_dict.values():
    print(model.__name__)

我在模型字典里面注释掉了一些模型,主要是因为这些模型需要安装一些别的库,我没有装........

pyod这个库看来也不是自己纯手搓的,也是从别人的库上面建成的。如果需要用到这些被注释掉的方法,那就去看它对应的调用的时候报错,没有哪些库就去装一下好了。

下面开始正式的数据分析过程,数据分析第一步,先导入数据分析四剑客的包。

python 复制代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt 
import seaborn as sns

plt.rcParams ['font.sans-serif'] ='SimHei'               #显示中文
plt.rcParams ['axes.unicode_minus']=False               #显示负号

再导入一些机器学习常用的预处理的方法

python 复制代码
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

读取数据

python 复制代码
df=pd.read_excel('data.xlsx',sheet_name='总表').iloc[:,:].set_index('证券代码').drop(columns='证券简称')
df=df[df['市净率']!='市净率']

然后我们需要将阴性,阳性的这种文本型的标签处理为数值型。

python 复制代码
def check(txt):
    if '阳性' in txt:
        return 1
    elif '阴性' in txt:
        return 0
    else:
        return np.nan

apply向量化处理

python 复制代码
df['label']=df['[阳性样本]总表'].astype('str').apply(check)
df=df.iloc[:,1:]
df.shape

可以看到数据只有300多条,然后有30列特征以及一个y,总共31列。

查看前五行

python 复制代码
df.head()

查看数据信息

python 复制代码
df.info()

可以看到有些数据存在一定的缺失值,不过没关系,这些都是不重要的,因为pyod里面的类都还是支持缺失数据直接输入的。


特征工程

分离X和y

python 复制代码
X=df.drop(columns='label')

y=df['label']
X.shape,y.shape

查看y的分布比例

python 复制代码
y.value_counts(normalize=True)

进行数据标准化

python 复制代码
scaler = StandardScaler()

# 进行标准化
X_s = scaler.fit_transform(X)

# 将标准化后的数据转换为DataFrame
X_s = pd.DataFrame(X_s, columns=X.columns)

X_s=X_s.fillna(X_s.mean())
X_s.shape

无监督 效果对比

自定义一个函数,输入我们的标准化后的数据和标签,还有模型的类,可以自动训练这个模型,然后在这个上面进行预测。得到他这个模型认为的所谓异常的标签之后,再跟真实值去做对比,计算一些评价指标分类问题很常见的一些评价指标,例如准确率,精准率,召回率,F1值,特异度,灵敏度等。

python 复制代码
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix

# 定义函数:训练模型、预测并评估
def evaluate_model(model_class, X, y):
    """
    训练模型并返回评估指标。

    参数:
    - model_class: 模型的类(如 KNN, PCA 等)。
    - X: 数据特征。
    - y: 数据标签。

    返回:
    - 包含评估指标的字典。
    """
    # 初始化模型
    model = model_class(contamination=0.358255)
    X=np.array(X)
    # 训练模型
    model.fit(X)
    
    # 预测
    y_pred = model.predict(X)  # 预测标签(0: 正常, 1: 异常)
    y_pred_score=model.decision_function(X)
    
    # 计算评估指标
    accuracy = accuracy_score(y, y_pred)
    precision = precision_score(y, y_pred)
    recall = recall_score(y, y_pred)
    f1 = f1_score(y, y_pred)
    
    # 计算特异率(Specificity)
    tn, fp, fn, tp = confusion_matrix(y, y_pred).ravel()
    specificity = tn / (tn + fp)
    
    # 返回评估指标
    return {
        'Accuracy': accuracy,
        'Precision': precision,
        'Recall': recall,
        'F1': f1,
        'Specificity': specificity
    },y_pred_score
# 初始化结果数据框
df_eval = pd.DataFrame(columns=['Accuracy', 'Precision', 'Recall', 'F1', 'Specificity'])

遍历模型列表,将所有的模型都进行统一的训练评估,然后将评估结果存在一个数据框里面查看。

python 复制代码
y_pred_score_dict={}
models=models_dict.values()
for model_class in models:
    model_name = model_class.__name__  # 获取模型名称
    print(f"Evaluating {model_name}...")
    
    # 训练模型并评估
    metrics, y_pred_score = evaluate_model(model_class, X_s, y)
    y_pred_score_dict[model_name]=y_pred_score
    # 将结果添加到数据框
    df_eval.loc[model_name,:] = list(metrics.values())

df_eval.shape

查看评价指标

python 复制代码
df_eval#.style.bar(color='pink')

从F1值上来看的话,大概是PCA的效果是最好的。准确率上来说也是如此,大概能有61%的样本能被正确分类。召回率上来看的话,大概只有46.95%的黑样本,也就是所谓的内幕交易能够被检测出来。

评价指标可视化其柱状图

python 复制代码
bar_width = 0.4
colors=['c', 'b', 'g', 'tomato', 'm', 'y', 'lime', 'k','orange','pink','grey','tan','gold','r']
fig, ax = plt.subplots(2,2,figsize=(8,6),dpi=128)
for i,col in enumerate(df_eval.columns[:-1]):
    n=int(str('22')+str(i+1))
    plt.subplot(n)
    df_col=df_eval[col]
    m =np.arange(len(df_col))
    plt.bar(x=m,height=df_col.to_numpy(),width=bar_width,color=colors)
    
    #plt.xlabel('Methods',fontsize=12)
    names=df_col.index
    plt.xticks(range(len(df_col)),names,fontsize=10)
    plt.xticks(rotation=40)
    plt.ylabel(col,fontsize=14)
    
plt.tight_layout()
#plt.savefig('柱状图.jpg',dpi=512)
plt.show()

画出ROC曲线图,计算AUC

python 复制代码
for k,v in y_pred_score_dict.items():
    y_pred_score_dict[k]=(v-v.min())/(v.max()-v.min())
python 复制代码
from sklearn.metrics import roc_curve, auc

plt.figure(figsize=(7, 4.5),dpi=128)

# 遍历每个模型绘制 ROC 曲线
for model_name, y_scores in y_pred_score_dict.items():
    fpr, tpr, _ = roc_curve(y, y_scores)  # 计算假阳性率和真阳性率
    roc_auc = auc(fpr, tpr)  # 计算 AUC 值
    plt.plot(fpr, tpr, label=f'{model_name} (AUC = {roc_auc:.4f})')  # 绘制 ROC 曲线

# 绘制对角线
plt.plot([0, 1], [0, 1], 'k--', label='Random Classifier (AUC = 0.50)')  

# 添加图例和标签
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic (ROC) Curve')
plt.legend(loc='lower right')

# 显示图形
plt.show()

可以看到虽然模型的召回和F1值没有那么高,并且也只有60%的准确率,但是总体上来说比随机猜测效果还是要好一些的。从AUC上来看的话,效果最好的是LOF模型。

也就是说这些模型用来做异常检测的话还是能起到一定的判断效果的。


总结

其实本文具体的数据含义或者说经济业务含义不用太关注,因为本身想从几个数据指标,财务公司指标去判断这个公司有没有内幕交易,本身就是一件很困难的事情,数据决定预测效果质量,模型只是逼进这个上限罢了。如果这个数据本身就对我们的标签没有太多的解释力,那么模型再厉害也不可能能够准确的预测出来。本身这个内幕交易的数据x对y只有这么点解释力,所以说异常检测的模型只有这么点效果也是很正常的,但整体上来说还是比随机猜测要好一些。

由于异常检测是无监督的,其实其检测方式还是和模型算法自身的特性有很强的关系。这个肯定得需要根据特定的数据找特定的异常的时候去设计特定的算法罢了,本文只是对通用的,简便的,能快速使用的,一些异常值检测的方法的一个总结演示。


创作不易,看官觉得写得还不错的话点个关注和赞吧,本人会持续更新python数据分析领域的代码文章~(需要定制类似的代码可私信)

相关推荐
深度之眼6 分钟前
2025时间序列都有哪些创新点可做——总结篇
人工智能·深度学习·机器学习·时间序列
晓数23 分钟前
【硬核干货】JetBrains AI Assistant 干货笔记
人工智能·笔记·jetbrains·ai assistant
jndingxin27 分钟前
OpenCV 图形API(60)颜色空间转换-----将图像从 YUV 色彩空间转换为 RGB 色彩空间函数YUV2RGB()
人工智能·opencv·计算机视觉
Sherlock Ma1 小时前
PDFMathTranslate:基于LLM的PDF文档翻译及双语对照的工具【使用教程】
人工智能·pytorch·语言模型·pdf·大模型·机器翻译·deepseek
知舟不叙1 小时前
OpenCV中的SIFT特征提取
人工智能·opencv·计算机视觉
船长@Quant1 小时前
文档构建:Sphinx全面使用指南 — 基础篇
python·markdown·sphinx·文档构建
kadog1 小时前
PubMed PDF下载 cloudpmc-viewer-pow逆向
前端·javascript·人工智能·爬虫·pdf
喵手1 小时前
从 Java 到 Kotlin:在现有项目中迁移的最佳实践!
java·python·kotlin
liuweidong08022 小时前
【Pandas】pandas DataFrame rsub
开发语言·python·pandas
亿坊电商2 小时前
AI数字人多模态技术如何提升用户体验?
人工智能·ux·ai数字人