#python #pandas #matplotlib
#python #панды #matplotlib
Вопрос:
Итак, я пытаюсь нарисовать линию в 3d, но у меня ничего не получается. Я могу сделать правильный разброс, как вы можете видеть на этом рисунке.
Когда я на самом деле провожу через нее линию, я получаю следующую ошибку: «Ошибка значения: входной операнд имеет больше измерений, чем разрешено переназначением оси»
Есть идеи, как это решить?
Мой код:
from pathlib import Path
import pandas as pd
from matplotlib import pyplot as plt
from sklearn import linear_model
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split
# Path of file
path = Path("data/houses.csv")
df = pd.read_csv(path)
# Assign X and Y axis
X = df[['GarageArea', 'YearBuilt']].apply(pd.to_numeric)
y = df[['SalePrice']].apply(pd.to_numeric)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=1)
model = linear_model.LinearRegression(fit_intercept=1)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(r2_score(y_test, y_pred))
print(X_test['GarageArea'])
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X['GarageArea'], X['YearBuilt'], y, c='blue', marker='o')
ax.plot(X_test['GarageArea'], X_test['YearBuilt'], y_pred, color='blue', linewidth=3)
# set your labels
ax.set_xlabel('Garage Area')
ax.set_ylabel('Year Built')
ax.set_zlabel('Price')
plt.show()
Ответ №1:
Вы должны предоставить минимальный рабочий пример путем загрузки data/house.csv
, а также предоставить полный стек трассировки ошибки.
Сообщение об ошибке, которое вы видите, должно исходить из ax.plot
, а точнее, из строки
zs = np.broadcast_to(zs, np.shape(xs))
это строка 1570 mpl_toolkits/mplot3d/axes3d.py
.
X_test['GarageArea']
и X_test['YearBuilt']
представляют собой две серии pandas, что означает, что они представляют собой одномерный массив и имеют форму (N,). y_predict
является результатом model.predict
. sklearn.linear_model.LinearRegression
способен обучаться нескольким целям одновременно, хотя в вашем примере у вас есть только одна цель, которая является ценой продажи, поэтому ее вывод представляет собой матрицу формы (n_samples, n_targets)
или (N, 1), что-то вроде [[1],[2],[3],...]
.
Axes3D.plot
может принимать входные данные (xs, ys, zs, …). По какой-то причине автор Axes3D.plot
решил, что zs должен быть
- либо одинаковой формы xs и ys,
- или одно значение
таким образом, тот же z будет связан со всеми (xs, ys) и np.broadcast_to
используется для обработки обоих случаев. В первом случае broadcast_to
это не вступает в силу, а во втором случае будет создан массив одинаковой формы xs и ys со значением zs.
В вашем коде numpy попытается передать (N,1) в (N,). (N,1) означает, что это массив длиной N из массива длиной 1, например [[1],[2],[3]]
. broadcast_to
аналогично repeat
, и невозможно повторить (N,1), чтобы получить (N,) .
Вы можете попробовать еще несколько тестов, чтобы понять правило np.broadcast_to
:
НЕТ | тест | Статус |
---|---|---|
01 | np.broadcast_to(1,np.shape([1,2,3,4,5,6])) |
ОК |
02 | np.broadcast_to([1],np.shape([1,2,3,4,5,6])) |
ОК |
03 | np.broadcast_to([[1]],np.shape([1,2,3,4,5,6])) |
ошибка |
04 | np.broadcast_to([1,2,3],np.shape([1,2,3,4,5,6])) |
ошибка |
05 | np.broadcast_to([1,2,3,4,5,6],np.shape([1,2,3,4,5,6])) |
ОК |
06 | np.broadcast_to([[1,2,3,4,5,6]],np.shape([1,2,3,4,5,6])) |
ошибка |
07 | np.broadcast_to(1,np.shape([[1,2,3],[4,5,6]])) |
ОК |
08 | np.broadcast_to([1],np.shape([[1,2,3],[4,5,6]])) |
ОК |
09 | np.broadcast_to([[1]],np.shape([[1,2,3],[4,5,6]])) |
ОК |
10 | np.broadcast_to([1,2,3],np.shape([[1,2,3],[4,5,6]])) |
ОК |
11 | np.broadcast_to([[1,2,3]],np.shape([[1,2,3],[4,5,6]])) |
ОК |
12 | np.broadcast_to([[1],[2],[3]],np.shape([[1,2,3],[4,5,6]])) |
ошибка |
13 | np.broadcast_to([1,2],np.shape([[1,2,3],[4,5,6]])) |
ошибка |
14 | np.broadcast_to([1,2,3,4],np.shape([[1,2,3],[4,5,6]])) |
ошибка |
Чтобы решить вашу проблему, измените y_pred
(случай 6) на y_pred.flatten()
(случай 5) ax.plot
.
Прикрепленный MWE:
import numpy as np
import pandas as pd
from sklearn import linear_model
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split
rng = np.random.default_rng()
N = 2000
yearBuilt = rng.random(N)*(2020-1860) 1860
garageArea = rng.random(N)*1000
salePrice = rng.normal(yearBuilt*1000 garageArea*500 (yearBuilt-1860)*garageArea/(2020-1860)/1000*300000,50000,N)
data = {
'YearBuilt': yearBuilt,
'GarageArea': garageArea,
'SalePrice': salePrice
}
df = pd.DataFrame(data)
# Assign X and Y axis
X = df[['GarageArea', 'YearBuilt']].apply(pd.to_numeric)
y = df[['SalePrice']].apply(pd.to_numeric)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=1)
model = linear_model.LinearRegression(fit_intercept=1)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X['GarageArea'], X['YearBuilt'], y, c='blue', marker='o')
ax.plot(X_test['GarageArea'], X_test['YearBuilt'], y_pred.flatten(), color='red', linewidth=3)
# set your labels
ax.set_xlabel('Garage Area')
ax.set_ylabel('Year Built')
ax.set_zlabel('Price')
plt.show()
Смотрите выходное изображение MWE
Представьте, что вы рисуете свои объекты в декартовой системе координат x-y-z. model.predict
может рассматриваться как функция, которая отображает массив (GarageArea, YearBuild) другого массива. X_test
представляет собой набор случайно выбранных и упорядоченных точек на плоскости xy и model.predict
вычисляет координату z. То, что вы видите, будет набором случайных упорядоченных точек, соединенных, как клубок пряжи.
Чтобы нарисовать линию, отражающую линейность вашей модели, вам необходимо предоставить проекцию линии на плоскость xy в качестве входных model.predict
данных вместо X_test . Вы можете использовать линейную регрессию GarageArea как функцию YearBuilt, чтобы получить эту строку. Другая идея состоит в том, чтобы нарисовать линейную плоскость прогнозирования или плоскость тренда, которая является более точной, а не линию тренда.