Получите эквивалент » bs` (сплайны) в Python

#python #r #scipy #spline #bspline

Вопрос:

На r языке программирования следующие

 require(stats)
require(splines)
knots = quantile(women$height, seq(0.1,0.9,length.out = 5))
bs(women$height, knots=knots, degree=3)
 

ВОЗВРАТ

 1   2   3   4   5   6   7   8
0.0000000000    0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.0000000000    0.00000000
0.6284418529    0.323939099 0.024295432 0.000000000 0.000000000 0.000000000 0.0000000000    0.00000000
0.2155814707    0.599894720 0.182883868 0.001639942 0.000000000 0.000000000 0.0000000000    0.00000000
0.0349854227    0.495626822 0.438289602 0.031098154 0.000000000 0.000000000 0.0000000000    0.00000000
0.0001619695    0.245586330 0.620809038 0.133442663 0.000000000 0.000000000 0.0000000000    0.00000000
0.0000000000    0.072886297 0.584548105 0.338678328 0.003887269 0.000000000 0.0000000000    0.00000000
0.0000000000    0.009110787 0.384718173 0.561892614 0.044278426 0.000000000 0.0000000000    0.00000000
0.0000000000    0.000000000 0.166666667 0.666666667 0.166666667 0.000000000 0.0000000000    0.00000000
0.0000000000    0.000000000 0.044278426 0.561892614 0.384718173 0.009110787 0.0000000000    0.00000000
0.0000000000    0.000000000 0.003887269 0.338678328 0.584548105 0.072886297 0.0000000000    0.00000000
0.0000000000    0.000000000 0.000000000 0.133442663 0.620809038 0.245586330 0.0001619695    0.00000000
0.0000000000    0.000000000 0.000000000 0.031098154 0.438289602 0.495626822 0.0349854227    0.00000000
0.0000000000    0.000000000 0.000000000 0.001639942 0.182883868 0.599894720 0.2155814707    0.00000000
0.0000000000    0.000000000 0.000000000 0.000000000 0.024295432 0.323939099 0.6284418529    0.02332362
0.0000000000    0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.0000000000    1.00000000
 

Существует ли эквивалент Python? Я пробовал BSpline от scipy , но для этого требуется, чтобы коэффициенты уже были известны и передавались.

Как я могу просто сгенерировать базовую матрицу B-сплайна, передав массив, узлы и степень?


Чтобы воспроизвести входной Python, вы можете сделать:

 import numpy as np

women_height = np.array([58,59,60,61,62,63,64,65,66,67,68,69,70,71,72])
knots = array([59.4, 62.2, 65. , 67.8, 70.6])
 

Комментарии:

1. BSpline.design_matrix будет доступен в scipy 1.8, когда он будет выпущен. Между тем, вы можете использовать мастер-ветвь scipy

Ответ №1:

Превращение комментария в ответ- BSpline.design_matrix это построение того, что вам нужно, в разреженном формате csr. Он будет доступен с scipy 1.8, когда он будет выпущен. До тех пор вы можете либо захватить главную ветвь scipy, либо воспользоваться обходным путем, предложенным в документах (https://scipy.github.io/devdocs/reference/generated/scipy.interpolate.BSpline.design_matrix.html#scipy.интерполировать.BSpline.design_matrix) :

 t = ... 
c = np.eye(len(t) - k - 1)
design_matrix_gh = BSpline(t, c, k)(x)
 

ПРАВКА: документация R, https://www.rdocumentation.org/packages/splines/versions/3.6.2/topics/bs, утверждает, что knots аргумент является внутренним узлом. scipy’s BSpline не накладывает узлы автоматически, поэтому вам нужно сделать это самостоятельно. Использование данных OP:

 In [22]: women_height = np.array([58,59,60,61,62,63,64,65,66,67,68,69,70,71,72])
    ...: knots = np.array([59.4, 62.2, 65. , 67.8, 70.6])

In [23]: t = np.r_[(58,)*4, knots, (72,)*4]   # <<<<<< here

In [24]: m = BSpline.design_matrix(women_height, t, k=3)

In [25]: with np.printoptions(linewidth=120, precision=5):
    ...:     print(m.toarray())
    ...:
[[1.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00]
 [2.33236e-02 6.28442e-01 3.23939e-01 2.42954e-02 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00]
 [0.00000e 00 2.15581e-01 5.99895e-01 1.82884e-01 1.63994e-03 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00]
 [0.00000e 00 3.49854e-02 4.95627e-01 4.38290e-01 3.10982e-02 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00]
 [0.00000e 00 1.61970e-04 2.45586e-01 6.20809e-01 1.33443e-01 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00]
 [0.00000e 00 0.00000e 00 7.28863e-02 5.84548e-01 3.38678e-01 3.88727e-03 0.00000e 00 0.00000e 00 0.00000e 00]
 [0.00000e 00 0.00000e 00 9.11079e-03 3.84718e-01 5.61893e-01 4.42784e-02 0.00000e 00 0.00000e 00 0.00000e 00]
 [0.00000e 00 0.00000e 00 0.00000e 00 1.66667e-01 6.66667e-01 1.66667e-01 0.00000e 00 0.00000e 00 0.00000e 00]
 [0.00000e 00 0.00000e 00 0.00000e 00 4.42784e-02 5.61893e-01 3.84718e-01 9.11079e-03 0.00000e 00 0.00000e 00]
 [0.00000e 00 0.00000e 00 0.00000e 00 3.88727e-03 3.38678e-01 5.84548e-01 7.28863e-02 0.00000e 00 0.00000e 00]
 [0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 1.33443e-01 6.20809e-01 2.45586e-01 1.61970e-04 0.00000e 00]
 [0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 3.10982e-02 4.38290e-01 4.95627e-01 3.49854e-02 0.00000e 00]
 [0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 1.63994e-03 1.82884e-01 5.99895e-01 2.15581e-01 0.00000e 00]
 [0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 2.42954e-02 3.23939e-01 6.28442e-01 2.33236e-02]
 [0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 0.00000e 00 1.00000e 00]]

 

что похоже на вывод R из операции по модулю первого столбца. Из документов R не сразу понятно, как именно он заполняет вектор узлов, но если вы хотите получить тот же результат, вы можете просто отрезать первый столбец ( m.toarray()[1:, :] или что-то в этом роде).

Комментарии:

1. Как я могу использовать это для воспроизведения приведенного выше результата?

2. Заткните узлы, которые вы получили от R

3. Это дает ошибку значения: ValueError: Out of bounds w/ x = [58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72.].

4. Как я уже сказал, можете ли вы добавить узлы из R к вопросу

5. отлично, спасибо! t = np.hstack([58, 58, 58, 58, knots, 72, 72, 72, 72]); pd.DataFrame(BSpline(t, np.eye(len(t) - 3 - 1), 3)(heights)[:, 1:]) также работает