Страницы: Пред. 1 2
RSS
Аппроксимация полиномом в MS Excel., Сравнение разных способов аппроксимации полиномом. Низкое "качество" аппроксимации встроенной функцией ЛИНЕЙН.
 
Цитата
tutochkin написал:
Читайте не через строчку - давал вариант. Урезанный правда, только с линейным вариантом, но давал.

Простите великодушно, я и Яндекс не местные и не знакомы с вашими трудами.
Можно нам прямую ссылку?




Цитата
tutochkin написал:
У как всё запущено... А ещё на глаз погрешности определяете.
Как у Вас интересно..
А я вот не смог воспроизвести ваш эксперимент, у меня, к сожалению счастью, всё совпадает до последнего знака!


Так у кого что запущено?
;)
А Вы всё о глазах и о глазах...
Я уже давал комментарий, что считаю погрешностью аппроксимации, не поленюсь, процитирую:

Цитата
Алексей Назаров написал:
Под погрешностью аппроксимации я имею в виду максимальную разницу между любой точкой экспериментальных данных и соответствующей точкой, вычисленной по полиному, построенному по этим данным.

Конечно, это не стандартизованная методика, но вполне адекватная и имеющая право на жизнь.
Хотя, слово методика слишком громкое для модуля разности двух чисел.
Можно ещё и дисперсию посчитать.
И, обратите внимание, я написал "...я имею в виду...".

Если Вы несогласны и знаете, как поступить лучше - пожалуйста, поделитесь, а не тыкайте голословно в глаз.


Цитата
tutochkin написал:
А зачем сменили Имя-фамилию на ник?


А Вы почему пользуетесь ником?  ;)

Я уже писал, что неместный, я только-только зарегистрировался на этом форуме, и не ожидал, что вместо логина будет отображаться имя и фамилия. Зашёл в настройки профиля и снял галочку.  
 
Цитата
МатросНаЗебре написал:
Вариант, вычисляющий коэффициенты через решение системы линейных уравнений. Точность хуже, чем у метода, через уравнение из линии тренда.
Подскажите, а у Вас вариант с линией тренда нормально выполняется, не требует "плясок с бубном" перед считыванием уравнения?  
Изменено: alenco - 09.12.2021 13:31:58
 
alenco,  вопрос по смене отображаемого имени не праздный: меня его в пределах одной темы, Вы вносите неразбериху. Менять следовало ПОСЛЕ закрытия обсуждения. Т.е. все последующие темы м сообщения в них  пойдут под новым ником.
 
Цитата
alenco написал:
Простите великодушно, я и Яндекс не местные и не знакомы с вашими трудами.Можно нам прямую ссылку?
В третьем посте ссылка на решение аналогичной проблемы А вы по ней даже не удосужились пройти
Цитата
alenco написал:
А я вот не смог воспроизвести ваш эксперимент, у меня, к сожалению счастью, всё совпадает до последнего знака!
Только макрос Матроса в ячейку начиная с Е заливает результат... А то что вы что то куда то скопировали - это ваше личное дело.
Цитата
alenco написал:
А Вы почему пользуетесь ником?
Я не против ника, просто общался с одним, тут влезает другой... Потребовалось время чтобы понять.
 
Цитата
написал:
вариант с линией тренда нормально выполняется, не требует "плясок с бубном" перед считыванием уравнения?
Иногда не срабатывал. В этом случае останавливал код перед считыванием, тогда работал. Глюк какой-то.
 
Цитата
Юрий М написал:
alenco ,  вопрос по смене отображаемого имени не праздный: меня его в пределах одной темы, Вы вносите неразбериху.

Цитата
tutochkin написал:
Я не против ника, просто общался с одним, тут влезает другой... Потребовалось время чтобы понять.

Извиняюсь, не подумал.

Цитата
tutochkin написал:
В третьем посте ссылка на решение аналогичной проблемы  А вы по ней даже не удосужились пройти
Сейчас посмотрел ещё раз.
Извините, но я наверное, слепой, т.к. kus_interp не вижу нигде...
Да и поиск не находит.

Цитата
tutochkin написал:
Только макрос Матроса в ячейку начиная с Е заливает результат... А то что вы что то куда то скопировали - это ваше личное
А для Вас сложно поменять адрес ячейки в макросе?
Уверен, что нет.
Или Вы думаете, что я не в состоянии это сделать?
Я сделал, как мне удобно. И, поверьте, пишет это именно макрос.

Вот с безостановочным выполнением есть заморочка, не отрицаю, аналогично и моему, ранее приведённому примеру.
И обновлять все элементы пробовал, и Select, и Do evenrs, но увы, безупречной работы не добился.

Макросы Матроса построены значительно грамотнее моего (я писал на VBA 10-13 лет назад, и напрочь всё забыл), но с его кодом на моей системе та же проблема..
Возможно, Вы что-то предложите?

Прошу Вас, пожалуйста, не предлагать кусочно-линейную, даже если она и даёт в каких-то случаях хороший результат.
Я про неё знаю и кое-где использовал ранее.
Есть куча оборудования, ПО для МК и рабочих станций, документов, где уже есть то, что есть, то есть полиномиальная обработка, и менять это - страшный гемор и затраты.
Мне сейчас нужно добить методику расчета коэффициентов полиномов 5-7 порядков, чтобы было удобно и результат не хуже, чем в Матлабе/Октаве или на линии тренда.
 
Цитата
МатросНаЗебре написал:
Иногда не срабатывал. В этом случае останавливал код перед считыванием, тогда работал. Глюк какой-то.

Как я предполагаю, свойство .DataLabel.Text, также, как и .DataLabel.FormulaR1C1, можно считать только с уже существующего объекта, а в процессе выполнения макроса он ещё не создан, и возникает проблема с синхронизацией..
Причем простые временные задержки или Do events не помогают...  :cry:

Это всё не очень страшно, уже в таком виде код можно использовать, но хочется добиться работы в одно нажатие..
 
Цитата
alenco написал:
И, поверьте, пишет это именно макрос.
Не поленился, повторно скачал Ваш файлик, вставил тудой макрос и собственно получил:

Прицепил Ваш файлик собственно с макросом

Цитата
alenco написал:
Мне сейчас нужно добить методику расчета коэффициентов полиномов 5-7 порядков
В данном случае проблема не в методике расчёта а в исходных данных. Если Х имеет порядок 10^7, и аппроксимируется полиномом 6-й степени (т.е. 10^7^6) то возникают просто проблемы с памятью.
О методах расчёта можете почитать, например, здесь http://alexeypetrov.narod.ru/progs.html#sqr_less

Цитата
alenco написал:
Сейчас посмотрел ещё раз.Извините, но я наверное, слепой, т.к. kus_interp не вижу нигде...
Вы по ссылке перешли? Тогда смотрите мой пост с прицепленным файлом... Там собственно и макрос и его применение.
Изменено: tutochkin - 09.12.2021 14:18:03
 
Цитата
написал:
в таком виде код можно использовать, но хочется добиться работы в одно нажатие
А так?
Код
Option Explicit
'v2
Sub Polynomial()
    Dim rX As Range
    Dim rY As Range
    Dim rOut As Range
    Set rX = ActiveSheet.Range("B4:B68")
    Set rY = ActiveSheet.Range("C4:C68")
    Set rOut = ActiveSheet.Range("E4")
    
    Dim dataLabelText As String
    dataLabelText = GetDataLabelText(rX, rY)
    Dim coefficients As Variant
    coefficients = GetCoefficients(dataLabelText)
    
    rOut.Resize(UBound(coefficients, 1), UBound(coefficients, 2)) = coefficients
End Sub

Private Function GetCoefficients(dataLabelText As String) As Variant
    Dim txt As String
    txt = dataLabelText
    txt = Replace(txt, "y = ", "")
    Dim arr As Variant
    arr = Split(txt, " ")
    Dim brr As Variant
    Dim dic As Object
    Set dic = CreateObject("Scripting.Dictionary")
    Dim ii As Integer
    For ii = LBound(arr) To UBound(arr)
        Select Case arr(ii)
        Case "+", "-"
        Case Else
            brr = Split(arr(ii), "x")
            If UBound(brr) = 0 Then
                ReDim brr(0 To 1)
                brr(0) = arr(ii)
                brr(1) = "0"
            Else
                If ii > 0 Then
                    brr(0) = arr(ii - 1) & brr(0)
                End If
                If brr(1) = "" Then brr(1) = "1"
            End If
            dic.Item(brr(1)) = brr(0)
        End Select
    Next
    
    Dim orr As Variant
    If dic.Count = 0 Then
        ReDim orr(1 To 1, 1 To 2)
    Else
        arr = dic.Keys()
        brr = dic.Items()
        Set dic = Nothing
        ReDim orr(1 To UBound(arr) - LBound(arr) + 1, 1 To 2)
        Dim jj As Integer
        For ii = UBound(arr) To LBound(arr) Step -1
            jj = jj + 1
            orr(jj, 1) = arr(ii)
            orr(jj, 2) = CDbl(brr(ii))
        Next
    End If
    GetCoefficients = orr
End Function

Function GetDataLabelText(rX As Range, rY As Range) As String
    If rX.Rows.Count = 1 Then Exit Function
    Dim arX As Variant
    Dim arY As Variant
    arX = rX.Columns(1)
    arY = rY.Cells(1, 1).Resize(UBound(arX, 1), 1)
    
'    Application.ScreenUpdating = False
    
    Dim wb As Workbook
    Set wb = Workbooks.Add(1)
    With ActiveSheet
        .Cells(1, 1).Resize(UBound(arX, 1), 1) = arX
        .Cells(1, 2).Resize(UBound(arX, 1), 1) = arY
        
        .Shapes.AddChart2(240, xlXYScatter).Select
        With ActiveChart
            .SetSourceData Source:=Cells(1, 1).Resize(UBound(arX, 1), 2) 'Range("Лист1!$A$1:$B$3")
            .FullSeriesCollection(1).Trendlines.Add
            With .FullSeriesCollection(1).Trendlines(1)
                .Type = xlPolynomial
                .Order = 2
                .Type = xlPolynomial
                .Order = 6
                .DisplayEquation = True
                .DataLabel.NumberFormat = "# ##0,00000000000000000000000000000000000000000000000000000000000000000000000000"
                Dim dt As Date
                dt = Now
                Do
                    If .DataLabel.Text <> "" Then Exit Do
                    If dt < Now - TimeSerial(0, 1, 0) Then Exit Do
                    DoEvents
                    Application.Wait Now + TimeSerial(0, 0, 1)
                Loop
                GetDataLabelText = .DataLabel.Text
            End With
        End With
    End With
    wb.Close False
    
    Application.ScreenUpdating = True
End Function
 
МатросНаЗебре, Вопрос к тебе, как к автору вытаскивания данных.
Итак, при первом запуске макроса значения выдаются верные. При повторных запусках - идёт сдвиг регистра. Собственно файл прилагаю.
 
У меня xlsm и xlsb не скачиваются. Проблема на моей стороне.
 
К вопросу о кусочно-линейной интерполяции.
И ещё раз с благодарностью МСН и БМВ
 
Цитата
МатросНаЗебре написал:
У меня xlsm и xlsb не скачиваются. Проблема на моей стороне.
7zip  устроит?
Вообще то я уже докопался - проблема только при таком формате данных. Думаю переделаю распарсивание и будет счастье. Однако может и не прав.

Странно... Файл меньше 100 кб...
Изменено: tutochkin - 09.12.2021 15:45:04
 
Цитата
написал:
Вообще то я уже докопался
Значит и зип не нужен )
 
МатросНаЗебре,
В общем я вот так распарсил
Код
Private Function GetCoefficients2(dataLabelText As String) As Variant
Dim i As Integer
Dim rez() As Variant, txt As Variant
Dim razd As String
txt = Split(dataLabelText, "x")
ReDim rez(LBound(txt) To UBound(txt), 1 To 2)
For i = LBound(txt) To UBound(txt)
    txt(i) = Right(txt(i), IIf(i = LBound(txt), (Len(txt(i)) - 2), (Len(txt(i)) - 1)))
    rez(i, 1) = i
    rez(i, 2) = txt(i)
Next i
GetCoefficients2 = rez
End Function

А формат такого вида:
Код
.DataLabel.NumberFormat = "#.############E+00"

# - добавляются по желанию...
Изменено: tutochkin - 09.12.2021 16:28:03
 
Цитата
tutochkin написал:
Не поленился, повторно скачал Ваш файлик, вставил тудой макрос и собственно получил:

Не знаю, почему так, но я неоднократно уже пробовал, всё отлично.
Обратил внимание только, Вас в качестве децимального разделителя точка, у меня запятая.

Цитата
tutochkin написал:
В данном случае проблема не в методике расчёта а в исходных данных. Если Х имеет порядок 10^7, и аппроксимируется полиномом 6-й степени (т.е. 10^7^6) то возникают просто проблемы с памятью
Это известное предположение.
Я писал здесь, что проверял его, уменьшал Х на 6 порядков, всё совпало до 7-8-го знака, изменились только порядки. Общая форма кривой ПХ и, соответственно, ошибки аппроксимации, в точности совпали.
А вообще, емнип, Double подразумевает числа до 10Е+308 примерно при 16 полных разрядах.  По моему, должно хватить.. )))

Цитата
tutochkin написал:
Вы по ссылке перешли? Тогда смотрите мой пост с прицепленным файлом... Там собственно и макрос и его применение.
Я не копал настолько глубоко, т.к. содержание сообщения ясно говорило о том, что ответа на мой вопрос в содержимом нет, только альтернативное решение.
Буду иметь в виду.

Цитата
МатросНаЗебре написал:
А так?
Благодарю, завтра посмотрю.
Интересный цикл..

Цитата
tutochkin написал:
А формат такого вида:
Как я заметил, линия тренда выдаёт максимум 14 знаков, если поставить больше - остальные будут нули.
 
Цитата
alenco написал:
А вообще, емнип, Double подразумевает числа до 10Е+308 примерно при 16 полных разрядах.  По моему, должно хватить.. )))
Ну вот пример определения коэффициентов влоб. Заметьте какие порядки получаются для полинома 5-й степени просто при Х и У до 10ки и 10 точках. Можете подставить свои значения и своё количество точек...
 
Урря!
Заработало!!!
Всем благодарю!

Не знаю, на всех ли системах это сработает, но сейчас у меня работает без проблем, будем пробовать дальше.
Итак, по порядку.

Цитата
МатросНаЗебре написал:
А так?

Попробовал, при запуске создаётся вспомогательный файл с графиком, висит ровно минуту, после чего закрывается и... всё..((
Если тормознуть перед считыванием, то на графике появляется уравнение тренда и, после продолжения, всё нормально.
То есть, фактически, ничего радикально не поменялось.

Цитата
tutochkin написал:
Вы по ссылке перешли? Тогда смотрите мой пост с прицепленным файлом... Там собственно и макрос и его применение.
Как я уже сказал, так глубоко я не копал, глянул по диагонали.

А вот из этого сообщения файл Копия Сравнение способов аппроксимации 6 пор (урезан)-2.xlsm (283.21 КБ) показал интересный результат - в нём извлечение коэффициентов работает без проблем!
При первом взгляде это был код МатросаНаЗебре без каких-либо серьёзных изменений, но он работал!
И он работает при переносе в другие файлы.
Отличие оказалось в том, что у Вас перед считыванием уравнения DoEvents повторяется дважды!!
DoEvents  я изначально проверял, но у меня и мысли не было попробовать его поставить дважды.
:D  :D  :D

Ещё раз большое спасибо!!


Теперь осталось отшлифовать мелочи для удобства (кнопки на панель, возможность задания области исходных данных выделением и автоматическим поиском границ диапазона и т.п.).


Цитата
tutochkin написал:
Ну вот пример определения коэффициентов влоб. Заметьте какие порядки получаются для полинома 5-й степени просто при Х и У до 10ки и 10 точках. Можете подставить свои значения и своё количество точек...

Пробовал подставлять числа из своей выборки, ничего фатального не заметил.
Но я пока только 10 точек ставил, позже проверю на большой выборке.
 
Вот так работает пошустрее.
Код
Sub Polynomial()
    Dim rX As Range
    Dim rY As Range
    Dim rOut As Range
    Dim dataLabelText As String
    Dim coefficients As Variant
    
    Set rX = ActiveSheet.Range("B2:B8") ' Данные Х
    Set rY = ActiveSheet.Range("C2:C8") ' Данные Y

    Set rOut = ActiveSheet.Range("E2")
    
    dataLabelText = Извлечение_Полинома(rX, rY)
    coefficients = Извлечение_коэффициентов(dataLabelText)
    rOut.Resize(UBound(coefficients, 1) + 1, UBound(coefficients, 2)) = coefficients
End Sub
 
Private Function Извлечение_коэффициентов(dataLabelText As String) As Variant
Dim i As Integer
Dim rez() As Variant, txt As Variant
txt = Split(dataLabelText, "x")
ReDim rez(LBound(txt) To UBound(txt), 1 To 2)
For i = LBound(txt) To UBound(txt)
    txt(i) = Right(txt(i), IIf(i = LBound(txt), (Len(txt(i)) - 2), (Len(txt(i)) - 1)))
    rez(i, 1) = i: rez(i, 2) = txt(i)
Next i
Извлечение_коэффициентов = rez
End Function

Function Извлечение_Полинома(rX As Range, rY As Range) As String
    Dim MyChart As Chart
    Dim text As String
    Dim dt As Date
    Set MyChart = ActiveSheet.Shapes.AddChart2(, , , , 450, 300).Chart
    With MyChart
        .SeriesCollection.NewSeries
        .SeriesCollection(1).XValues = rX
        .SeriesCollection(1).Values = rY
        .ChartType = xlXYScatter
        .FullSeriesCollection(1).Trendlines.Add
        With .FullSeriesCollection(1).Trendlines(1)
            .Type = xlPolynomial
            .Order = 6 ' Указываем степень полинома
            DoEvents
            .DisplayEquation = True
            .DataLabel.NumberFormat = "#.####E+00"
            dt = Now
            DoEvents
            DoEvents
            text = .DataLabel.text
        End With
    End With
    Извлечение_Полинома = text
    MyChart.Parent.Delete
End Function


Однако на некоторых компах (с одним и тем же дистрибутивом офиса) ругается на
Код
rOut.Resize(UBound(coefficients, 1) + 1, UBound(coefficients, 2)) = coefficients

Причина мне непонятна, но т.к. делал ради спортивного интереса - не вникал.
 
Думаю, так чуть правильнее(не везде хватит двух DoEvents). Плюс убрал ошибку вставки(про которую писалось, что на некоторых ПК возникает): она будет возникать всегда, если формат ячеек, в которые вставляем результат - Общий и при попытке преобразования в формулу будет ошибка вычисления этой формулы:
Код
Sub Polynomial()
    Dim rX As Range
    Dim rY As Range
    Dim rOut As Range
    Dim dataLabelText As String
    Dim coefficients As Variant
    
    Set rX = ActiveSheet.Range("B2:B6")
    Set rY = ActiveSheet.Range("C2:C6")
    Set rOut = ActiveSheet.Range("E2")
     

    dataLabelText = Извлечение_Полинома(rX, rY)
    coefficients = Извлечение_коэффициентов(dataLabelText)
    With rOut.Resize(UBound(coefficients, 1) + 1, UBound(coefficients, 2))
        .NumberFormat = "@" 'назначаем текстовый формат для избежания ошибок при вставке получившихся формул
        .Value = coefficients
    End With
End Sub
 
Private Function Извлечение_коэффициентов(dataLabelText As String) As Variant
Dim i As Integer
Dim rez() As Variant, txt As Variant
Dim razd As String
txt = Split(dataLabelText, "x")

ReDim rez(LBound(txt) To UBound(txt), 1 To 2)
For i = LBound(txt) To UBound(txt)
    txt(i) = Right(txt(i), IIf(i = LBound(txt), (Len(txt(i)) - 2), (Len(txt(i)) - 1)))
    rez(i, 1) = i
    rez(i, 2) = txt(i)
Next i
Извлечение_коэффициентов = rez
End Function


Function Извлечение_Полинома(rX As Range, rY As Range) As String
    Dim MyChart As Chart
    Dim text As String
    Dim dt As Date
    Dim i&
    
    Set MyChart = ActiveSheet.Shapes.AddChart2(, , , , 450, 300).Chart
    
    MyChart.Parent.Name = "Временная"

    With MyChart
        .SeriesCollection.NewSeries
        .SeriesCollection(1).XValues = rX
        .SeriesCollection(1).Values = rY
        .ChartType = xlXYScatter
        .FullSeriesCollection(1).Trendlines.Add
        With .FullSeriesCollection(1).Trendlines(1)
            .Type = xlPolynomial
            .Order = 2 ' Указываем степень полинома
            .DisplayEquation = True
            .DataLabel.NumberFormat = "#.############E+00"
            dt = Now
            Do
                If .DataLabel.text <> "" Then Exit Do
                If dt < Now - TimeSerial(0, 1, 0) Then Exit Do
                For i = 1 To 100: DoEvents: Next
            Loop
            text = .DataLabel.text
        End With
    End With
    Извлечение_Полинома = text
    MyChart.Parent.Delete
End Function
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий(The_Prist) Щербаков,
Цитата
Дмитрий(The_Prist) Щербаков написал:
Плюс убрал ошибку вставки(про которую писалось, что на некоторых ПК возникает): она будет возникать всегда, если формат ячеек, в которые вставляем результат - Общий
А вот тут не уверен что дело в этом.
Файл один и тот же. Макрос, соответственно, один и тот же. Исходные данные одни и те-же (т.е.работающий файл перекидываю по почте на другой комп, скачиваю, запускаю, разрешаю и клик по кнопке - на части компов работает, на части нет.

Был не прав. Действительно с  .NumberFormat = "@" стало работать...
Поставил .NumberFormat = "#.####E+00"
Изменено: tutochkin - 20.12.2021 12:55:05
 
Цитата
написал:
.DataLabel.NumberFormat = "#.############E+00"
Подскажи пож. как задать формат .DataLabel.NumberFormat = "#.############E+00" чтобы коэфф уравнения которые больше 1 отображались точнее?
Например, 5 и 6 коэфф полинома 2,32034993322507 и 3,96627816142041, а в ячейке у нас 2 и 397 соотв.

Прошу сильно не пинать)  
Страницы: Пред. 1 2
Наверх