Qual é uma boa maneira de transformar atributos do Ordinal Cíclico?

21

Estou tendo o campo 'hora' como meu atributo, mas são necessários valores cíclicos. Como eu poderia transformar o recurso para preservar as informações como '23' e '0' hora estão próximas não muito longe.

Uma maneira de pensar é fazer a transformação: 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]

Existe algum padrão para lidar com esses atributos?

Atualização: Vou usar o aprendizado supervisionado para treinar o classificador aleatório da floresta!

Mangat Rai Modi
fonte
1
Excelente primeira pergunta! Você pode adicionar mais informações sobre qual é o seu objetivo de realizar essa transformação de recurso específico? Você pretende usar esse recurso transformado como uma entrada para um problema de aprendizado supervisionado? Nesse caso, considere adicionar essas informações, pois isso pode ajudar outras pessoas a responder melhor a essa pergunta.
Nitesh
1
@Nitesh, por favor, veja a atualização
Mangat Rai Modi
Você pode encontrar respostas aqui: datascience.stackexchange.com/questions/4967/…
MrMeritology 4/15/15
Desculpe, mas não posso comentar. @ AN6U5, você poderia estender como considerar simultaneamente o dia da semana e a hora após sua abordagem incrível, por favor? Estou lutando com isso desde uma semana e também postei um Q, mas você não o leu.
Seymour

Respostas:

33

A maneira mais lógica de transformar a hora é em duas variáveis ​​que oscilam para frente e para trás na pia. Imagine a posição do ponteiro de fim de hora de um relógio de 24 horas. A xposição oscila para frente e para trás na pia com a yposição. Para um relógio de 24 horas você pode fazer isso com x=sin(2pi*hour/24), y=cos(2pi*hour/24).

Você precisa de ambas as variáveis ​​ou o movimento adequado ao longo do tempo é perdido. Isso se deve ao fato de que a derivada do pecado ou do cos muda no tempo em que a (x,y)posição varia suavemente à medida que viaja ao redor do círculo unitário.

Por fim, considere se vale a pena adicionar um terceiro recurso para rastrear o tempo linear, que pode ser construído por minhas horas (ou minutos ou segundos) desde o início do primeiro registro ou por um carimbo de data / hora do Unix ou algo semelhante. Esses três recursos fornecem proxies para a progressão cíclica e linear do tempo, por exemplo, você pode retirar fenômenos cíclicos como ciclos de sono no movimento das pessoas e também crescimento linear como população versus tempo.

Espero que isto ajude!

Adicionando algum código de exemplo relevante que eu gerei para outra resposta:

Exemplo de se está sendo realizado:

# 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

insira a descrição da imagem aqui

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

Agora vamos tentar:

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

insira a descrição da imagem aqui

Você mal consegue ver que há algumas horas após a meia-noite incluídas no cluster verde antes da meia-noite. Agora vamos reduzir o número de clusters e mostrar que antes e depois da meia-noite podem ser conectados em um único cluster com mais detalhes:

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

insira a descrição da imagem aqui

Veja como o cluster azul contém horários anteriores e posteriores à meia-noite agrupados no mesmo cluster ...

QED!

AN6U5
fonte
Maneira brilhante de lidar com isso. Daria 0 e 23 horas pontuações semelhantes, mas também não tornará o horário am / pm? Que é de fato separado por uma janela de 12 horas.
Mangat Rai Modi
O horário de 12 horas (AM / PM) não funciona, basta convertê-lo para 24 horas.
AN6U5
Acabei de perceber que você está dividindo por 24. Quando você deu analogia ao relógio, pensei que fosse um relógio padrão de 12 horas. No entanto, você está usando o relógio de 24 horas. Parece ser a melhor maneira de me transformar. Obrigado!
Mangat Rai Modi
Resposta incrível exatamente o que eu estava procurando Obrigado ..
Aditya
A resposta aceita combinando sin () e cost () é ótima; aqui como um complemento outra explicação muito detalhada e agradável por Ian London.
FlorianH
3

A pergunta é muito interessante e não me lembro de ler sobre respostas interessantes. Por isso, ouso dar a você uma solução possível, mesmo que pareça louca o suficiente.

Geralmente, evita-se ter as mesmas informações em vários recursos, pois muitos algoritmos não conseguem lidar com isso. Mas este não é o caso da floresta aleatória. Em contraste com a regressão linear (e todos os modelos baseados em idéias semelhantes), as florestas aleatórias testam todos os recursos, levando em consideração cada recurso, um de cada vez. Dessa forma, é possível codificar as mesmas informações de várias maneiras, sem afetar o desempenho da aprendizagem, apenas o espaço e o tempo de execução.

(h+offset)

Perde algum espaço e tempo, mas eu tentaria ver como isso funciona.

rapaio
fonte
0

Idealmente, você não precisa de nenhuma transformação. A diferença de tempo relativa entre dois pontos pode ser usada como função de distância. Onde a classificação pode ser baseada nisso.

em 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);
        }
    }
}
shiva.n404
fonte
1
Está tudo bem, mas a questão precisa de mais alguma coisa ..
Aditya