清理、处理和可视化数据集,第 2 部分 从干净的数据集中获取宝贵洞察-1
- UID
- 1066743
|
清理、处理和可视化数据集,第 2 部分 从干净的数据集中获取宝贵洞察-1
数据是有价的,但来自数据的洞察是无价的。当您得到一个数据集时,如何理解该数据并利用它来获取知识呢?为了帮助您实现此目标,我将向您展示两种处理已清理数据集的方法。
本系列包含 3 部分,本教程是第 2 部分,将继续讨论我在中发起的关于散乱数据的讨论,展示如何对已清理的数据集应用机器学习方法。第 3 部分将继续探讨数据可视化方法。
图 1. 数据处理管道回想,我清理了一个包含动物特征的数据集,以便可以使用该数据集进行聚类。现在,我将使用两种无监督学习算法为此数据进行聚类。第一种算法名为矢量量化 (VQ),最初被开发为一种基于分组编码原理的数据压缩算法(尽管您也可以用它来解决聚类问题)。第二种算法名为自适应共振理论 (ART),是利用内存模板的概念开发的,后者可应用于具有相似性的特征。ART 还包含一个重要功能,那就是动态调节所使用的聚类次数,这个特性在聚类领域具有独特的优势。
矢量量化VQ 最初在信号处理中被作为一种压缩数据的方法,它对要传输的数据进行分段,以便最小化将要传输的数据量。通过将类似数据聚类到各个分组中,可以传输集群标识符而不是特征数据,从而最小化传输的数据量。因为可以将不同的特征聚集到一起,所以该方法是有损的,在传输中会丢失一些信息。但是,通过将类似的特征矢量分组到一起,可以实现典型的聚类。
VQ 的结构如图 2 所示。您可以将要编码(即压缩)的码字或数据作为输入应用于网络。该算法计算整个网络的输出(或码书)的方式是,将特征矢量输入乘以与每个输出节点相关的权重,然后选择具有最小值的输出节点作为最接近的集群。最后,该算法对权重稍作调节,让 VQ 质心向输入方向移动。VQ 以这种方式按照给定迭代次数对网络应用整个码字集(或者直到没有码字更改输出码书的成员关系)。
图 2. 一种矢量量化网络经过训练后,您可以对网络应用新的码字来标识它们的码书(即它们的成员集群)。在数据压缩上下文中,此方法将一个高维特征空间映射到一个低维子空间。
此方法还被应用于数据更正,方法是将损坏的码字应用于网络,然后选择的输出码书表明了该分组的质心,以便重建输入。
实现 VQ通过 VQ 进行聚类可简单定义为:使用一个无标签的数据集来训练网络。在生产环境中,您可以对网络应用新的观察值,并采用胜者全得的方法从输出节点中识别结果集群。我在 GitHub 上提供了一个 。此实现被拆分为两个源文件,但其中一个在各种机器学习算法中是通用的。如图 3 所示,文件 learn.c 实现了 VQ 和 ART 都在使用的通用元素,包括解析来自命令行的用户选项,打开和关闭文件,并解析来自输入文件的观察值。文件 vq.c 包含拆分为初始化、训练和验证的 VQ 实现。
图 3. VQ 实现样本的高级流程图后续讨论将专注于 VQ 实现的细节。
首先,注意所需的结构和符号的集合,如下所示。我定义了输出节点(码书)的数量;学习率;输出计算数组;权重(涵盖指向输出的特征矢量的二维权重,如上面图 2 所示);以及网络的输入矢量。
清单 1. VQ 的关键结构和符号1
2
3
4
5
6
7
8
| #define OUTPUTS 7
#define MAX_FEATURES 21
#define RATE 0.01
static double outputs[ OUTPUTS ];
static double weights[ OUTPUTS ][ MAX_FEATURES ];
static int input_feature_vector[ MAX_FEATURES ];
|
vq_initialize 函数初始化输出数组和权重数组。
vq_train 函数实现了网络的训练循环(参见 清单 2)。需要向此函数传递要在训练中执行的测试数据文件和迭代次数。该算法首先分配前 n 个观察值作为类原型(但也可以随机分配观察值)。get_observation 函数从输入文件中获取一个新观察值,vq_set_input_vector 将这个观察值转换为输入矢量。vq_updateweights 函数更新输出节点(类)的权重,以便向输入特征方向移动(提供一个较小的学习率来最大程度地减少更改)。
然后,我对训练循环执行了指定的迭代次数。此循环获取一个新观察值(而且如果循环到达文件末尾,则回到起点重新开始),然后在观察值上执行一个类似的训练周期。该观察值被馈送到网络的输入矢量中(通过 vq_set_input_vector),然后在网络中对输入进行前馈处理以识别最近的类(通过 vq_feedforward)。然后,这一步返回了最近的类,我使用该类更新此输出节点的权重。
清单 2. 训练 VQ 网络的 vq_train 函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| void vq_train( FILE *fptr, long iterations )
{
int result;
observation obs;
long iteration = 0;
// Initialize the first N observations to the N classes.
for ( int class = 0 ; class < OUTPUTS ; class++ )
{
result = get_observation( fptr, &obs );
vq_set_input_vector( &obs );
vq_updateweights( class );
}
while ( iteration < iterations )
{
result = get_observation( fptr, &obs );
if ( !result )
{
// Reset the file position to the beginning.
fseek( fptr, 0L, SEEK_SET );
iteration++;
}
else
{
vq_set_input_vector( &obs );
int class = vq_feedforward( );
vq_updateweights( class );
}
}
return;
}
|
清单 3 提供了 vq_feedforward 函数,该函数执行网络,并识别代表离观察值最近的类的获胜输出节点。为此,该函数会迭代每个输出节点,并计算来自输入矢量的权重的欧氏距离之和。该结果会为每个输出节点的权重提供输入特征矢量的类似指标,其中最小的数字表示最近的集群。该函数的后半部分将跟踪最佳的输出节点,然后将其返回给调用方。
清单 3. 执行 VQ 网络的 vq_feedforward 函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| int vq_feedforward( void )
{
int best;
double best_value;
// Given the current input feature vector, compute each output node.
for ( int output = 0 ; output < OUTPUTS ; output++ )
{
outputs[ output ] = 0.0;
for ( int feature = 0 ; feature < MAX_FEATURES ; feature++ )
{
outputs[ output ] +=
distance( NORMALIZE( weights[ output ][ feature ] ),
input_feature_vector[ feature ] );
}
// Keep track of the best activation
if ( output == 0 )
{
best = 0;
best_value = outputs[ output ];
}
else
{
if ( outputs[ output ] < best_value )
{
best = output;
best_value = outputs[ output ];
}
}
}
return best;
}
|
清单 4 中所示的 vq_updateweights 函数实现了 VQ 的学习部分。一旦找到离输入矢量最近的输出节点,就可以更新此输出节点的权重,以便将它们朝新特征方向移动。为此,我采用了一个学习率来调节每个权重,调节幅度为特征矢量值与(获胜输出节点的)此特征权重的差值,以便减少观察值的总体变化。
清单 4. 学习最新特征矢量的 vq_updateweights 函数1
2
3
4
5
6
7
8
9
10
11
| void vq_updateweights( int class )
{
for ( int feature = 0 ; feature < MAX_FEATURES ; feature++ )
{
weights[ class ][ feature ] += RATE *
( ( double ) NORMALIZE( input_feature_vector[ feature ] ) -
weights[ class ][ feature ] );
}
return;
}
|
验证函数(vq_validate,未具体展示)用于测试新观察值,但不包括新的学习,所以无法验证将网络推广到未见过的观察值的效果。在来自我的测试数据文件的观察值集中,此函数识别每个观察值的获胜节点(或类)。 |
|
|
|
|
|