У меня есть две переменные (x и y), которые имеют несколько сигмоидальное отношение друг к другу, и мне нужно найти какое-то уравнение предсказания, которое позволит мне предсказать значение y при любом значении x. Мое уравнение предсказания должно показать несколько сигмоидальное соотношение между двумя переменными. Поэтому я не могу согласиться на уравнение линейной регрессии, которое создает линию. Мне нужно увидеть постепенное криволинейное изменение наклона, которое происходит как справа, так и слева от графика двух переменных.
Я начал использовать numpy.polyfit после криволинейной регрессии в googling и python, но это дало мне ужасные результаты, которые вы можете увидеть, если вы запустите код ниже. Может ли кто-нибудь показать мне, как переписать код ниже, чтобы получить тип сигмоидального уравнения регрессии, который я хочу?
Если вы запустите код ниже, вы увидите, что он дает параболу, направленную вниз, и это не так, как должно выглядеть отношение между моими переменными. Вместо этого должно быть больше сигмоидальной связи между моими двумя переменными, но с плотной подгонкой данных, которые я использую в приведенном ниже коде. Данные в приведенном ниже коде являются средством из исследования с большой выборкой, поэтому они собирают больше статистической мощности, чем могут предположить их пять точек данных. У меня нет фактических данных из исследования с большой выборкой, но у меня есть средства ниже и их стандартные отклонения (которые я не показываю). Я бы предпочел просто построить простую функцию со средними данными, перечисленными ниже, но код мог бы стать более сложным, если бы сложность обеспечила существенные улучшения.
Как я могу изменить свой код, чтобы наилучшим образом соответствовать сигмоидальной функции, предпочтительно используя scipy, numpy и python? Вот текущая версия моего кода, которая должна быть исправлена:
import numpy as np
import matplotlib.pyplot as plt
# Create numpy data arrays
x = np.array([821,576,473,377,326])
y = np.array([255,235,208,166,157])
# Use polyfit and poly1d to create the regression equation
z = np.polyfit(x, y, 3)
p = np.poly1d(z)
xp = np.linspace(100, 1600, 1500)
pxp=p(xp)
# Plot the results
plt.plot(x, y, '.', xp, pxp, '-')
plt.ylim(140,310)
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)
plt.show()
ИЗМЕНИТЬ НИЖЕ: (Подтвердил вопрос)
Ваш ответ и его скорость очень впечатляют. Благодарю вас, unutbu. Но для того, чтобы получить более достоверные результаты, мне нужно переопределить мои значения данных. Это означает перебронирование значений x в процентах от значения max x, при повторном литье значений y в процентах от значений x в исходных данных. Я попытался сделать это с помощью вашего кода и придумал следующее:
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize
# Create numpy data arrays
'''
# Comment out original data
#x = np.array([821,576,473,377,326])
#y = np.array([255,235,208,166,157])
'''
# Re-calculate x values as a percentage of the first (maximum)
# original x value above
x = np.array([1.000,0.702,0.576,0.459,0.397])
# Recalculate y values as a percentage of their respective x values
# from original data above
y = np.array([0.311,0.408,0.440,0.440,0.482])
def sigmoid(p,x):
x0,y0,c,k=p
y = c / (1 + np.exp(-k*(x-x0))) + y0
return y
def residuals(p,x,y):
return y - sigmoid(p,x)
p_guess=(600,200,100,0.01)
(p,
cov,
infodict,
mesg,
ier)=scipy.optimize.leastsq(residuals,p_guess,args=(x,y),full_output=1,warning=True)
'''
# comment out original xp to allow for better scaling of
# new values
#xp = np.linspace(100, 1600, 1500)
'''
xp = np.linspace(0, 1.1, 1100)
pxp=sigmoid(p,xp)
x0,y0,c,k=p
print('''\
x0 = {x0}
y0 = {y0}
c = {c}
k = {k}
'''.format(x0=x0,y0=y0,c=c,k=k))
# Plot the results
plt.plot(x, y, '.', xp, pxp, '-')
plt.ylim(0,1)
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)
plt.show()
Можете ли вы показать мне, как исправить этот исправленный код?
ПРИМЕЧАНИЕ. Переливая данные, я по существу повернул сигмоид 2d (x, y) относительно оси z на 180 градусов. Кроме того, 1.000 не является максимальным значением x. Вместо этого 1.000 представляет собой среднее значение диапазона значений от разных участников теста в максимальном состоянии теста.
ВТОРАЯ РЕДАКТИРОВАТЬ НИЖЕ:
Спасибо, ubuntu. Я внимательно прочитал ваш код и рассмотрел его аспекты в скудной документации. Поскольку ваше имя, похоже, появляется как автор скудной документации, я надеюсь, что вы ответите на следующие вопросы:
1.) Идет ли lesssq() остатки(), которые затем возвращают разницу между входным вектором y и y-вектором, возвращаемым функцией sigmoid()? Если да, то как это объясняет разницу в длинах входного y-вектора и y-вектора, возвращаемого функцией sigmoid()?
2.) Похоже, что я могу назвать lesssq() для любого математического уравнения, пока я получаю доступ к этому математическому уравнению через функцию остатков, которая, в свою очередь, вызывает математическую функцию. Это правда?
3.) Кроме того, я замечаю, что p_guess имеет такое же количество элементов, что и p. Означает ли это, что четыре элемента p_guess соответствуют, соответственно, значениям, возвращаемым x0, y0, c и k?
4.) Является ли p, который отправляется как аргумент функции residuals() и sigmoid(), тот же p, который будет выводиться с помощью наименьших квадратов(), а функция lesssq() использует это p внутри, прежде чем возвращать это?
5.) Могут ли p и p_guess иметь любое количество элементов в зависимости от сложности используемого уравнения в качестве модели, если число элементов в p равно числу элементов в p_guess?