Нелинейная аппроксимация данных
В данном примере мы рассмотрим, как аппроксимировать нелинейную функцию по данным с использованием различных алгоритмов Julia.
Присоединим необходимые библиотеки:
Задача состоит в аппроксимации функции по следующим данным:
Построим график точек данных:
Попробуем аппроксимировать функцию к данным на графике.
Решение с помощью функции curve_fit
Чтобы аппроксимировать функцию к данным с помощью curve_fit, сопоставим параметры в функции с переменной x следующим образом:
x(1) =
x(2) =
x(3) =
x(4) =
Определим функцию для аппроксимации:
Произвольно зададим начальную точку x0 следующим образом:
Запустим функцию curve_fit и построим график полученной аппроксимации:
[3.0068987272691983, 10.586437798894883, 2.8890341644746096, 1.4003175885557395]
Время вычисления: 0.002053976058959961 секунд
Решение с помощью функции optimize
Чтобы решить задачу с помощью optimize, определим целевую функцию как сумму квадратов остатков:
[2.8890341327114255, 1.4003175757616197, 3.0068987558767297, 10.586437572259701]
Время вычисления: 0.04426288604736328 секунд
Заметим, что optimize находит то же решение, что и curve_fit, но требует значительно больше времени для вычислений. Так как порядок переменных произвольный, результаты вычислений расположены в ином порядке.
Разделение линейной и нелинейной задач
Заметим, что задача аппроксимации линейна по параметрам и . Это означает, что для любых значений и можно использовать оператор обратного деления для нахождения значений c₁ и c₂, решающих задачу наименьших квадратов.
Переформулируем задачу как двумерную, выполняя поиск оптимальных значений и . Значения и вычисляются на каждом шаге с использованием оператора обратного деления.
Решим задачу с использованием curve_fit, начиная с двумерной начальной точки [1, 0]:
[10.5864375304706, 1.400317572907302]
Разделённая задача наиболее устойчива к начальному приближению
Выбор неудачной начальной точки для исходной задачи с четырьмя параметрами приводит к локальному решению, которое не является глобальным. Однако выбор начальной точки с такими же неудачными значениями λ₁ и λ₂ для разделённой задачи с двумя параметрами, приводит к глобальному решению. Чтобы продемонстрировать этот результат, перезапустим исходную задачу с начальной точкой, которая приводит к относительно неудачному локальному решению, и сравним полученную аппроксимацию с глобальным решением.
[5.875979032555211, 2.4785902042541337, -0.7523543061281264, 2.4785903664742834]
Время вычисления: 0.0038368701934814453 секунд
Остаточная норма в удачной конечной точке: 0.14772257123485094;
Остаточная норма в неудачной конечной точке 2.2172997805818286.
Данный пример демонстрирует ключевые аспекты нелинейной аппроксимации данных с использованием методов оптимизации:
-
Эффективность специализированных алгоритмов - функция curve_fit, предназначенная специально для задач аппроксимации кривых, показала значительно более высокую эффективность по сравнению с функцией optimize, требуя меньшего количества вычислений целевой функции для достижения того же результата.
-
Важность разделения параметров - выделение линейных параметров задачи позволяет существенно упростить исходную четырехпараметрическую задачу до двумерной, что не только сохраняет эффективность вычислений, но и повышает устойчивость метода.
-
Устойчивость к начальным приближениям - разделённая формулировка задачи продемонстрировала повышенную надёжность, позволяя избегать локальных минимумов и находить глобальное решение даже при неудачном выборе начальных значений параметров.
-
Практическая значимость - представленные подходы имеют широкую применимость в различных областях, где требуется точная аппроксимация экспериментальных данных сложными нелинейными моделями, включая химическую кинетику, биологические процессы и физические эксперименты.
Метод разделения линейных и нелинейных параметров представляет особую ценность, поскольку сочетает вычислительную эффективность с повышенной надёжностью сходимости к глобальному решению, что делает его предпочтительным выбором для решения практических задач нелинейной аппроксимации.
{"id": "id_692d0d5d_654f_4b90_a5fc_1bbc0128e7a7", "data": [{"xaxis": "x", "colorbar": {"y": 0.48958333333333337, "title": {"text": ""}, "len": 0.9039260717410325, "x": 0.9934383202099737}, "yaxis": "y", "x": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2], "showlegend": true, "mode": "markers", "name": "y1", "legendgroup": "y1", "marker": {"symbol": "circle", "color": "rgba(255, 255, 255, 1.000)", "line": {"color": "rgba(0, 0, 255, 1.000)", "width": 1}, "size": 8}, "y": [5.8955, 3.5639, 2.5173, 1.979, 1.899, 1.3938, 1.1359, 1.0096, 1.0343, 0.8435, 0.6856, 0.61, 0.5392, 0.3946, 0.3903, 0.5474, 0.3459, 0.137, 0.2211, 0.1704, 0.2636], "type": "scatter"}], "config": {"showlegend": false, "xaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0, 0.5, 1, 1.5, 2], "range": [-0.06000000000000005, 2.06], "domain": [0.02137649460484106, 0.9934383202099737], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0.0", "0.5", "1.0", "1.5", "2.0"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "y", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "paper_bgcolor": "rgba(255, 255, 255, 1.000)", "annotations": [{"yanchor": "top", "xanchor": "center", "rotation": 0, "y": 1, "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 20}, "yref": "paper", "showarrow": false, "text": "Точки данных", "xref": "paper", "x": 0.5074074074074074}], "height": 400, "margin": {"l": 0, "b": 20, "r": 0, "t": 20}, "plot_bgcolor": "rgba(255, 255, 255, 1.000)", "yaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0, 1, 2, 3, 4, 5, 6], "range": [-0.03575499999999954, 6.068255000000001], "domain": [0.03762029746281716, 0.9415463692038496], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0", "1", "2", "3", "4", "5", "6"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "x", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "width": 980.5}}
{"id": "id_279d738c_78a1_491d_847f_fab7547ff51d", "data": [{"xaxis": "x", "colorbar": {"y": 0.48958333333333337, "title": {"text": ""}, "len": 0.9039260717410325, "x": 0.9934383202099737}, "yaxis": "y", "x": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2], "showlegend": true, "mode": "markers", "name": "Точки данных", "legendgroup": "Точки данных", "marker": {"symbol": "circle", "color": "rgba(255, 255, 255, 1.000)", "line": {"color": "rgba(0, 0, 255, 1.000)", "width": 1}, "size": 8}, "y": [5.8955, 3.5639, 2.5173, 1.979, 1.899, 1.3938, 1.1359, 1.0096, 1.0343, 0.8435, 0.6856, 0.61, 0.5392, 0.3946, 0.3903, 0.5474, 0.3459, 0.137, 0.2211, 0.1704, 0.2636], "type": "scatter"}, {"xaxis": "x", "colorbar": {"y": 0.48958333333333337, "title": {"text": ""}, "len": 0.9039260717410325, "x": 0.9934383202099737}, "yaxis": "y", "x": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2], "showlegend": true, "mode": "lines", "name": "Аппроксимация", "legendgroup": "Аппроксимация", "line": {"color": "rgba(0, 0, 255, 1.000)", "shape": "linear", "dash": "solid", "width": 2}, "y": [5.895932891743808, 3.5546972249389106, 2.5452496263002584, 2.0236035126312792, 1.6935907003710566, 1.4495354540485965, 1.2522313285952176, 1.0858643293998098, 0.9430249856657108, 0.8194708757887617, 0.7122767738470783, 0.6191643407722397, 0.5382447603978944, 0.4679078795649593, 0.4067649933082507, 0.35361269157283076, 0.3074061431531151, 0.2672375056984087, 0.23231772412663573, 0.20196090422420013, 0.1755707964115053], "type": "scatter"}], "config": {"showlegend": true, "xaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0, 0.5, 1, 1.5, 2], "range": [-0.06000000000000005, 2.06], "domain": [0.02137649460484106, 0.9934383202099737], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0.0", "0.5", "1.0", "1.5", "2.0"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "y", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "paper_bgcolor": "rgba(255, 255, 255, 1.000)", "annotations": [{"yanchor": "top", "xanchor": "center", "rotation": 0, "y": 1, "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 20}, "yref": "paper", "showarrow": false, "text": "Аппроксимация", "xref": "paper", "x": 0.5074074074074074}], "height": 400, "margin": {"l": 0, "b": 20, "r": 0, "t": 20}, "plot_bgcolor": "rgba(255, 255, 255, 1.000)", "yaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0, 1, 2, 3, 4, 5, 6], "range": [-0.03576798675231396, 6.068700878496122], "domain": [0.03762029746281716, 0.9415463692038496], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0", "1", "2", "3", "4", "5", "6"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "x", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "legend": {"yanchor": "auto", "xanchor": "auto", "bordercolor": "rgba(0, 0, 0, 1)", "bgcolor": "rgba(255, 255, 255, 1.000)", "borderwidth": 1, "tracegroupgap": 0, "y": 1, "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "title": {"font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}, "text": ""}, "traceorder": "normal", "x": 1}, "width": 980.5}}
{"id": "id_089a42d9_e053_4dd6_87a1_fa08b3496cab", "data": [{"xaxis": "x", "colorbar": {"y": 0.48958333333333337, "title": {"text": ""}, "len": 0.9039260717410325, "x": 0.9934383202099737}, "yaxis": "y", "x": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2], "showlegend": true, "mode": "markers", "name": "Данные", "legendgroup": "Данные", "marker": {"symbol": "circle", "color": "rgba(255, 255, 255, 1.000)", "line": {"color": "rgba(0, 0, 255, 1.000)", "width": 1}, "size": 8}, "y": [5.8955, 3.5639, 2.5173, 1.979, 1.899, 1.3938, 1.1359, 1.0096, 1.0343, 0.8435, 0.6856, 0.61, 0.5392, 0.3946, 0.3903, 0.5474, 0.3459, 0.137, 0.2211, 0.1704, 0.2636], "type": "scatter"}, {"xaxis": "x", "colorbar": {"y": 0.48958333333333337, "title": {"text": ""}, "len": 0.9039260717410325, "x": 0.9934383202099737}, "yaxis": "y", "x": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2], "showlegend": true, "mode": "lines", "name": "Удачные параметры", "legendgroup": "Удачные параметры", "line": {"color": "rgba(0, 0, 255, 1.000)", "shape": "linear", "dash": "solid", "width": 2}, "y": [5.895932891743808, 3.5546972249389106, 2.5452496263002584, 2.0236035126312792, 1.6935907003710566, 1.4495354540485965, 1.2522313285952176, 1.0858643293998098, 0.9430249856657108, 0.8194708757887617, 0.7122767738470783, 0.6191643407722397, 0.5382447603978944, 0.4679078795649593, 0.4067649933082507, 0.35361269157283076, 0.3074061431531151, 0.2672375056984087, 0.23231772412663573, 0.20196090422420013, 0.1755707964115053], "type": "scatter"}, {"xaxis": "x", "colorbar": {"y": 0.48958333333333337, "title": {"text": ""}, "len": 0.9039260717410325, "x": 0.9934383202099737}, "yaxis": "y", "x": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2], "showlegend": true, "mode": "lines", "name": "Неудачные параметры", "legendgroup": "Неудачные параметры", "line": {"color": "rgba(255, 0, 0, 1.000)", "shape": "linear", "dash": "solid", "width": 2}, "y": [5.123624726427085, 3.9988352247684267, 3.120970798733676, 2.435823978496736, 1.9010874618330487, 1.483741669941717, 1.1580158132223626, 0.9037965643478392, 0.705386075388684, 0.5505326474783473, 0.42967419759811776, 0.3353478071231869, 0.2617288921954638, 0.20427154003932743, 0.1594278022575979, 0.12442861167930816, 0.09711279453896007, 0.07579361961758985, 0.05915464385520517, 0.046168422979288186, 0.03603306759164787], "type": "scatter"}], "config": {"showlegend": true, "xaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0, 0.5, 1, 1.5, 2], "range": [-0.06000000000000005, 2.06], "domain": [0.02137649460484106, 0.9934383202099737], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0.0", "0.5", "1.0", "1.5", "2.0"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "y", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "paper_bgcolor": "rgba(255, 255, 255, 1.000)", "annotations": [{"yanchor": "top", "xanchor": "center", "rotation": 0, "y": 1, "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 20}, "yref": "paper", "showarrow": false, "text": "Аппроксимация", "xref": "paper", "x": 0.5074074074074074}], "height": 400, "margin": {"l": 0, "b": 20, "r": 0, "t": 20}, "plot_bgcolor": "rgba(255, 255, 255, 1.000)", "yaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0, 1, 2, 3, 4, 5, 6], "range": [-0.1397639271329174, 6.071729886468373], "domain": [0.03762029746281716, 0.9415463692038496], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0", "1", "2", "3", "4", "5", "6"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "x", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "legend": {"yanchor": "auto", "xanchor": "auto", "bordercolor": "rgba(0, 0, 0, 1)", "bgcolor": "rgba(255, 255, 255, 1.000)", "borderwidth": 1, "tracegroupgap": 0, "y": 1, "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "title": {"font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}, "text": ""}, "traceorder": "normal", "x": 1}, "width": 980.5}}