3D-графики и легенды возникают при отображении некоторых размеров PCA - PullRequest
0 голосов
/ 04 ноября 2019

У меня есть следующие данные и метки, которые я преобразовываю через PCA. Метки только 0 или 1.

from mpl_toolkits.mplot3d import Axes3D
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import seaborn as sns
import numpy as np

fields = ["Occupancy", "Temperature", "Humidity", "Light", "CO2", "HumidityRatio", "NSM", "WeekStatus"]
df = pd.read_csv('datatraining-updated.csv', skipinitialspace=True, usecols=fields, sep=',') 
#Get the output from pandas as a numpy matrix
final_data=df.values
#Data
X = final_data[:,1:8]  
#Labels
y = final_data[:,0]
#Normalize features
X_scaled = StandardScaler().fit_transform(X)
#Apply PCA on them
pca = PCA(n_components=7).fit(X_scaled)
#Transform them with PCA
X_reduced = pca.transform(X_scaled)

Затем я просто хочу показать на трехмерном графике 3 функции PCA с наибольшей дисперсией, я могу найти их следующим образом

#Show variable importance
importance = pca.explained_variance_ratio_
print('Explained variation per principal component: 
{}'.format(importance))

После этого я хочу отобразить только топ-3 высочайших отклонений. Итак, я предварительно выбрал их в коде ниже

X_reduced=X_reduced[:, [0, 4, 5]]

Хорошо, вот моя проблема: я могу построить их без легенды. Когда я пытаюсь построить их, используя следующий код

# Create plot
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax = fig.gca(projection='3d')
colors = ("red", "gray")

for data, color, group in zip(X_reduced, colors, y):
    dim1,dim2,dim3=data
    ax.scatter(dim1, dim2, dim3, c=color, edgecolors='none',  
    label=group)

plt.title('Matplot 3d scatter plot')
plt.legend(y)
plt.show()

, я получаю следующую ошибку:

plot_data-3d-pca.py:56: UserWarning: Requested projection is different from current axis projection, creating new axis with requested projection.
  ax = fig.gca(projection='3d')
plot_data-3d-pca.py:56: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance.  In a future version, a new instance will always be created and returned.  Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.
  ax = fig.gca(projection='3d')
Traceback (most recent call last):
  File "/home/unica-server/.local/lib/python3.6/site-packages/matplotlib/backends/backend_gtk3.py", line 307, in idle_draw
    self.draw()
  File "/home/unica-server/.local/lib/python3.6/site-packages/matplotlib/backends/backend_gtk3agg.py", line 76, in draw
    self._render_figure(allocation.width, allocation.height)
  File "/home/unica-server/.local/lib/python3.6/site-packages/matplotlib/backends/backend_gtk3agg.py", line 20, in _render_figure
    backend_agg.FigureCanvasAgg.draw(self)
  File "/home/unica-server/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py", line 388, in draw
    self.figure.draw(self.renderer)
  File "/home/unica-server/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/unica-server/.local/lib/python3.6/site-packages/matplotlib/figure.py", line 1709, in draw
    renderer, self, artists, self.suppressComposite)
  File "/home/unica-server/.local/lib/python3.6/site-packages/matplotlib/image.py", line 135, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/unica-server/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/unica-server/.local/lib/python3.6/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 292, in draw
    reverse=True)):
  File "/home/unica-server/.local/lib/python3.6/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 291, in <lambda>
    key=lambda col: col.do_3d_projection(renderer),
  File "/home/unica-server/.local/lib/python3.6/site-packages/mpl_toolkits/mplot3d/art3d.py", line 545, in do_3d_projection
    ecs = (_zalpha(self._edgecolor3d, vzs) if self._depthshade else
  File "/home/unica-server/.local/lib/python3.6/site-packages/mpl_toolkits/mplot3d/art3d.py", line 847, in _zalpha
    rgba = np.broadcast_to(mcolors.to_rgba_array(colors), (len(zs), 4))
  File "<__array_function__ internals>", line 6, in broadcast_to
  File "/home/unica-server/.local/lib/python3.6/site-packages/numpy/lib/stride_tricks.py", line 182, in broadcast_to
    return _broadcast_to(array, shape, subok=subok, readonly=True)
  File "/home/unica-server/.local/lib/python3.6/site-packages/numpy/lib/stride_tricks.py", line 127, in _broadcast_to
    op_flags=['readonly'], itershape=shape, order='C')
ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (0,4) and requested shape (1,4)

Моя форма у (8143,) и форма моего X_reduced (8143,3)

В чем моя ошибка?

РЕДАКТИРОВАТЬ: Используемые мной данные можно найти здесь

Ответы [ 2 ]

1 голос
/ 04 ноября 2019

Первое предупреждение Requested projection is different from current axis projection связано с тем, что вы пытаетесь изменить проекцию оси после ее создания с помощью ax = fig.gca(projection='3d'), но не можете. Вместо этого установите проекцию при создании.

Чтобы исправить вторую ошибку, замените edgecolors='none' на edgecolors=None.

У меня работает следующий исправленный код.

# Create plot
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d') # set projection at creation of axis
# ax = fig.gca(projection='3d') # you cannot change the projection after creation
colors = ("red", "gray")

for data, color, group in zip(X_reduced, colors, y):
    dim1,dim2,dim3=data
    # replace 'none' by None
    ax.scatter(dim1, dim2, dim3, c=color, edgecolors=None, label=group) 

plt.title('Matplot 3d scatter plot')
plt.legend(y)
plt.show()

РЕДАКТИРОВАТЬ: Выше мой ответ на то, что я понял из первоначального вопроса. Ниже приведена зацикленная версия собственного ответа сумасшедшего.

class_values = [0, 1]
labels = ['Empty', 'Full']

n_class = len(class_values)
# allocate lists
index_class = [None] * n_class
X_reduced_class = [None] * n_class

for i, class_i in enumerate(class_values) :

    # get where are the 0s and 1s labels
    index_class[i] = np.where(np.isin(y, class_i))
    # get reduced PCA for each label
    X_reduced_class[i] = X_reduced[index_class[i]]

colors = ['blue', 'red']

# To getter a better understanding of interaction of the dimensions
# plot the first three PCA dimensions
fig = plt.figure(1, figsize=(8, 6))
ax = Axes3D(fig, elev=-150, azim=110)

ids_plot = [0, 4, 5]

for i in range(n_class) : 

    # get the three interesting columns
    data  = X_reduced_class[i][:, ids_plot]

    ax.scatter(data[:,0], data[:,1], data[:,2], c=colors[i], edgecolor='k', s=40, label=labels[i])

ax.set_title("Data Visualization with 3 highest variance dimensions with PCA")
ax.set_xlabel("1st eigenvector")
ax.w_xaxis.set_ticklabels([])
ax.set_ylabel("2nd eigenvector")
ax.w_yaxis.set_ticklabels([])
ax.set_zlabel("3rd eigenvector")
ax.w_zaxis.set_ticklabels([])

ax.legend()

plt.show()
0 голосов
/ 04 ноября 2019

Я решил ошибку по-другому.

Я не знал, что для каждой метки мне приходилось делать разные диаграммы рассеяния. Благодаря этому сообщению я нашел ответ.

Мое решение было сначала отделить метки и данные от одного класса, а затем сделать то же самое для другого класса. Наконец, я строю их отдельно с разными точками рассеяния. Итак, сначала я идентифицирую разные метки (у меня есть только две метки, 0 или 1) и их данные (соответствующие им X).

#Get where are the 0s and 1s labels
index_class1 = np.where(np.isin(y, 0))
index_class2 = np.where(np.isin(y, 1))

#Get reduced PCA for each label
X_reducedclass1=X_reduced[index_class1][:]
X_reducedclass2=X_reduced[index_class2][:]

Затем я нанесу на график каждый вектор с уменьшенным числом PCA из каждого класса вразличные диаграммы рассеяния

colors = ['blue', 'red']

# To getter a better understanding of interaction of the dimensions
# plot the first three PCA dimensions
fig = plt.figure(1, figsize=(8, 6))
ax = Axes3D(fig, elev=-150, azim=110)
scatter1=ax.scatter(X_reducedclass1[:, 0], X_reducedclass1[:, 4], X_reducedclass1[:, 5], c=colors[0], cmap=plt.cm.Set1, edgecolor='k', s=40)
scatter2=ax.scatter(X_reducedclass2[:, 0], X_reducedclass2[:, 4], X_reducedclass2[:, 5], c=colors[1], cmap=plt.cm.Set1, edgecolor='k', s=40)

ax.set_title("Data Visualization with 3 highest variance dimensions with PCA")
ax.set_xlabel("1st eigenvector")
ax.w_xaxis.set_ticklabels([])
ax.set_ylabel("2nd eigenvector")
ax.w_yaxis.set_ticklabels([])
ax.set_zlabel("3rd eigenvector")
ax.w_zaxis.set_ticklabels([])

#ax.legend(np.unique(y))
ax.legend([scatter1, scatter2], ['Empty', 'Full'], loc="upper right")

plt.show()

Что дает мне это прекрасное изображение

enter image description here

Конечно, такой код можно упростить с помощьюцикл тоже (хотя я понятия не имею, как это сделать).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...