2009-05-27 20 views
15

mayoría de los algoritmos de clasificación se basan en una comparación por pares-la determina si un < B, A = B o A> B.algoritmo de ordenación en pares-comparación puede volver más información que -1, 0, +1

I Estoy buscando algoritmos (y puntos de bonificación, código en Python) que aprovechen una función de comparación por pares que puede distinguir mucho menos de un poco menos o mucho más de un poco más. Entonces, quizás en lugar de devolver {-1, 0, 1} la función de comparación devuelve {-2, -1, 0, 1, 2} o {-5, -4, -3, -2, -1, 0, 1 , 2, 3, 4, 5} o incluso un número real en el intervalo (-1, 1).

Para algunas aplicaciones (como la clasificación cercana o la ordenación aproximada), esto permitiría determinar un tipo razonable con menos comparaciones.

+0

¿Se puede garantizar que para la función de comparación f() y los valores x, y y z, las distancias f (x, y) + f (y, z) = f (x, z)? ¿Sería eso <=? Hace la diferencia :-). – Joel

+0

Sí, soy consciente de ese problema. En mi aplicación, no puedo garantizarlo pero solo estoy buscando un tipo cercano, de todos modos, no del todo. –

+3

Si lee hacia abajo, OP está buscando minimizar las comparaciones proporcionadas por un panel de expertos humanos donde los resultados de comparación son subjetivos –

Respuesta

7

La información adicional de hecho se puede utilizar para minimizar el número total de comparaciones. Las llamadas a la función super_comparison se pueden usar para hacer deducciones equivalentes a un gran número de llamadas a una función de comparación regular. Por ejemplo, a much-less-than b y c little-less-than b implica a < c < b.

Las deducciones pueden organizarse en contenedores o particiones que pueden clasificarse por separado. Efectivamente, esto es equivalente a QuickSort con partición n-way. Aquí está una implementación en Python:

from collections import defaultdict 
from random import choice 

def quicksort(seq, compare): 
    'Stable in-place sort using a 3-or-more-way comparison function' 
    # Make an n-way partition on a random pivot value 
    segments = defaultdict(list) 
    pivot = choice(seq) 
    for x in seq: 
     ranking = 0 if x is pivot else compare(x, pivot) 
     segments[ranking].append(x) 
    seq.clear() 

    # Recursively sort each segment and store it in the sequence 
    for ranking, segment in sorted(segments.items()): 
     if ranking and len(segment) > 1: 
      quicksort(segment, compare) 
     seq += segment 

if __name__ == '__main__': 
    from random import randrange 
    from math import log10 

    def super_compare(a, b): 
     'Compare with extra logarithmic near/far information' 
     c = -1 if a < b else 1 if a > b else 0 
     return c * (int(log10(max(abs(a - b), 1.0))) + 1) 

    n = 10000 
    data = [randrange(4*n) for i in range(n)] 
    goal = sorted(data) 
    quicksort(data, super_compare) 
    print(data == goal) 

instrumentando este código con el módulo de traza , es posible medir la ganancia de rendimiento. En el código anterior, una comparación tridireccional regular utiliza 133,000 comparaciones, mientras que una función de súper comparación reduce la cantidad de llamadas a 85,000.

El código también hace que sea fácil experimentar con una variedad de funciones de comparación. Esto demostrará que las funciones de comparación n-way ingenuas hacen muy poco para ayudar al género. Por ejemplo, si la función de comparación devuelve +/- 2 para las diferencias superiores a cuatro y +/- 1 para las diferencias de cuatro o menos, solo hay una modesta reducción del 5% en el número de comparaciones. La causa principal es que las particiones granulares utilizadas al principio solo tienen un puñado de "coincidencias cercanas" y todo lo demás corresponde a "coincidencias lejanas".

Una mejora a la comparación súper es cubre rangos logarítmicos (es decir +/- 1 si dentro de diez, +/- 2 si dentro de un centenar, +/- si dentro de un mil.

Una función de comparación ideales sería adaptativo. Para cualquier tamaño de secuencia dado, la función de comparación debería tratar de subdividir la secuencia en particiones de tamaño aproximadamente igual. La teoría de la información nos dice que esto maximizará la cantidad de bits de información por comparación.

El enfoque adaptativo también tiene sentido intuitivo. Las personas primero deben dividirse en amor frente a como antes de hacer distinciones más refinadas como love-a-lot vs love-a-little. Los pases de partición adicionales deberían hacer cada uno distinciones más finas y más finas.

7

Puede usar una ordenación rápida modificada. Permítanme explicar un ejemplo cuando la función de comparación devuelve [-2, -1, 0, 1, 2]. Diga, usted tiene una matriz A para ordenar.

Crea 5 matrices vacías: Aminus2, Aminus1, A0, Aplus1, Aplus2.

Elija un elemento arbitrario de A, X.

Para cada elemento de la matriz, compararlo con X.

Dependiendo del resultado, colocar el elemento en una de las Aminus2, Aminus1, A0 , Aplus1, arreglos Aplus2.

Aplique el mismo tipo recursivamente a Aminus2, Aminus1, Aplus1, Aplus2 (nota: no es necesario ordenar A0, ya que todos los elementos son iguales a X).

Concatenar las matrices para obtener el resultado final: A = Aminus2 + Aminus1 + A0 + Aplus1 + Aplus2.

+2

Por lo tanto, en un mundo bello e igual de propagación de problemas (golpes iguales a -2 .. + 2 intervalos) esto sería un log^4 n solución para ordenar en lugar de un log^2 n solución –

+1

@Tom, esa es la misma complejidad, la base de registro es como un multiplicador constante. – wowest

+0

También, quiere decir log_4 n (log to base 4), no log^4 n (lo que significa log-n a la cuarta potencia). – ShreevatsaR

1

Parece que usar el quicksort modificado de raindog le permitiría transmitir los resultados antes y quizás acceder a ellos más rápido.

¿Quizás esas características ya están disponibles desde una operación qsort cuidadosamente controlada? No he pensado mucho sobre eso.

Esto también suena como una ordenación de radix, excepto que en lugar de mirar cada dígito (u otro tipo de regla de cubo), está acumulando cubetas de las comparaciones enriquecidas. Me cuesta pensar en un caso donde las comparaciones ricas están disponibles pero los dígitos (o algo así como ellos) no lo son.

+1

la aplicación particular que tengo en mente es en la que los humanos en realidad están (subjetivamente) proporcionando la comparación por pares –

+1

Una aplicación interesante. Entonces, en teoría, está tratando de reducir el número de comparaciones al mínimo posible. –

+0

Tom, sí, reduzca el número de comparaciones a expensas de ser solo un tipo cercano –

1

No puedo pensar en ninguna situación en la que esto sea realmente útil. Incluso si pudiera, sospecho que los ciclos adicionales de CPU necesarios para ordenar los valores difusos serían más que esas "comparaciones adicionales" a las que alude. Pero igual voy a ofrecer una sugerencia.

Considere esta posibilidad (todas las cadenas utilizan los 27 caracteres AZ y _):

  11111111112 
    123456789
1/ now_is_the_time 
2/ now_is_never 
3/ now_we_have_to_go 
4/ aaa 
5/ ___ 

Obviamente cadenas 1 y 2 son más similares que 1 y 3 y mucho más similares que 1 y 4.

Un enfoque es escalar el valor de diferencia para cada posición de carácter idéntico y usar el primer carácter diferente para establecer la última posición.

Dejando de lado los signos por el momento, comparando la cuerda 1 con 2, los diferentes en la posición 8 por 'n' - 't'. Esa es una diferencia de 6.Con el fin de convertir eso en un solo dígito 1-9, utilizamos la fórmula:

digit = ceiling(9 * abs(diff)/27) 

ya que la diferencia máxima es de 26. La diferencia mínima de 1 se convierte en el dígito 1. La diferencia máxima de 26 se convierte en el dígito 9. Nuestra diferencia de 6 convierte 3.

Y debido a que la diferencia está en la posición 8, fuera función de comparación volverá 3x10 -8 (en realidad se volverá negativo de la cadena que desde 1 hora después de cadena 2

Usando un proceso similar ess para las cadenas 1 y 4, la función de comparación devuelve -5x10 -1. El retorno más alto posible (cadenas 4 y 5) tiene una diferencia en la posición 1 de '-' - 'a' (26) que genera el dígito 9 y por lo tanto nos da 9x10 -1.

Siga estas sugerencias y úselos como mejor le parezca. Me interesaría saber cómo termina tu código de comparación difusa.

1

Considerando que está buscando ordenar una cantidad de artículos basada en la comparación humana, es posible que desee abordar este problema como un torneo deportivo. Puede permitir que cada voto humano aumente el puntaje del ganador en 3 y disminuya el que pierde en 3, +2 y -2, +1 y -1 o solo 0 0 en el sorteo.

Luego, simplemente haga un tipo regular basado en los puntajes.

Otra alternativa sería una estructura de torneo de eliminación simple o doble.

+0

He considerado hacer una ordenación cercana primero como una forma de sembrar una estructura de torneo –

0

Puede usar dos comparaciones para lograr esto. Multiplique la comparación más importante por 2 y agréguela.

Aquí hay un ejemplo de lo que quiero decir en Perl. Compara dos referencias de matriz por el primer elemento, luego por el segundo elemento.

use strict; 
use warnings; 
use 5.010; 

my @array = (
    [a => 2], 
    [b => 1], 
    [a => 1], 
    [c => 0] 
); 

say "$_->[0] => $_->[1]" for sort { 
    ($a->[0] cmp $b->[0]) * 2 + 
    ($a->[1] <=> $b->[1]); 
} @array; 
 
a => 1 
a => 2 
b => 1 
c => 0 

Usted podría extender esto a cualquier número de comparaciones con mucha facilidad.

0

Quizás haya una buena razón para hacer esto, pero no creo que supere las alternativas para cualquier situación dada y ciertamente no es bueno para casos generales. ¿La razón? A menos que sepa algo sobre el dominio de los datos de entrada y sobre la distribución de los valores, no puede mejorar realmente, digamos, en el orden rápido. Y si hace sabe esas cosas, a menudo hay formas que serían mucho más efectivas.

anti-ejemplo: supongamos que la comparación devuelve un valor de "gran diferencia" para los números que difieren en más de 1000, y que la entrada es {0, 10000, 20000, 30000, ...}

anti -example: igual que el anterior, pero con la entrada {0, 10000, 10001, 10002, 20000, 20001, ...}

Pero, dices, sé que mis entradas no se ven así. Bueno, en ese caso cuéntenos cuáles son realmente sus entradas, en detalle. Entonces alguien podría ser capaz de realmente ayuda.

Por ejemplo, una vez que tuve que ordenar los datos históricos. La información se mantuvo ordenada.Cuando se agregaron nuevos datos, se adjuntaron, luego la lista se ejecutó nuevamente. No tenía la información de dónde se anexaron los nuevos datos. Diseñé un tipo híbrido para esta situación que superaba hábilmente a qsort y a otros seleccionando un tipo que fuera rápido en los datos ya ordenados y ajustándolos para que fuera rápido (esencialmente cambiando a qsort) cuando encontraba datos sin clasificar.

La única forma de mejorar los géneros genéricos es conocer sus datos. Y si quieres respuestas, vas a tener que comunicar eso muy bien.

+0

la tarea es que un ser humano exprese subjetivamente su preferencia por los elementos en una colección en forma pareja para poder ordenar esa colección por preferencia de la persona –

Cuestiones relacionadas