KDE adaptativo
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 é difícil quando as amostras contêm zonas com 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 a dimensão 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):
- Encontrar uma estimativa piloto kde(x) que satisfaça kde(Xi)>0 para todos i;
- Calcular a média geométrica de todas as estimativas kde(Xi);
- Calcular o factor de janela local lambda para cada i;
- 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;
}
}
English
Português