飞道的博客

【机器学习】实战系列五——天文数据挖掘实验(天池比赛)

477人阅读  评论(0)

系列文章目录

学习笔记:
【机器学习】第一章——机器学习分类和性能度量
【机器学习】第二章——EM(期望最大化)算法
【机器学习】第六章——概率无向图模型

实战系列:
【机器学习】实战系列一——波士顿房价预测(一文学会)
【机器学习】实战系列二——梯度下降(一文学会)
【机器学习】实战系列三——支持向量机(一文学会)
【机器学习】实战系列四——聚类实验(一文学会)
【机器学习】实战系列五——天文数据挖掘实验(天池比赛)



【注】本文实验环境为Jupyter Notebook

开源

本次实验的完整代码(Notebook)已开源至我的github
如果对你有帮助的话,欢迎star和follow~

数据集已上传至百度网盘
提取码:8sk6


实验简介

郭守敬望远镜是一架新类型的大视场兼备大口径望远镜,在大规模光学光谱观测和大视
场天文学研究方面,居于国际领先的地位。作为世界上光谱获取率最高的望远镜,LAMOST 每
个观测夜晚能采集万余条光谱,使得传统的人工或半人工的利用模板匹配的方式不能很好应
对,需要高效而准确的天体光谱智能识别分类算法。

实验目的

对 LAMOST 光谱进行分类,需要将光谱分为四类,STAR/ GALAXY/QSO/ UNKNOWN,即:恒星/星系/类星体/未知。

实验数据集

数据描述

  • 数据包括索引文件(index.csv) 和波段文件(id.txt 集合的 zip) 两部分。
  • 索引文件记录了波段文件 id 号以及分类信息
  • 波段文件存储的是已经插值采样好的波段数据,以逗号分隔。所有波段文件的波段区间和采样点都相同,采样点个数都是 2600 个。

数据说明

  • 带 train 为训练集
  • 带 test 为第一阶段测试集
  • unknown 类别是由于光谱质量(信噪比低)等原因,未能够给出确切的分类的天体
  • Unknown 分类目前由程序给出,其中不排除有恒星、星系和类星体。

数据处理

本文采用两种方法完成实验——LightGBM 模型和 CNN 卷积神经网络。

数据分析

拿到该题目后,首先想到的是对数据集进行可视化分析,通过直观的图表对数据集进行一个感性的理解,这样能使我们更好的理解数据集的构成,深刻的理解数据集的各种特征,方便对以后的程序编写有一个指导性的作用。
我们首先将所有训练集的type标签进行分类,分成STAR,GALAXY,QSO,UNKNOWN四种类别,分别对每种类别的样本数量进行统计。从图(5.3.1)中可以看出,不同类别天体的数据的分布状况极不平衡,属于STAR种类的数据个数远远超过其他几种类别的天体的总数,占总体样本的92%以上,而QSO样本的数量不到总数的1%。这代表我们的模型如果按照该数据集学习,将会出现严重的过拟合现象,模型对未知数据的拟合度会很差.


随机选取三个样本的前100个光谱特征值,并将它们的特征值在折线图上可视化。从图(5.3.2)中我们能够看出,同一样本的不同特征值的变化范围很大,参数的取值范围可从-1000到10000。同样地,不同样本的同一参数的取值范围波动也很大,相差可达几百倍以上。


随机抽取了部分数据进行主成分分析(PCA),并将分析结果可视化,如图5.3.3所示。从图中我们可以看到,样本点绝大多数都分布在与XOY平面平行的某一平面的对角线上,在Z轴的方向上的区分度比较小。

数据预处理

由5.3节中的分析可以,数据集的数据分布比较不合理,如果直接进行学习效果将会很差,因此我们首先考虑对数据集进行预处理,使得数据分布合理,数据取值范围在合适的范围内。

  1. 数据均衡化
    由于数据集中含有过多的STAR天体,而GALAXY,QSO,UNKNOWN天体的数量过少,学习会出现过拟合现象,因此考虑优化数据集的分布,这里使用过采样和欠采样的方法。对于STAR数据来说,其数量过于庞大,考虑对其进行欠采样。从STAR数据中随机抽取一部分作为STAR的训练集使用,其余的数据舍弃不用。对于GALAXY,QSO,UNKONWN等天体,由于其数据数量过少,考虑对其进行过采样。例如,对一个QSO天体,将这中天体的特征光谱同时乘上一个系数,形成一个新的QSO天体,作为训练集使用。我们尝试了ADASYN、SMOTE等过采样方法,完成了数据分布的均衡化。
  2. 数据归一化
    从图5.3.3中,可以看到样本点在Z轴的区分度较小。考虑到样本的数据取值范围较大,我们可以将数据进行归一化处理。经过归一化处理的样本在主成分分析后,再进行可视化处理。可以看出,在图5.4.1中,数据在Z轴的层次上有了更明显的区分度。

LightGBM

LightGBM原理

本次实验中首先采用了LightGBM算法进行数据集的分类,LightGBM凭借出色表现多次获得Kaggle比赛的冠军。微软开源的LightGBM(基于GBDT的)则很好的解决了GBDT和XGBoost所面临的大量数据和高特征维度下结果不精确的问题。它主要包含两个算法:单边梯度采样,Gradient-based One-Side Sampling(GOSS)和互斥特征绑定,Exclusive Feature Bundling(EFB)
GOSS(从减少样本角度):排除大部分小梯度的样本,仅用剩下的样本计算信息增益。GBDT虽然没有数据权重,但每个数据实例有不同的梯度,根据计算信息增益的定义,梯度大的实例对信息增益有更大的影响,因此在下采样时,我们应该尽量保留梯度大的样本(预先设定阈值,或者最高百分位间),随机去掉梯度小的样本。我们证明此措施在相同的采样率下比随机采样获得更准确的结果,尤其是在信息增益范围较大时。
EFB(从减少特征角度):捆绑互斥特征,也就是他们很少同时取非零值(也就是用一个合成特征代替)。通常真是应用中,虽然特征量比较多,但是由于特征空间十分稀疏,是否可以设计一种无损的方法来减少有效特征呢?特别在稀疏特征空间上,许多特征几乎是互斥的(例如许多特征不会同时为非零值,像one-hot),我们可以捆绑互斥的特征。最后,我们将捆绑问题归约到图着色问题,通过贪心算法求得近似解。

LightGBM实验过程

  1. 导入库
import numpy as np
import pandas as pd
import os
from imblearn.over_sampling import SMOTE
# from sklearn.cross_validation import train_test_split
from sklearn.model_selection import KFold
from sklearn.metrics import f1_score
import lightgbm as lgb

  1. 构造训练集与测试集
    为了方便操作和处理,将.txt文件中的2600个特征光谱值与id索引合并成一个.csv文件,也就是说在.csv文件中设置id,attribute1,attribute2,……,attribute2600共2601个字段,并通过索引.csv文件将id与对应.txt文件中的特征光谱值对应起来。
    接着利用K-Fold方法构造训练集和验证集,其中n_split参数设置为10,根据K-Fold方法,我们将整个数据集划分为10个互不相交的子集,并且每次训练时以其中的9个子集的并集作为训练集,以另外一个子集作为测试集。
# 将label.csv和attributes合并 之后划分验证集交叉验证
print("loading test data...")
test_data = pd.read_csv("../data_csv/test_data.csv")
test_data.drop(['Unnamed: 0'], inplace=True, axis=1)
# print(test_data)
test_data_np = test_data.values
# print(test_data_np)
X_test_data = test_data_np[:, 0:2600]
Y_test_data = test_data_np[:, 2600]
print("X_test_data shape:" + str(X_test_data.shape))
print("Y_test_data shape:" + str(Y_test_data.shape))
# K-Fold方法划分数据集和验证集
kf = KFold(n_splits=10)
for train_index, test_index in kf.split(X_test_data):
    print('train_index', train_index, 'test_index', test_index)
    train_X, train_y = X_test_data[train_index], Y_test_data[train_index]
    test_X, test_y = X_test_data[test_index], Y_test_data[test_index]
print("loading test data ended")
print(test_X.shape)
overstamp = SMOTE(random_state=0)
SMOTE_train_x, SMOTE_train_y = overstamp.fit_resample(train_X, train_y)
print("new train shape" + str(SMOTE_train_x.shape))
  1. 使用LightGBM训练
    接着,构造我们需要的LightGBM模型,导入训练集lgb_train,设置模型的参数params,最后设置迭代最大次数num_boost_round。模型构造完成后就可以利用训练集进行训练了,运行bst = lgb.train(params, lgb_train, num_boost_round=10000)命令,开始训练模型。
lgb_train = lgb.Dataset(SMOTE_train_x, label=SMOTE_train_y)

params = {
   'task': 'train',
               'boosting': 'gbdt',
               'application': 'multiclass',
               'num_class': 4,
                'metric': 'multi_logloss',
                'min_data_in_leaf': 500,
                 'num_leaves': 31,
                 'learning_rate': 0.05,
 				'feature_fraction': 1.0,
                 'bagging_fraction': 1.0,
                 'bagging_freq': 2,
               'bagging_seed': 5048,
               'feature_fraction_seed': 2048,
                'verbose': 5, # >1 显示信息
}
print('start training')
# bst = lgb.train(params, lgb_train, num_boost_round=1000)
bst = lgb.train(params,  lgb_train,  num_boost_round=10000)
print('finished')
  1. 开始预测
    利用训练好的模型去预测测试集,输出预测出的天体分类和正确的天体分类,并计算出f1_score作为预测准确度的结果。
predict_y = bst.predict(test_X)
predict_y = predict_y.tolist()
print(len(predict_y))
predict_Y = []
for i in range(1000):
    # print(predict_y[i])
    num = predict_y[i].index(max(predict_y[i]))
    # print(num)
    predict_Y.append(num)
print(predict_Y)
print(test_y)
score = f1_score(test_y, predict_Y, average='macro')
print("score: %f" % score)

深度学习CNN方法

卷积神经网络原理

卷积神经网络通过卷积、激活、池化,捕捉二维图像数据的特定特征空间,并作为输入予全连接网络,映射到标签集。把天体光谱数据看作1(通道维C)x1(高H)x2600(宽W,特征维)的类似图像数据,然后就可以采用卷积神经网络提取特征,具体的网络结构如下:

CNN实验过程

由于CNN的代码较长,但是读起来容易理解,笔者就不多赘述,网络结构可见上图。笔者在省略了CNN实验过程,不过实验的相关代码已上传至我的github。有需要的读者可以前去观看。

实验结果以及分析

为了避免小组之间的互相抄袭,笔者在此处省略了实验结果的分析,不过实验的相关代码Notebook已上传至我的github。有需要的读者可以前去观看。
可以透露的是实验结果分别是LightGBM:f1-score ≈ 0.56 ; CNN ≈ 0.74。

总结

实验告诉我们,在入手一个项目或者实验的时候,不要盲目的直接去套模型或者带入方法。我们首先应该做的是去对数据集进行一个可视化处理,从感性的角度产生对一个数据集的认知。这样能对这个数据集有一个整体的认知,方便我们根据数据集的数据分布特征去对数据集进行处理,选择合适的方法完成实验。
同时,由于该实验中数据分布不合理的情况导致刚开始训练的模型效果不是很好,因此我们通过查找资料,学会了欠拟合和过拟合的数据处理方法,通过该处理能够使得数据集达到一种数据分布相对合理、平衡的状态,更有利于模型的训练和学习。
在构造训练集和测试集时,我们采用了K-Fold方法,通过划分训练集为不想交的子集,并将子集相互组合形成不同的训练集和测试集,能够提高模型训练的泛化能力和效果。

如果本篇文章给你带来了启发或收获,欢迎点赞,收藏+关注我,你的点赞是对我最大滴支持~


转载:https://blog.csdn.net/weixin_43794327/article/details/116358293
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场