Procedimento de clustering em que cada cluster tem um número igual de pontos?


25

Eu tenho alguns pontos em e quero agrupar os pontos para que:X={x1,...,xn}Rp

  1. Cada grupo contém um número igual de elementos de . (Suponha que o número de clusters divida .)Xn

  2. Cada agrupamento é "espacialmente coeso" em algum sentido, como os agrupamentos de -eans.k

É fácil pensar em muitos procedimentos de cluster que satisfazem um ou outro, mas alguém sabe como obter os dois ao mesmo tempo?


2
O tamanho do cluster também está especificado? Então, como afirmado, o problema parece insolúvel para mim. Considere o seguinte caso com : . Se você quiser dois clusters, terá tamanhos diferentes ou não será "espacialmente coeso". Ou você quer algo como "o mais espacialmente coeso possível" - minimizando a distância máxima intra-cluster ou algo assim? A outra solução seria permitir qualquer divisor de como tamanho de cluster - mas sempre há a solução trivial de clusters de tamanho . n=4,p=1X={-1,0,99,1,1.01}nn1
Erik P.

1
Bom ponto. Idealmente, gostaria de algo "o mais espacialmente coeso possível", satisfazendo a mesma restrição de cardinalidade. Mas eu gostaria de saber sobre os procedimentos que também fazem outras trocas aqui, pois talvez eles possam ser adaptados.
Não Durrett

Dividir os dados por quantis é suficiente? Se os valores não são monotônicos um em relação ao outro, não vejo como eles poderiam ser "espacialmente coesos".
22611 Celenius

4
Houve algumas pesquisas recentes sobre cluster restrito. Google google.com/search?q=constrained+k-means .
whuber

Apenas uma ideia não testada. No agrupamento, uma estatística chamada Silhueta é usada com frequência. Ele mostra o quão bem um objeto está armazenado em cluster e qual é o melhor outro cluster vizinho em que ele pode ser registrado. Portanto, você pode começar com K-MEANS ou outra classificação com diferentes n de cluster . Em seguida, mova objetos não muito bem classificados (de acordo com a estatística) para seus melhores agrupamentos vizinhos com menor n até obter n igual . Espero iterações: mover alguns objetos, recalcular as estatísticas, mover alguns objetos, etc. Esse será o processo de troca.
ttnphns

Respostas:


6

Sugiro uma abordagem em duas etapas:

  1. obtenha boas estimativas iniciais dos centros de cluster, por exemplo, usando meios K difusos ou difusos.

  2. Use a atribuição de vizinho global mais próximo para associar pontos aos centros de cluster: Calcule uma matriz de distância entre cada ponto e cada centro de cluster (você pode tornar o problema um pouco menor calculando apenas distâncias razoáveis), replicar cada centro de cluster X vezes e resolver a linearidade problema de atribuição . Você obterá, para cada centro de cluster, exatamente X corresponde aos pontos de dados, para que, globalmente, a distância entre os pontos de dados e os centros de cluster seja minimizada.

Observe que você pode atualizar os centros de cluster após a etapa 2 e repetir a etapa 2 para executar basicamente médias médias com número fixo de pontos por cluster. Ainda assim, será uma boa ideia obter um bom palpite inicial primeiro.


4

Experimente esta variação k-means:

Inicialização :

  • escolha kcentros do conjunto de dados aleatoriamente, ou melhor ainda, usando a estratégia kmeans ++
  • para cada ponto, calcule a distância até o centro do cluster mais próximo e crie um monte para esse
  • desenhe pontos da pilha e atribua-os ao cluster mais próximo, a menos que o cluster já esteja cheio demais. Nesse caso, calcule o próximo centro de cluster mais próximo e reinsira no heap

No final, você deve ter um pareamento que atenda aos seus requisitos do mesmo número de objetos + -1 por cluster (verifique se os últimos poucos clusters também têm o número certo. Os primeiros mclusters devem ter ceilobjetos e o restante exatamente como floorobjetos).

Etapa de iteração :

Requisitos: uma lista para cada cluster com "propostas de troca" (objetos que preferem estar em um cluster diferente).

Etapa E : calcular os centros de cluster atualizados como no k-means regular

Etapa M : Iterando todos os pontos (apenas um ou todos em um lote)

Calcule o centro de cluster mais próximo do objeto / todos os centros de cluster mais próximos que os atuais. Se for um cluster diferente:

  • Se o outro cluster for menor que o atual, basta movê-lo para o novo cluster
  • Se houver uma proposta de troca do outro cluster (ou qualquer cluster com uma distância menor), troque as atribuições de cluster de dois elementos (se houver mais de uma oferta, escolha aquela com a maior melhoria)
  • caso contrário, indique uma proposta de troca para o outro cluster

Os tamanhos dos aglomerados permanecem invariantes (+ - a diferença teto / piso); os objetos são movidos apenas de um aglomerado para outro, desde que resulte em uma melhoria na estimativa. Portanto, deve convergir em algum momento como k-means. Pode ser um pouco mais lento (ou seja, mais iterações).

Não sei se isso foi publicado ou implementado antes. É exatamente o que eu tentaria (se eu tentasse k-means. Existem algoritmos de clustering muito melhores).

Um bom ponto de partida pode ser a implementação do k-means no ELKI , que já parece oferecer suporte a três inicializações diferentes (incluindo o k-means ++), e os autores disseram que também querem ter estratégias de iteração diferentes, para cobrir todas as várias variantes de forma modular (por exemplo, Lloyd, MacQueen, ...).


2
Uma abordagem semelhante é incluído no Elki como um tutorial e no tutorial "extensão" Módulo: elki.dbs.ifi.lmu.de/wiki/Tutorial/SameSizeKMeans
Erich Schubert

3

Este é um problema de otimização. Temos uma biblioteca java de código aberto que resolve esse problema (cluster onde a quantidade por cluster deve estar entre os intervalos definidos). Você precisaria que seu número total de pontos tivesse no máximo alguns milhares - não mais que 5000 ou talvez 10000.

A biblioteca está aqui:

https://github.com/PGWelch/territorium/tree/master/territorium.core

A própria biblioteca está configurada para problemas de tipo geográfico / GIS - para que você veja referências a X e Y, latitudes e longitudes, clientes, distância e tempo, etc. Você pode simplesmente ignorar os elementos 'geográficos' e usá-lo como um puro clusterer.

Você fornece um conjunto de clusters de entrada inicialmente vazios, cada um com uma quantidade alvo mínima e máxima. O clusterer atribuirá pontos aos seus clusters de entrada, usando um algoritmo de otimização baseado em heurística (swaps, movimentos etc.). Na otimização, prioriza primeiro manter cada cluster dentro de sua faixa de quantidade mínima e máxima e, em seguida, minimiza as distâncias entre todos os pontos no cluster e o ponto central do cluster, para que um cluster seja espacialmente coeso.

Você atribui ao solucionador uma função métrica (isto é, função de distância) entre pontos usando esta interface:

https://github.com/PGWelch/territorium/blob/master/territorium.core/src/main/java/com/opendoorlogistics/territorium/problem/TravelMatrix.java

A métrica é realmente estruturada para retornar uma distância e um 'tempo', porque foi projetada para problemas geográficos baseados em viagens, mas para problemas arbitrários de cluster, apenas defina 'tempo' como zero e a distância como a métrica real que você está usando entre pontos.

Você configurou seu problema nesta classe:

https://github.com/PGWelch/territorium/blob/master/territorium.core/src/main/java/com/opendoorlogistics/territorium/problem/Problem.java

Seus pontos seriam os 'Clientes' e a quantidade deles seria 1. Na classe do cliente, defina costPerUnitTime = 0 e costPerUnitDistance = 1, supondo que você esteja retornando sua distância métrica no campo 'distância' retornado pelo TravelMatrix.

https://github.com/PGWelch/territorium/blob/master/territorium.core/src/main/java/com/opendoorlogistics/territorium/problem/Customer.java

Veja aqui um exemplo de execução do solucionador:

https://github.com/PGWelch/territorium/blob/master/territorium.core/src/test/java/com/opendoorlogistics/territorium/TestSolver.java



2

Recentemente, eu mesmo precisei disso para um conjunto de dados não muito grande. Minha resposta, embora tenha um tempo de execução relativamente longo, é garantida para convergir para um ótimo local.

def eqsc(X, K=None, G=None):
    "equal-size clustering based on data exchanges between pairs of clusters"
    from scipy.spatial.distance import pdist, squareform
    from matplotlib import pyplot as plt
    from matplotlib import animation as ani    
    from matplotlib.patches import Polygon   
    from matplotlib.collections import PatchCollection
    def error(K, m, D):
        """return average distances between data in one cluster, averaged over all clusters"""
        E = 0
        for k in range(K):
            i = numpy.where(m == k)[0] # indeces of datapoints belonging to class k
            E += numpy.mean(D[numpy.meshgrid(i,i)])
        return E / K
    numpy.random.seed(0) # repeatability
    N, n = X.shape
    if G is None and K is not None:
        G = N // K # group size
    elif K is None and G is not None:
        K = N // G # number of clusters
    else:
        raise Exception('must specify either K or G')
    D = squareform(pdist(X)) # distance matrix
    m = numpy.random.permutation(N) % K # initial membership
    E = error(K, m, D)
    # visualization
    #FFMpegWriter = ani.writers['ffmpeg']
    #writer = FFMpegWriter(fps=15)
    #fig = plt.figure()
    #with writer.saving(fig, "ec.mp4", 100):
    t = 1
    while True:
        E_p = E
        for a in range(N): # systematically
            for b in range(a):
                m[a], m[b] = m[b], m[a] # exchange membership
                E_t = error(K, m, D)
                if E_t < E:
                    E = E_t
                    print("{}: {}<->{} E={}".format(t, a, b, E))
                    #plt.clf()
                    #for i in range(N):
                        #plt.text(X[i,0], X[i,1], m[i])
                    #writer.grab_frame()
                else:
                    m[a], m[b] = m[b], m[a] # put them back
        if E_p == E:
            break
        t += 1           
    fig, ax = plt.subplots()
    patches = []
    for k in range(K):
        i = numpy.where(m == k)[0] # indeces of datapoints belonging to class k
        x = X[i]        
        patches.append(Polygon(x[:,:2], True)) # how to draw this clock-wise?
        u = numpy.mean(x, 0)
        plt.text(u[0], u[1], k)
    p = PatchCollection(patches, alpha=0.5)        
    ax.add_collection(p)
    plt.show()

if __name__ == "__main__":
    N, n = 100, 2    
    X = numpy.random.rand(N, n)
    eqsc(X, G=3)

1
Obrigado por esta contribuição, @ user2341646. Você gostaria de adicionar alguma exposição que explique o que é essa solução, como ela funciona e por que é uma solução?
gung - Restabelece Monica

ESTÁ BEM. Basicamente, o algoritmo começa com atribuições de associação aleatórias, mas há quase G membros em um cluster e há K clusters em geral. Definimos a função de erro que mede as distâncias médias entre os dados em um cluster, com a média de todos os clusters. Examinando sistematicamente todos os pares de dados, vemos se a troca da associação desses dois dados resulta em um erro menor. Nesse caso, atualizamos o menor erro possível; caso contrário, desfazemos a opção de associação. Fazemos isso até que não haja mais movimentos para um passe inteiro.
Alexander Kain
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.