Wednesday, May 11, 2022

MinMaxScaler Transforms in Python

 Многие алгоритмы машинного обучения работают лучше, когда числовые входные переменные масштабируются до стандартного диапазона.

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

Двумя наиболее популярными методами масштабирования числовых данных перед моделированием являются нормализация и стандартизация. Нормализация масштабирует каждую входную переменную отдельно до диапазона 0-1, который является диапазоном для значений с плавающей запятой, где мы имеем наибольшую точность. Стандартизация масштабирует каждую входную переменную отдельно путем вычитания среднего значения (так называемое центрирование) и деления на стандартное отклонение, чтобы сдвинуть распределение так, чтобы среднее значение равнялось нулю, а стандартное отклонение равнялось единице.

=======================

Вы можете нормализовать свой набор данных с помощью объекта scikit-learn MinMaxScaler.

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

Соответствуйте скейлеру с помощью доступных обучающих данных. Для нормализации это означает, что обучающие данные будут использоваться для оценки минимального и максимального наблюдаемых значений. Это делается путем вызова функции fit().

Примените шкалу к обучающим данным. Это означает, что вы можете использовать нормализованные данные для обучения вашей модели. Это делается путем вызова функции transform().

Примените шкалу к данным в будущем. Это означает, что вы можете подготовить новые данные в будущем, на основе которых вы хотите делать прогнозы.

Масштаб по умолчанию для MinMaxScaler заключается в изменении масштаба переменных в диапазоне [0,1], хотя предпочтительный масштаб можно указать с помощью аргумента «feature_range» и указать кортеж, включая минимальное и максимальное значение для всех переменных.

(.env) [boris@Server35fedora MAXSCALER]$ cat minmaxScaler.py

# visualize a minmax scaler transform of the sonar dataset

from pandas import read_csv

from pandas import DataFrame

from pandas.plotting import scatter_matrix

from sklearn.preprocessing import MinMaxScaler

from matplotlib import pyplot

# load dataset

url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"

dataset = read_csv(url, header=None)

# retrieve just the numeric input values

data = dataset.values[:, :-1]

# perform a robust scaler transform of the dataset

trans = MinMaxScaler()

data = trans.fit_transform(data)

# convert the array back to a dataframe

dataset = DataFrame(data)

# summarize

print(dataset.describe())

# histograms of the variables

dataset.hist()

pyplot.show()































Далее оценим одну модель KNN,но в данном случае на преобразовании набора данных MinMaxScaler.

# evaluate knn on the sonar dataset with minmax scaler transform
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
data = dataset.values
# separate into input and output columns
X, y = data[:, :-1], data[:, -1]
# ensure inputs are floats and output is an integer label
X = X.astype('float32')
y = LabelEncoder().fit_transform(y.astype('str'))
# define the pipeline
trans = MinMaxScaler()
model = KNeighborsClassifier()
pipeline = Pipeline(steps=[('t', trans), ('m', model)])
# evaluate the pipeline
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
# report pipeline performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
























References


Friday, May 6, 2022

3D Plotting with linear SVM Python 3.10

 (.env) [boris@Server35fedora PLOT3DSVM]$ cat plotting3DSVM1.py

from sklearn.svm import SVC

import numpy as np

import matplotlib.pyplot as plt

from sklearn import svm, datasets

from mpl_toolkits.mplot3d import Axes3D

iris = datasets.load_iris()

X = iris.data[:, :3]  # we only take the first three features.

Y = iris.target

#make it binary classification problem

X = X[np.logical_or(Y==0,Y==1)]

Y = Y[np.logical_or(Y==0,Y==1)]

model = svm.SVC(kernel='linear')

clf = model.fit(X, Y)

# The Equation the separating plane given by 

# all x so that np.dot(svc.coef_[0],x)+b = 0

# Solved for w3 (z)

z=lambda x,y: \

  (-clf.intercept_[0]-clf.coef_[0][0]*x -clf.coef_[0][1]*y) \

  / clf.coef_[0][2]


tmp = np.linspace(-5,5,30)

x,y = np.meshgrid(tmp,tmp)

fig = plt.figure()

ax  = fig.add_subplot(111, projection='3d')

ax.plot3D(X[Y==0,0], X[Y==0,1], X[Y==0,2],'ob')

ax.plot3D(X[Y==1,0], X[Y==1,1], X[Y==1,2],'sr')

ax.plot_surface(x, y, z(x,y))

ax.view_init(30, 60)

plt.show()





























(.env) [boris@Server35fedora PLOT3DSVM]$ cat plotting3DSVM4.py
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn.svm import SVC

rs = np.random.RandomState(1234)
# Generate some fake data.
n_samples = 200
# X is the input features by row.
X = np.zeros((200,3))
X[:n_samples//2] = rs.multivariate_normal( np.ones(3), np.eye(3), size=n_samples//2)
X[n_samples//2:] = rs.multivariate_normal(-np.ones(3), np.eye(3), size=n_samples//2)

# Y is the class labels for each row of X.
Y = np.zeros(n_samples); Y[n_samples//2:] = 1

# Fit the data with an svm
svc = SVC(kernel='linear')
svc.fit(X,Y)

# The equation of the separating plane is given by all x in R^3 such that:
# np.dot(svc.coef_[0], x) + b = 0. We should solve for the last coordinate
# to plot the plane in terms of x and y.
z = lambda x,y: \
    (-svc.intercept_[0]-svc.coef_[0][0]*x-svc.coef_[0][1]*y) \
    / svc.coef_[0][2]

tmp = np.linspace(-2,2,51)
x,y = np.meshgrid(tmp,tmp)
# Plot stuff.
fig = plt.figure()
ax  = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z(x,y))
ax.plot3D(X[Y==0,0], X[Y==0,1], X[Y==0,2],'ob')
ax.plot3D(X[Y==1,0], X[Y==1,1], X[Y==1,2],'sr')
plt.show()
































Thursday, May 5, 2022

Multivariate Time Series Forecasting with LSTMs in Keras

 Нейронные сети, такие как рекуррентные нейронные сети с Long Short-Term Memory памятью (LSTM), способны почти без проблем моделировать проблемы с несколькими входными переменными.Это большое преимущество при прогнозировании временных рядов, когда классические линейные методы трудно адаптировать к задачам прогнозирования с несколькими переменными или несколькими входными данными.

Разработатка модели LSTM для прогнозирования многомерных временных рядов с помощью библиотеки глубокого обучения Keras. Используя Keras определим соответствующую модель LSTM.


Мы определим LSTM с 50 нейронами в первом скрытом слое и 1 нейроном в выходном слое для прогнозирования загрязнения. Форма ввода будет 1 временный шаг с 8 функциями.Мы будем использовать функцию потери средней абсолютной ошибки (MAE) и эффективную версию ADAM стохастического градиента.

Модель будет подходить для 50 тренировочных эпох с размером партии 72. Помните, что внутреннее состояние LSTM в керасах сбрасывается в конце каждой партии, поэтому внутреннее состояние, которое является функцией нескольких дней. 

После того, как модель подходит, мы можем прогнозировать весь набор тестирования.

Мы объединяем прогноз с тестовым набором данных и инвертируют масштабирование. Мы также инвертируем масштабирование на наборе данных тестового набора данных с ожидаемыми числами загрязнения.С прогнозами и фактическими значениями в их исходной шкале, мы можем затем рассчитать оценку ошибки для модели. В этом случае мы рассчитываем среднюю квадратную ошибку (RMSE), которая дает ошибку в тех же единицах, что и сама переменная.

Подготовительная часть для кода MultivTimeSeries3.py,MultivTimeSeries5.py

(.env) [boris@Server35fedora TIMESERIES]$ cat MultivTimeSeries1.py

from pandas import read_csv

from matplotlib import pyplot

# load dataset

dataset = read_csv('pollution.csv', header=0, index_col=0)

values = dataset.values

# specify columns to plot

groups = [0, 1, 2, 3, 5, 6, 7]

i = 1

# plot each column

pyplot.figure()

for group in groups:

pyplot.subplot(len(groups), 1, i)

pyplot.plot(values[:, group])

pyplot.title(dataset.columns[group], y=0.5, loc='right')

i += 1

pyplot.show( )


# prepare data for lstm

from pandas import read_csv

from pandas import DataFrame

from pandas import concat

from sklearn.preprocessing import LabelEncoder

from sklearn.preprocessing import MinMaxScaler


# convert series to supervised learning

def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):

n_vars = 1 if type(data) is list else data.shape[1]

df = DataFrame(data)

cols, names = list(), list()

# input sequence (t-n, ... t-1)

for i in range(n_in, 0, -1):

cols.append(df.shift(i))

names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]

# forecast sequence (t, t+1, ... t+n)

for i in range(0, n_out):

cols.append(df.shift(-i))

if i == 0:

names += [('var%d(t)' % (j+1)) for j in range(n_vars)]

else:

names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]

# put it all together

agg = concat(cols, axis=1)

agg.columns = names

# drop rows with NaN values

if dropnan:

agg.dropna(inplace=True)

return agg


# load dataset

dataset = read_csv('pollution.csv', header=0, index_col=0)

values = dataset.values

# integer encode direction

encoder = LabelEncoder()

values[:,4] = encoder.fit_transform(values[:,4])

# ensure all data is float

values = values.astype('float32')

# normalize features

scaler = MinMaxScaler(feature_range=(0, 1))

scaled = scaler.fit_transform(values)

# frame as supervised learning

reframed = series_to_supervised(scaled, 1, 1)

# drop columns we don't want to predict

reframed.drop(reframed.columns[[9,10,11,12,13,14,15]], axis=1, inplace=True)

print(reframed.head())


(.env) [boris@Server35fedora TIMESERIES]$ python MultivTimeSeries1.py

   var1(t-1)  var2(t-1)  var3(t-1)  var4(t-1)  ...  var6(t-1)  var7(t-1)  var8(t-1)   var1(t)

1   0.129779   0.352941   0.245902   0.527273  ...   0.002290   0.000000        0.0  0.148893

2   0.148893   0.367647   0.245902   0.527273  ...   0.003811   0.000000        0.0  0.159960

3   0.159960   0.426471   0.229508   0.545454  ...   0.005332   0.000000        0.0  0.182093

4   0.182093   0.485294   0.229508   0.563637  ...   0.008391   0.037037        0.0  0.138833

5   0.138833   0.485294   0.229508   0.563637  ...   0.009912   0.074074        0.0  0.109658


[5 rows x 9 columns]


(.env) [boris@Server35fedora FORECAST]$ cat  MultivTimeSeries3.py

from math import sqrt

from numpy import concatenate

from matplotlib import pyplot

from pandas import read_csv

from pandas import DataFrame

from pandas import concat

from sklearn.preprocessing import MinMaxScaler

from sklearn.preprocessing import LabelEncoder

from sklearn.metrics import mean_squared_error

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import Dense

from tensorflow.keras.layers import LSTM

 

# convert series to supervised learning

def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):

n_vars = 1 if type(data) is list else data.shape[1]

df = DataFrame(data)

cols, names = list(), list()

# input sequence (t-n, ... t-1)

for i in range(n_in, 0, -1):

cols.append(df.shift(i))

names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]

# forecast sequence (t, t+1, ... t+n)

for i in range(0, n_out):

cols.append(df.shift(-i))

if i == 0:

names += [('var%d(t)' % (j+1)) for j in range(n_vars)]

else:

names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]

# put it all together

agg = concat(cols, axis=1)

agg.columns = names

# drop rows with NaN values

if dropnan:

agg.dropna(inplace=True)

return agg

# load dataset

dataset = read_csv('pollution.csv', header=0, index_col=0)

values = dataset.values

# integer encode direction

encoder = LabelEncoder()

values[:,4] = encoder.fit_transform(values[:,4])

# ensure all data is float

values = values.astype('float32')

# normalize features

scaler = MinMaxScaler(feature_range=(0, 1))

scaled = scaler.fit_transform(values)

# frame as supervised learning

reframed = series_to_supervised(scaled, 1, 1)

# drop columns we don't want to predict

reframed.drop(reframed.columns[[9,10,11,12,13,14,15]], axis=1, inplace=True)

print(reframed.head())

 

# split into train and test sets

values = reframed.values

n_train_hours = 365 * 24

train = values[:n_train_hours, :]

test = values[n_train_hours:, :]

# split into input and outputs

train_X, train_y = train[:, :-1], train[:, -1]

test_X, test_y = test[:, :-1], test[:, -1]

# reshape input to be 3D [samples, timesteps, features]

train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))

test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))

print(train_X.shape, train_y.shape, test_X.shape, test_y.shape)


# design network

model = Sequential()

model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2])))

model.add(Dense(1))

model.compile(loss='mae', optimizer='adam')


# fit network

history = model.fit(train_X, train_y, epochs=50, batch_size=72, validation_data=(test_X, test_y), verbose=2, shuffle=False)


# plot history

pyplot.plot(history.history['loss'], label='train')

pyplot.plot(history.history['val_loss'], label='test')

pyplot.legend()

pyplot.show()

# make a prediction

yhat = model.predict(test_X)

test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))

# invert scaling for forecast

inv_yhat = concatenate((yhat, test_X[:, 1:]), axis=1)

inv_yhat = scaler.inverse_transform(inv_yhat)

inv_yhat = inv_yhat[:,0]

# invert scaling for actual

test_y = test_y.reshape((len(test_y), 1))

inv_y = concatenate((test_y, test_X[:, 1:]), axis=1)

inv_y = scaler.inverse_transform(inv_y)

inv_y = inv_y[:,0]

# calculate RMSE

rmse = sqrt(mean_squared_error(inv_y, inv_yhat))

print('Test RMSE: %.3f' % rmse)





























Окончательный код
Обучить на примере многократных временных точек.
Изменения, необходимые для обучения модели на нескольких предыдущих временных шагах, довольно минимальны, следующим образом:
Во -первых, вы должны подстроить проблему соответствующим образом при вызове series_to_supervised (). Мы будем использовать 3 часа данных в качестве входных данных. Также обратите внимание, мы больше не объясняем столбцы из всех других полей в OB (T).
Далее нам нужно быть более осторожными при указании столбца для ввода и вывода.
У нас есть 3 * 8 + 8 столбцов в нашем наборе данных с фреймами. Мы возьмем 3 * 8 или 24 столбца в качестве входных данных для наблюдения за всеми функциями за предыдущие 3 часа. Мы возьмем только переменную загрязнения в качестве выходных данных в следующий час следующим образом
...
# split into input and outputs
n_obs = n_hours * n_features
train_X, train_y = train[:, :n_obs], train[:, -n_features]
test_X, test_y = test[:, :n_obs], test[:, -n_features]
print(train_X.shape, len(train_X), train_y.shape)

Далее мы можем правильно изменить наши входные данные, чтобы отразить временные шаги и функции
# reshape input to be 3D [samples, timesteps, features]
train_X = train_X.reshape((train_X.shape[0], n_hours, n_features))
test_X = test_X.reshape((test_X.shape[0], n_hours, n_features))

Обучение модели такое же.
Единственное другое небольшое изменение заключается в том, как оценивать модель. В частности, в том, как мы реконструируем строки с 8 столбцами, подходящими для обращения операции масштабирования, чтобы вернуть y и yhat к исходному масштабу, чтобы мы могли вычислить RMSE.
Суть изменения заключается в том, что мы объединяем столбец y или yhat с последними 7 функциями тестового набора данных, чтобы инвертировать масштабирование следующим образом:
...
# invert scaling for forecast
inv_yhat = concatenate((yhat, test_X[:, -7:]), axis=1)
inv_yhat = scaler.inverse_transform(inv_yhat)
inv_yhat = inv_yhat[:,0]
# invert scaling for actual
test_y = test_y.reshape((len(test_y), 1))
inv_y = concatenate((test_y, test_X[:, -7:]), axis=1)
inv_y = scaler.inverse_transform(inv_y)
inv_y = inv_y[:,0]
======================
Сначала при выполнении примера создается график, показывающий потери поезда и теста во время обучения.
Примечание. Ваши результаты могут отличаться из-за стохастического характера алгоритма или процедуры оценки, а также из-за различий в численной точности. Попробуйте запустить пример несколько раз и сравните средний результат.
Интересно, что мы можем видеть, что потери при тестировании падают ниже потерь при обучении. Модель может переобучать обучающие данные. Измерение и построение RMSE во время обучения может пролить больше света на это.
===============================
(.env) [boris@Server35fedora FORECAST]$ cat  MultivTimeSeries5.py
from math import sqrt
from numpy import concatenate
from matplotlib import pyplot
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import mean_squared_error
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import LSTM
 
# convert series to supervised learning
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
n_vars = 1 if type(data) is list else data.shape[1]
df = DataFrame(data)
cols, names = list(), list()
# input sequence (t-n, ... t-1)
for i in range(n_in, 0, -1):
cols.append(df.shift(i))
names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
# forecast sequence (t, t+1, ... t+n)
for i in range(0, n_out):
cols.append(df.shift(-i))
if i == 0:
names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
else:
names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
# put it all together
agg = concat(cols, axis=1)
agg.columns = names
# drop rows with NaN values
if dropnan:
agg.dropna(inplace=True)
return agg
 
# load dataset
dataset = read_csv('pollution.csv', header=0, index_col=0)
values = dataset.values
# integer encode direction
encoder = LabelEncoder()
values[:,4] = encoder.fit_transform(values[:,4])
# ensure all data is float
values = values.astype('float32')
# normalize features
scaler = MinMaxScaler(feature_range=(0, 1))
scaled = scaler.fit_transform(values)
# specify the number of lag hours
n_hours = 3
n_features = 8
# frame as supervised learning
reframed = series_to_supervised(scaled, n_hours, 1)
print(reframed.shape)
 
# split into train and test sets
values = reframed.values
n_train_hours = 365 * 24
train = values[:n_train_hours, :]
test = values[n_train_hours:, :]

# split into input and outputs
n_obs = n_hours * n_features
train_X, train_y = train[:, :n_obs], train[:, -n_features]
test_X, test_y = test[:, :n_obs], test[:, -n_features]
print(train_X.shape, len(train_X), train_y.shape)

# reshape input to be 3D [samples, timesteps, features]
train_X = train_X.reshape((train_X.shape[0], n_hours, n_features))
test_X = test_X.reshape((test_X.shape[0], n_hours, n_features))
print(train_X.shape, train_y.shape, test_X.shape, test_y.shape)
 
# design network
model = Sequential()
model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2])))
model.add(Dense(1))
model.compile(loss='mae', optimizer='adam')

# fit network
history = model.fit(train_X, train_y, epochs=50, batch_size=72, validation_data=(test_X, test_y), verbose=2, shuffle=False)

# plot history
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()
 
# make a prediction
yhat = model.predict(test_X)
test_X = test_X.reshape((test_X.shape[0], n_hours*n_features))
# invert scaling for forecast
inv_yhat = concatenate((yhat, test_X[:, -7:]), axis=1)
inv_yhat = scaler.inverse_transform(inv_yhat)
inv_yhat = inv_yhat[:,0]

# invert scaling for actual
test_y = test_y.reshape((len(test_y), 1))
inv_y = concatenate((test_y, test_X[:, -7:]), axis=1)
inv_y = scaler.inverse_transform(inv_y)
inv_y = inv_y[:,0]

# calculate RMSE
rmse = sqrt(mean_squared_error(inv_y, inv_yhat))
print('Test RMSE: %.3f' % rmse)
























Epoch 45/50
122/122 - 2s - loss: 0.0141 - val_loss: 0.0138 - 2s/epoch - 19ms/step
Epoch 46/50
122/122 - 2s - loss: 0.0142 - val_loss: 0.0137 - 2s/epoch - 20ms/step
Epoch 47/50
122/122 - 2s - loss: 0.0142 - val_loss: 0.0138 - 2s/epoch - 20ms/step
Epoch 48/50
122/122 - 2s - loss: 0.0141 - val_loss: 0.0137 - 2s/epoch - 19ms/step
Epoch 49/50
122/122 - 2s - loss: 0.0141 - val_loss: 0.0138 - 2s/epoch - 18ms/step
Epoch 50/50
122/122 - 2s - loss: 0.0142 - val_loss: 0.0138 - 2s/epoch - 15ms/step
Test RMSE: 26.422














REFERENCES

Wednesday, May 4, 2022

How does one interpret SVM feature weights

Рассмотрим следующий набор данных, который является линейно разделимым

import numpy as np
X = np.array([[3,4],[1,4],[2,3],[6,-1],[7,-1],[5,-3]] )
y = np.array([-1,-1, -1, 1, 1 , 1 ])





 (.env) [boris@Server35fedora SVM]$ cat classSVM.py

import numpy as np

X = np.array([[3,4],[1,4],[2,3],[6,-1],[7,-1],[5,-3]] )

y = np.array([-1,-1, -1, 1, 1 , 1 ])

from sklearn.svm import SVC

clf = SVC(C = 1e5, kernel = 'linear')

clf.fit(X, y)

print('w = ',clf.coef_)

print('b = ',clf.intercept_)

print('Indices of support vectors = ', clf.support_)

print('Support vectors = ', clf.support_vectors_)

print('Number of support vectors for each class = ', clf.n_support_)

print('Coefficients of the support vector in the decision function = ', np.abs(clf.dual_coef_))

(.env) [boris@Server35fedora SVM]$ python classSVM.py

w =  [[ 0.25 -0.25]]

b =  [-0.75]

Indices of support vectors =  [2 3]

Support vectors =  [[ 2.  3.]

 [ 6. -1.]]

Number of support vectors for each class =  [1 1]

Coefficients of the support vector in the decision function =  [[0.0625 0.0625]]


Monday, May 2, 2022

How to Get Feature names from Any Sklearn Pipeline

 Мы собираемся рассматривать Pipeline как дерево. Каждый слой может иметь произвольное количество FeatureUnion, но в конце концов все они будут складываться в один вектор признаков. Есть примерно три случая, которые следует учитывать при обходе. Первый — это базовый случай, когда мы находимся в реальном преобразователе или классификаторе, который будет генерировать наши функции. Во-вторых, если мы находимся в Pipeline. Третий и последний случай — это когда мы находимся внутри FeatureUnion. Давайте поговорим об этом немного подробнее.

============================

Case 1: Featurization Step

===========================

Здесь мы хотим написать функцию, которая с учетом какого-либо функционализатора будет возвращать имена функций. Это базовый случай в нашей DFS. В Sklearn есть несколько разных вещей, которые можно использовать для создания функций. Некоторыми примерами являются методы кластеризации, методы уменьшения размерности, традиционные классификаторы и препроцессоры, и это лишь некоторые из них. Каждый из них позволяет вам получить доступ к именам функций по-разному. Например, препроцессор текста TfidfVectorizer реализует метод get_feature_names, которыый приведен ниже. Однако , большинство методов кластеризации не имеют именованных функций, они представляют собой произвольные кластеры, но имеют фиксированное количество кластеров. Напишем вспомогательную функцию, которая с учетом метода характеристики Sklearn будет возвращать список функций.

=============================

def extract_feature_names(model, name) -> list[str]

=============================

Здесь мы попытаемся перечислить ряд потенциальных случаев, которые могут произойти внутри Sklearn. Мы используем hasattr, чтобы проверить, имеет ли предоставленная модель заданный атрибут, и если да, то мы вызываем его, чтобы получить имена функций. Если метод чем-то похож на кластеризацию и не включает фактические именованные функции, мы создаем наши собственные имена функций, используя предоставленное имя. Например, предположим, что мы применяем этот метод к PCA с двумя компонентами, и мы назвали шаг pca, тогда возвращаемые имена функций будут [pca_0, pca_1].

Давайте пройдем через это вместе. Эта функция займет три вещи. Первая — это модель, которую мы хотим проанализировать. Эта модель должна быть Pipeline. Второй — это список всех именованных шагов характеристики, которые мы хотим извлечь. В нашем последнем примере это были биграммы и отобранные вручную. Это названия отдельных шагов, которые мы использовали в нашей модели. Последний параметр — это текущее имя, на которое мы смотрим. Это необходимо для рекурсии и не имеет значения при первом проходе.

В этом примере мы создаем три написанных от руки средства описания правил, а также подконвейер, который выполняет несколько шагов и приводит к уменьшению размерности функций. Мы можем получить все имена функций из этого конвейера, используя одну строку!


(.env) [boris@fedora35server PIPELINE]$ cat GetFeatureNames.py

from sklearn.pipeline import FeatureUnion, Pipeline

import warnings

warnings.simplefilter(action='ignore', category=FutureWarning)

# Featurization Step

def extract_feature_names(model, name) -> list[str]:

    if hasattr(model, "get_feature_names"):

        return model.get_feature_names()

    elif hasattr(model, "n_clusters"):

        return [f"{name}_{x}" for x in range(model.n_clusters)]

    elif hasattr(model, "n_components"):

        return [f"{name}_{x}" for x in range(model.n_components)]

    elif hasattr(model, "components_"):

        n_components = model.components_.shape[0]

        return [f"{name}_{x}" for x in range(n_components)]

    elif hasattr(model, "classes_"):

        return classes_

    else:

        return [name]


# Implement the DFS.


def get_feature_names(model, names: list[str], name: str) -> list[str]:

    """Thie method extracts the feature names in order from a Sklearn Pipeline

    

    This method only works with composed Pipelines and FeatureUnions.  It will

    pull out all names using DFS from a model.

    

    Args:

        model: The model we are interested in

        names: The list of names of final featurizaiton steps

        name: The current name of the step we want to evaluate.

    Returns:

        feature_names: The list of feature names extracted from the pipeline.

    """

    # Check if the name is one of our feature steps.  This is the base case.

    if name in names:

        # If it has the named_steps atribute it's a pipeline and we need to access the features

        if hasattr(model, "named_steps"):

            return extract_feature_names(model.named_steps[name], name)

        # Otherwise get the feature directly

        else:

            return extract_feature_names(model, name)

    elif type(model) is Pipeline:

        feature_names = []

        for name in model.named_steps.keys():

            feature_names += get_feature_names(model.named_steps[name], names, name)

        return feature_names

    elif type(model) is FeatureUnion:

        feature_names= []

        for name, new_model in model.transformer_list:

            feature_names += get_feature_names(new_model, names, name)

        return feature_names

    # If it is none of the above do not add it.

    else:

        return []

# get the feature names in the correct order

from sklearn.decomposition import TruncatedSVD

from sklearn import svm

from sklearn.feature_extraction.text import CountVectorizer

from sklearn.feature_extraction.text import TfidfTransformer

from sklearn.feature_extraction.text import TfidfVectorizer

from sklearn import metrics


classifier = svm.LinearSVC(C=1.0, class_weight="balanced")

vocab = {"worst": 0, "awful": 1, "waste": 2,

         "boring": 3, "excellent": 4}

model = Pipeline([

    ("union", FeatureUnion(transformer_list=[

        ("h1", TfidfVectorizer(vocabulary={"worst": 0})),

        ("h2", TfidfVectorizer(vocabulary={"best": 0})),

        ("h3", TfidfVectorizer(vocabulary={"awful": 0})),

        ("tfidf_cls", Pipeline([

            ("vectorizer", CountVectorizer()),

            ("transformer", TfidfTransformer()),

            ("tsvd", TruncatedSVD(n_components=2))

        ]

        ))

    ])

     ),

    ("classifier", classifier),

])

print(get_feature_names(model, ["h1", "h2", "h3", "tsvd"], None))




















































REFERENCES