Hello chi-yu,

This is my idea:

```
u = np.linspace(X_train['LotFrontage'].min(), X_train['LotFrontage'].max(), 100)
v = np.linspace(X_train['YearBuilt'].min(), X_train['YearBuilt'].max(), 100)
u, v = np.meshgrid(u, v) #This gives you all combinations of u and v. this replaces the two for-loops when you generate z
uv = np.vstack([u.flatten(), v.flatten()]).T
#Now, we can treat uv as if it is a X_test, and then do map_feature and normalize
uv_mapped = map_feature(uv)
uv_norm_mapped = normalize(uv_mapped, mu, std)
z = (np.dot(uv_norm_mapped, w) + b).reshape((100, 100))
fig, ax = plt.subplots(1,3, sharey = True, figsize = (15,4))
ax[0].scatter(X_train.loc[train_rows_below_med, 'LotFrontage'],
X_train.loc[train_rows_below_med,'YearBuilt'],
facecolors = 'none',
edgecolors = 'r',
marker = '^')
ax[1].scatter(X_train.loc[train_rows_above_med, 'LotFrontage'],
X_train.loc[train_rows_above_med,'YearBuilt'],
facecolors = 'none',
edgecolors = 'b')
ax[2].scatter(X_train.loc[train_rows_below_med, 'LotFrontage'],
X_train.loc[train_rows_below_med,'YearBuilt'],
facecolors = 'none',
edgecolors = 'r',
marker = '^')
ax[2].scatter(X_train.loc[train_rows_above_med, 'LotFrontage'],
X_train.loc[train_rows_above_med,'YearBuilt'],
facecolors = 'none',
edgecolors = 'b')
ax[0].contour(u,v,z, levels = [0], colors="g")
ax[1].contour(u,v,z, levels = [0], colors="g")
ax[2].contour(u,v,z, levels = [0], colors="g")
ax[0].set_ylabel("Scaled YearBuilt")
ax[1].set_xlabel("Scaled LotFrontage")
fig.suptitle("Columnwise Normalization Decision Boundary Against Training set \
Using Only Homogeneous Quadratic Form",
fontsize = 14)
plt.show()
```

If you change the `X_train_norm_mapped `

to like my previous post, then you can use the code here to do the plot. This code is mostly based on yours.

Cheers,

Raymond

PS1: it looks more handsome, doesnâ€™t it?

PS2:

They are indeed not scaled YearBuilt and LotFrontage. The axesâ€™ labels need to be changed.