Saltar al contenido

Usando FindFit para ajustar $ a , b ^ t $: ¿cómo evitar la introducción de números complejos?

Solución:

La solución

Por lo general, es una muy muy muy muy buena idea trazar los datos para ver qué forma tienen aproximadamente al principio. En su caso, se ve así:

ingrese la descripción de la imagen aquí

… espera, ¡esa no es una función que aumenta exponencialmente! Por supuesto, $ a , b ^ t $ no se ajustará a eso, pero $ a , b ^ {- t} $ podría funcionar, intentemos:

FindFit[data, a*b^(-t), {a, b}, t]
{a -> 100.004, b -> 22099.8}

Tadaa 🙂

Algunas observaciones adicionales

Por supuesto, he utilizado el hecho de que $ b ^ t = left ( frac1b right) ^ {- t} $ aquí. También podría haber encajado con su función, solo que Mathematica eligió inapropiada parámetros iniciales. No sé cómo Mathematica los determina, pero creo que asumir que usa algo alrededor de 1 es razonable. Siempre tengo la impresión de que favorece a los números grandes a los pequeños, pero no contaría con eso.

Puede especificar parámetros de inicio como este:

FindFit[data, a*b^t, {{a, aStart}, {b, bStart}}, t]

Esto le dirá a Mathematica que use aStart y bStart inicialmente; luego continuará modificando levemente estos valores para ver si el ajuste mejora.

“Espere, pero si no conozco estos parámetros en absoluto, ¿cómo puedo encontrar buenos valores iniciales?”, Aquí está uno de los grandes poderes de Mathematica: interactividad fácil. Simplemente codifique un Manipulate entorno donde puede establecer los parámetros usted mismo, así:

Manipulate[
    Show[
        ListLinePlot[data],
        Plot[a b^(-t), {t, 0, .10}, PlotStyle -> Red]
    ],
    {a, 0, 200},
    {b, 0, 50000}
]

ingrese la descripción de la imagen aquí

Aquí puede jugar con los parámetros, hasta que su función (en rojo) coincida aproximadamente con los datos. Lea los valores de los parámetros, utilícelos como valores iniciales, obtenga un ajuste delicioso.

Digamos que descubrió sus parámetros iniciales usando Manipulate o de alguna solución manual (tos). Supongamos que sus valores aproximados son $ a approx 100 $, $ b approxx10 ^ {- 5} $:

FindFit[data, a*b^t, {{a, 100}, {b, 10^(-5)}}, t]
{a -> 100.004, b -> 0.0000452493}

Esa es su solución de libro de texto allí mismo.

Otra cosa que vale la pena mencionar es NonlinearModelFit, el hermano mayor de FindFit. No solo presenta el ajuste, sino que también genera una gran cantidad de datos adicionales para el análisis estadístico, por ejemplo, estimaciones de error de los parámetros y trazados de bandas de confianza. Aquí hay un ejemplo en el que ajusté un conjunto de puntos gaussianos con la curva teórica:

ingrese la descripción de la imagen aquí

Una forma de abordar este problema, y ​​una que creo que funciona bien, es ajustarse a un modelo explícitamente complejo. Si bien este enfoque inicialmente parece innecesario para este problema de valor real, el punto crucial es que, cuando se encuentran valores complejos, se necesita un mecanismo (que FindFit puede manejar sin ninguna dificultad) para penalizar la parte imaginaria no deseada eso no implica cambiar el significado esencial del modelo. Solo agregando Abs o Re-un enfoque común que normalmente funciona razonablemente bien, lo admito- no será suficiente en casos más difíciles. Si no puede dar conjeturas iniciales razonables para los parámetros, es muy probable que el ajuste se desvíe de la línea real y llegue a un mínimo falso en algún lugar del plano complejo.

Es bastante fácil convertir un modelo real en uno complejo automáticamente y, en gran medida, ni siquiera tiene que pensar en ello. He aquí una forma de hacerlo.

Comencemos con su modelo y datos:

data = {
 {0.0, 100.0}, {0.02, 81.87}, {0.04, 67.03},
 {0.06, 54.88}, {0.08, 44.93}, {0.10, 36.76}
};
model = a b^t;

Primero dividimos los datos en componentes separados. Aquí simplemente tomamos las partes real e imaginaria, pero puede elegir la transformación que desee siempre que represente una base completa (no necesariamente ortogonal) y asigne los números complejos a los reales. Sin embargo, debe tener en cuenta que los residuos ahora se calcularán en este espacio, y las diferentes opciones darán lugar a diferentes estimaciones de error en los parámetros. Esto puede ser suficiente (especialmente para un ajuste no lineal) para cambiar los valores óptimos de los propios parámetros, así que elija su transformación sabiamente.

En este punto, es conveniente trabajar con las abscisas y las ordenadas por separado. (Y debo señalar que asumimos aquí un modelo unidimensional, que estamos convirtiendo en uno bidimensional. Se puede usar un enfoque similar para cambiar un modelo norte-complejo dimensional encaja en un norte+ Uno real de 1 dimensión, pero el código diferirá en detalles menores).

transformation = {Re, Im};
{abscissae, ordinates} = Transpose[data];
data = Transpose[{abscissae, #}] & /@ [email protected][ordinates];

Ahora tenemos dos matrices de datos en lugar de una, pero esto no es lo que FindFit necesita (o puede aceptar). Entonces, los fusionamos agregando una variable de índice a cada abscisa:

data = MapIndexed[Prepend[#1, First[#2]] &, data, {2}] ~Flatten~ 1;

A continuación, el modelo debe ampliarse en una dimensión. Esto se puede hacer usando If, Which, Piecewise y así sucesivamente, pero yo personalmente creo KroneckerDelta es más ordenado:

model = Inner[
 #1[model] KroneckerDelta[i, #2] &,
 transformation, [email protected][transformation]
];

Ahora, FindFit obtiene la respuesta correcta de inmediato sin ninguna queja (¡pero no olvide agregar la etiqueta para la dimensión adicional!):

FindFit[data, model, {a, b}, {i, t}]
(* -> {a -> 100.004, b -> 0.0000452493} *)

Obviamente, si este modelo no se limitara a la línea real, también se podría desear transformar los parámetros. Eso se puede hacer, por supuesto, pero creo que es mejor dejarlo como tema para otra respuesta.

Consideré este mismo modelo de regresión en esta respuesta de math.SE. Enunciando brevemente las lecciones de esa respuesta: uno podría considerar realizar una linealización inicial de $ y = ab ^ x $ como $ log , y = log , a + x log , b $ y luego hacer una regresión lineal como de costumbre, pero como expliqué en esa respuesta, una transformación logarítmica distorsionará el error en sus datos originales, de modo que los errores en los transformados ya no necesariamente siguen, digamos, una distribución normal, incluso si el error en sus datos originales fue normalmente distribuido para empezar. (Recuerde que la suposición habitual, a menudo violada, para realizar la regresión es que sus datos tienen un error distribuido normalmente).

Entonces, uno no debe conformarse con los resultados de la linealización. Aquí en Mathematica, debido a la disponibilidad de regresión no lineal en FindFit[] y su primo más elaborado NonlinearModelFit[], ¡uno definitivamente no debería conformarse con los resultados de una linealización! La forma correcta es usar FindFit[] primero para la regresión lineal en los datos transformados, para obtener estimaciones iniciales que luego pueden ser pulidas posteriormente por FindFit[], pero esta vez haciendo regresión no lineal:

data = {{0.0, 100.0}, {0.02, 81.87}, {0.04, 67.03},
        {0.06, 54.88}, {0.08, 44.93}, {0.10, 36.76}};

{a, b} = {Exp[u], Exp[v]} /. 
  FindFit[Transpose[{data[[All, 1]], Log[data[[All, 2]]]}], u + v t, {u, v}, t]
{100.012, 0.0000451495}

{p, q} /. FindFit[data, p q^t, {{p, a}, {q, b}}, t]
{100.004, 0.0000452493}

Se pueden hacer cosas similares para todos los demás modelos de regresión que posean una linealización conveniente.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags : /

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *