O KDE adaptativo é uma melhoria de um KDE normal. Seleccionar uma janela que suavize todas as partes da curva de estimativas de um forma adequada é dificil quando as amostras contêm zonas com muito densidades muito diferentes. Frequentemente, é necessário um compromisso na suavidade da estimativa resultante em áreas de baixa densidade. O KDE Adaptativo tenta resolver o problema permitindo que o valor da janela varie em função da densidade da amostra. Em áreas de maior concentração de pontos a janela é menor, e vice-versa. Como a densidade é uma incógnita, o primeiro passo é realizar uma estimativa piloto usando uma função KDE normal. Em seguida calcula-se a média geométrica das estimativas, e com este valor calcula-se um factor de janela lambda para cada vértice que é de seguida usado para calcular estimativas ajustadas à densidade observada localmente. Estes passos podem ser sumarizados da seguinte forma (Silverman 1986):

  1. Encontrar uma estimativa piloto kde(x) que satisfaça kde(Xi)>0 para todos i;
  2. Calcular a média geométrica de todas as estimativas kde(Xi);
  3. Calcular o factor de janela local lambda para cada i;
  4. Calcular o KDE adaptativo

A definição do Grasshopper é a seguinte:

Passo 1 (Step 1): Para o primeiro passo pode ser usada qualquer função kde. No entanto, deve ser assegurado que todos os vértices da mesh têm estimativas com valores superiores a 0, ou seja, o domínio das estimativas de KDE não pode começar ou incluir 0 e tem que ser positivo.

Passo 2 (Step 2): O Grasshopper tem um componente para o cálculo da média geométrica . Contudo, não é adequado para números tão pequenos como os que são resultado da função kde. O código C# abaixo usa um método diferente de calcular a média geométrica que evita os problemas da multiplicação de números muito pequenos.

private void RunScript(List x, ref object A)
  {
    double tempv = 0.0;
    double a = 0.0;
    for (int i = 0; i < x.Count; i++)
      tempv += Math.Log(x[i]);

    a = tempv / x.Count;

    if(Double.IsNaN(a))
      return;

    if(Double.IsInfinity(a))
      return;

    A = Math.Pow(Math.E, a);

  }

Passo 3 (Step 3): O código abaixo permite calcular o valor de lambda. Necessita de um parâmetro a, um valor entre 0 e 1. Um valor adequado é 0,5. Se for usado 0, o efeito de lambda é anulado e a função passa a ser um KDE normal.

private void RunScript(List x, double g, double a, ref object A)
  {
    if (g <= 0)
      return;
    if (a < 0 || a > 1)
      return;
    if (x.Count == 0)
      return;

    List lambda = new List();
    for(int i = 0; i < x.Count; i++)
      lambda.Add(Math.Pow((x[i] / g), -a));

    A = lambda;
  }

Passo 4 (Step 4): O último passo implementa a função KDE adaptativo que calcula as estimativas ajustadas à densidade real.

private void RunScript(Mesh mesh, List pts, double window, List lambda, ref object A)
  {
    var rtnlist = new List();
    for(int i = 0; i < mesh.Vertices.Count; i++)
      {
       double l = lambda[i];
       double tempval = 0.0;
       double kde = 0.0;
       Point3d v = new Point3d(mesh.Vertices[i]);
       for(int j = pts.Count - 1; j > 0; j--)	
        {		
         var pt = pts[j];		
         Vector3d vt = new Vector3d(v - pt);		
         tempval += kernel(vt / (window * l)) / ((window * window) * (l * l));	
        }	
       kde = 1.0 / pts.Count * tempval;	
       rtnlist.Add(kde);
      }
    
    A = rtnlist;
  }

  public double kernel(Vector3d input)
  {   
    //Epanechnikov Kernel
    double k = Vector3d.Multiply(input, input);
    if ( k < 1)
    {
      return 3 * (1 / Math.PI) * (1 - k) * (1 - k);
    }else{
      return 0;
    }
  }

Leave a Reply

O seu endereço de email não será publicado. Campos obrigatórios marcados com *

11 + 13 =


@