【问题标题】:3D plot for the fitted regression surface with matplotlib使用 matplotlib 拟合回归曲面的 3D 图
【发布时间】:2020-05-12 10:44:51
【问题描述】:

我正在尝试制作一个 3D 图表来绘制拟合回归曲面。我看过下面的例子。

Plot linear model in 3d with Matplotlib

Combining scatter plot with surface plot

Best fit surfaces for 3 dimensional data

但是,第一个非常过时并且不再工作,第二个是相关的,但是我在生成 Z 的值时遇到了一些麻烦。 我能找到的所有示例都是过时的或低级的模拟数据示例。可能有比Z 更多的问题。 请看下面的代码。

import numpy as np
import seaborn as sns
import statsmodels.formula.api as smf
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

df = sns.load_dataset('mpg')
df.dropna(inplace=True)

model = smf.ols(formula='mpg ~ horsepower + acceleration', data=df)
results = model.fit()

x, y = model.exog_names[1:]

x_range = np.arange(df[x].min(), df[x].max())
y_range = np.arange(df[y].min(), df[y].max())

X, Y = np.meshgrid(x_range, y_range)
# Z = results.fittedvalues.values.reshape()

fig = plt.figure(figsize=plt.figaspect(1)*3)
ax = plt.axes(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha = 0.2)

更新:

我把Z改成下面是对的

Z = results.params[0] + X*results.params[1] + Y*results.params[2]

并追加

ax.scatter(df[x], df[y], df[model.endog_names], s=50)
ax.view_init(20, 120)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

我得到了下面的情节,但我不确定它是否正确。

如果可能,我还想为绘制的表面添加投影。

【问题讨论】:

  • results.fittedvalues.values的形状是什么?在进行任何显式重塑之前
  • 它是 1-d,但 Z 必须是 2-d 什么的...
  • 确实如此,但我所说的形状是指results.fittedvalues.values.shape 返回什么?
  • 它返回 (392,)
  • df[x].values.shapedf[y].values.shape 怎么样

标签: python numpy matplotlib


【解决方案1】:

在您链接的答案中,关键步骤是通过提供“外生”数据将模型应用于整个网格。在这种情况下,您可以通过创建一个包含解开的网格网格的新数据框并将其作为exog 传递给statsmodels.regression.linear_model.OLS.predict 来轻松完成此操作。使用您的示例对此进行演示:

import numpy as np
import seaborn as sns
import statsmodels.formula.api as smf
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

df = sns.load_dataset('mpg')
df.dropna(inplace=True)

model = smf.ols(formula='mpg ~ horsepower + acceleration', data=df)
results = model.fit()

x, y = model.exog_names[1:]

x_range = np.arange(df[x].min(), df[x].max())
y_range = np.arange(df[y].min(), df[y].max())

X, Y = np.meshgrid(x_range, y_range)

exog = pd.DataFrame({x: X.ravel(), y: Y.ravel()})
Z = results.predict(exog = exog).values.reshape(X.shape)

fig = plt.figure(figsize=plt.figaspect(1)*2)
ax = plt.axes(projection='3d')
ax.scatter(df[x].values, df[y].values, results.fittedvalues.values, 
           marker='.', label="Fits")
cond = df[model.endog_names].values > results.fittedvalues.values
ax.scatter(df[x][cond].values, df[y][cond].values, df[model.endog_names]
           [cond].values, label="Raw")
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha = 0.4)
ax.scatter(df[x][cond == False].values, df[y][cond == False].values,
           df[model.endog_names][cond == False].values)
ax.legend()
plt.show()

哪个会给你

除了数据点之外,我还在散点图中包含了各个拟合点,以表明这种方法正确地生成了相应的表面。我还将数据过滤成两组:应该在表面前面绘制的和应该在表面后面绘制的那些。这是为了适应 matplotlib 在 3D 渲染中对艺术家的分层。观察几何图形已从默认值更改,以尝试最大限度地提高 3D 属性的清晰度。


编辑

将回归表面的投影添加到其中一个轴平面上相当简单 - 您只需绘制一维设置为轴限制的数据,即

ax.plot_surface(X, Y, np.full_like(X, ax.get_zlim()[0]), alpha = 0.2)

然后给你

【讨论】:

  • 我想为绘制的表面添加一个投影(就像你把它压到一边)。有什么简单的方法可以做到这一点吗?如果是这样,我可以更新我的 PO。我认为它就像ax.contour,但我试过了,offset 看起来很奇怪,我找不到文档。
  • @steven 很容易将其投影到与任何轴对平行的平面(即 xy 平面、xz 平面或 yz 平面) - 投影到任意平面稍微困难一些。你想做什么?
  • 最简单的就是每个平面的轴。 xy, xz, yz...我试过了,但我不知道如何指定偏移量。
  • 您能对所有三个轴执行此操作吗?我不太明白这是如何工作的。
  • @steven 如果你想要一个不同的轴平面,你只需置换命令:ax.plot_surface(np.full_like(X, ax.get_xlim()[0]), Y, Z) 将在yz 平面上绘制,ax.plot_surface(X, np.full_like(X, ax.get_ylim()[0]), Z) 将在xz 平面上绘制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
  • 2022-07-10
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
相关资源
最近更新 更多