什么是转换循环序数属性的好方法?

数据挖掘 特征提取 特征缩放 特征化
2021-10-13 21:38:27

我将“小时”字段作为我的属性,但它需要一个循环值。我如何转换该功能以保留诸如“23”和“0”小时之类的信息,距离不远。

我能想到的一种方法是进行转换:min(h, 23-h)

Input: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]

Output: [0 1 2 3 4 5 6 7 8 9 10 11 11 10 9 8 7 6 5 4 3 2 1]

是否有任何标准来处理这些属性?

更新:我将使用监督学习来训练随机森林分类器!

3个回答

转换小时的最合乎逻辑的方法是转换成两个来回摆动不同步的变量。想象一下 24 小时制时针末端的位置。x位置前后摆动,与位置不同步y对于 24 小时制,您可以使用x=sin(2pi*hour/24),来完成此操作y=cos(2pi*hour/24)

您需要这两个变量,否则会丢失正确的时间运动。这是因为 sin 或 cos 的导数随时间变化,而(x,y)位置在绕单位圆行进时平滑变化。

最后,考虑是否值得添加第三个特征来跟踪线性时间,可以从第一条记录的开始或 Unix 时间戳或类似的东西开始构建我的小时(或分钟或秒)。然后,这三个特征为时间的循环和线性进展提供了代理,例如,您可以提取循环现象,如人们运动中的睡眠周期,以及人口与时间的线性增长。

希望这可以帮助!

添加一些我为另一个答案生成的相关示例代码:

如果完成的例子:

# Enable inline plotting
%matplotlib inline

#Import everything I need...

import numpy as np
import matplotlib as mp

import matplotlib.pyplot as plt
import pandas as pd

# Grab some random times from here: https://www.random.org/clock-times/
# put them into a csv.
from pandas import DataFrame, read_csv
df = read_csv('/Users/angus/Machine_Learning/ipython_notebooks/times.csv',delimiter=':')
df['hourfloat']=df.hour+df.minute/60.0
df['x']=np.sin(2.*np.pi*df.hourfloat/24.)
df['y']=np.cos(2.*np.pi*df.hourfloat/24.)

df

在此处输入图像描述

def kmeansshow(k,X):

    from sklearn import cluster
    from matplotlib import pyplot
    import numpy as np

    kmeans = cluster.KMeans(n_clusters=k)
    kmeans.fit(X)

    labels = kmeans.labels_
    centroids = kmeans.cluster_centers_
    #print centroids

    for i in range(k):
        # select only data observations with cluster label == i
        ds = X[np.where(labels==i)]
        # plot the data observations
        pyplot.plot(ds[:,0],ds[:,1],'o')
        # plot the centroids
        lines = pyplot.plot(centroids[i,0],centroids[i,1],'kx')
        # make the centroid x's bigger
        pyplot.setp(lines,ms=15.0)
        pyplot.setp(lines,mew=2.0)
    pyplot.show()
    return centroids

现在让我们试一试:

kmeansshow(6,df[['x', 'y']].values)

在此处输入图像描述

您几乎看不到午夜之前的绿色集群中包含一些午夜之后的时间。现在让我们减少集群的数量,并更详细地显示午夜之前和之后可以连接到一个集群中:

kmeansshow(3,df[['x', 'y']].values)

在此处输入图像描述

看看蓝色集群如何包含从午夜之前和之后聚集在同一个集群中的时间......

QED!

这个问题很有趣,我不记得阅读有趣的答案。因此,即使看起来很疯狂,我也敢为您提供一种可能的解决方案。

通常人们会避免在多个特征中拥有相同的信息,因为许多算法无法处理这一点。但这不是随机森林的情况。对比线性回归(以及基于相似思想的所有模型),随机森林通过一次考虑每个特征来测试所有特征。通过这种方式,可以以多种方式对相同的信息进行编码,而不会影响学习性能,仅影响空间和运行时间。

所以我的建议是创建 24 个特征,每个形式 (H+FFse). 就像您在本地时区中编码时间一样。因此,您让 rf 有机会在几个小时左右使用相同的单位检测一些有趣的聚集,因为每个可能的小时都有机会在 24 个特征中的至少 1 个中正确编码。

它浪费了一些空间和时间,但我会尝试看看它是如何工作的。

理想情况下,您不需要任何转换。两点之间的相对时间差可以作为距离函数。哪里分类可以以此为依据。

在java中:

public class TimeDistanceMeasurer implements DistanceMeasure {

    @Override
    public double compute(double[] a, double[] b) throws DimensionMismatchException {
        String time1 = String.format("%02d", (int)a[0]) + String.format("%02d", (int)a[0]);
        String time2 = String.format("%02d", (int)b[0]) + String.format("%02d", (int)b[0]);

        SimpleDateFormat format = new SimpleDateFormat("HHmm");
        try {
            Date date1 = format.parse(time1);
            Date date2 = format.parse(time2);
            return Math.abs(date2.getTime() - date1.getTime());
        } catch (Exception e) {
            throw new IllegalStateException("Something went wrong.", e);
        }
    }
}