О наборе данных:

Набор данных НАСА включает аэродинамические поверхности NACA 0012 разного размера при различных скоростях в аэродинамической трубе и углах атаки. Размах профиля и положение наблюдателя во всех экспериментах были одинаковыми.

Информация об атрибутах:

Эта задача имеет следующие входные данные:
1. Частота (f), в герцах.
2. Угол атаки (альфа), в градусах.
3. Длина хорды (c), в метров.
4. Скорость набегающего потока (u_infinity), в метрах в секунду.
5. Толщина смещения стороны всасывания (дельта ), в метрах.

Единственный вывод:
6. Масштабированный уровень звукового давления (SSPL) в децибелах.

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

Набор данных: Нажмите здесь

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

# importing libraries
import pandas as pd 
import numpy as np
import matplotlib.pyplot as plt 
import seaborn as sns
import scipy.stats as stats 
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score, cross_val_predict
from sklearn import metrics
from sklearn.model_selection import KFold
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Lasso
from sklearn.linear_model import Ridge

Чтобы получить доступ к данным на моем Google Диске. Я добавил следующие коды для доступа к файлам путем подключения учетной записи Google Диска к совместной работе Google. Когда мы запустим приведенный ниже код, появится окно с просьбой авторизовать наш Google Диск с помощью этого блокнота Google Colab.

from google.colab import drive
drive.mount('/content/drive')

Выполните приведенный ниже код, чтобы получить доступ к файлам на подключенном Google Диске.

#Getting Data
df = pd.read_csv('/content/drive/My Drive/Colab Notebooks/Machine Learning/data/AirfoilSelfNoise.csv')
df.head(10)

Теперь вы загрузили свои данные в переменную df. Затем, используя приведенный ниже код, вы можете увидеть первые n сохраненных строк данных в этой переменной. Библиотека Pandas включает метод head(), который обычно используется для возврата первых n строк фрейма данных или ряда.

Мы можем использовать приведенный ниже код для проверки столбцов и типов данных.

df.dtypes

Предварительная обработка данных

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

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

Чтобы увидеть, есть ли какие-либо пропущенные значения в данных из каждого столбца, запустите приведенный ниже код.

# Checking for missing values
df.isnull().values.any()

Выполняя это, мы можем узнать, что в нашем наборе данных нет пропущенных значений.

После этого мы должны проверить, есть ли повторяющиеся значения.

# Checking for duplicate values
df.duplicated().value_counts()

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

Мы должны выполнить сегменты кода для каждого столбца, чтобы найти какие-либо выбросы. Здесь мы собираемся использовать метод Box plot, чтобы найти выбросы.

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

# checking for outliers with boxplot for "f" column
sns.boxplot(df["f"])
plt.xlabel("\"f\" Frequency(in Hertz)", fontsize=12)
plt.title("Boxplot for \"f\" Frequency (before)", fontsize=16)
plt.show()

Сверху на диаграмме мы можем определить, что в столбце «f» есть выбросы. Так что мы должны справиться с ними. здесь мы собираемся справиться с этим, используя IQR (межквартильный диапазон). с приведенным ниже кодом мы можем добиться этого.

# Removing outliers using IQR
Q1 = df["f"].quantile(0.25)
Q3 = df["f"].quantile(0.75)
print(Q1,Q3)
IQR = Q3-Q1
print(IQR)
lower_limit = Q1 - 1.5*IQR
upper_limit = Q3 + 1.5*IQR
print(lower_limit,upper_limit)
df['f'] = np.where(df['f']>upper_limit,upper_limit,df['f'])
df['f'] = np.where(df['f']<lower_limit,lower_limit,df['f'])

После выполнения этого мы можем создать еще одну блочную диаграмму, чтобы убедиться, что выбросы обрабатываются.

# Boxplot After outliers removed
sns.boxplot(df["f"])
plt.xlabel("\"f\" Frequency(in Hertz)", fontsize=12)
plt.title("Boxplot for \"f\" Frequency (after)", fontsize=16)
plt.show()

Затем мы можем проверить наличие выбросов, используя приведенный ниже код, чтобы создать коробчатую диаграмму столбца «альфа».

# checking for outliers with boxplot
sns.boxplot(df["alpha"])
plt.xlabel("\"alpha\" Frequency(in Hertz)", fontsize=12)
plt.title("Boxplot for \"alpha\" Frequency (before)", fontsize=16)
plt.show()

Поскольку мы видим выбросы, мы должны справиться и с этим.

# Removing outliers using IQR
Q1 = df["alpha"].quantile(0.25)
Q3 = df["alpha"].quantile(0.75)
print(Q1,Q3)
IQR = Q3-Q1
print(IQR)
lower_limit = Q1 - 1.5*IQR
upper_limit = Q3 + 1.5*IQR
print(lower_limit,upper_limit)
df['alpha'] = np.where(df['alpha']>upper_limit,upper_limit,df['alpha'])
df['alpha'] = np.where(df['alpha']<lower_limit,lower_limit,df['alpha'])

# Boxplot After outliers removed
sns.boxplot(df["alpha"])
plt.xlabel("\"alpha\" Frequency(in Hertz)", fontsize=12)
plt.title("Boxplot for \"alpha\" Frequency (after)", fontsize=16)
plt.show()

Затем мы можем проверить наличие выбросов, используя приведенный ниже код, чтобы создать коробчатую диаграмму столбца «c».

# checking for outliers with boxplot
sns.boxplot(df["c"])
plt.xlabel("\"c\" Frequency(in Hertz)", fontsize=12)
plt.title("Boxplot for \"c\" Frequency (before)", fontsize=16)
plt.show()

Поскольку здесь нет выбросов, мы можем перейти к следующему столбцу «Обрабатывать столбец «U_infinity».

# checking for outliers with boxplot
sns.boxplot(df["U_infinity"])
plt.xlabel("\"U_infinity\" Frequency(in Hertz)", fontsize=12)
plt.title("Boxplot for \"U_infinity\" Frequency (before)", fontsize=16)
plt.show()

Поскольку здесь также нет выбросов, мы можем перейти к следующему столбцу «Обрабатывать столбец «дельта».

# checking for outliers with boxplot
sns.boxplot(df["delta"])
plt.xlabel("\"delta\" Frequency(in Hertz)", fontsize=12)
plt.title("Boxplot for \"delta\" Frequency (before)", fontsize=16)
plt.show()

Здесь мы должны обрабатывать выбросы с помощью IQR.

# Removing outliers using IQRQ1 = df["delta"].quantile(0.25)
Q3 = df["delta"].quantile(0.75)
print(Q1,Q3)
IQR = Q3-Q1
print(IQR)
lower_limit = Q1 - 1.5*IQR
upper_limit = Q3 + 1.5*IQR
print(lower_limit,upper_limit)
df['delta'] = np.where(df['delta']>upper_limit,upper_limit,df['delta'])
df['delta'] = np.where(df['delta']<lower_limit,lower_limit,df['delta'])
# Boxplot After outliers removed
sns.boxplot(df["delta"])
plt.xlabel("\"delta\" Frequency(in Hertz)", fontsize=12)
plt.title("Boxplot for \"delta\" Frequency (after)", fontsize=16)
plt.show()

Создавайте графики Q-Q и гистограммы функций и при необходимости применяйте преобразования.

Графики Q-Q и гистограммы помогут вам изучить распределение ваших данных. При проверке того, нормально ли распределены ваши данные (близко к колоколообразной кривой), вам помогут гистограмма и графики нормального QQ.

Здесь мы получим гистограммы и графики Q-Q для каждой функции в отдельности.

Мы собираемся выполнить приведенные ниже коды, чтобы получить график QQ и гистограмму для столбца «f», и при необходимости применить преобразования.

#Produce Histogram for f column
fig = plt.figure(figsize=(12,6))
sns.histplot(data = df['f'], kde=True)
plt.title('Histogram for f')
plt.xlabel('f')
plt.ylabel('count')

# Produce Q-Q Plot for f column
fig = plt.figure(figsize=(12,6))
stats.probplot(df['f'], dist="norm", plot=plt)  
plt.title('QQ Plot for f')
plt.xlabel('f')

Здесь мы не смогли увидеть нормальное распределение. Таким образом, мы должны выполнить преобразование, чтобы нормализовать функцию. Итак, здесь мы будем использовать преобразование Бокса-Кокса для выполнения преобразования. Преобразование Бокс-Кокса определяется как метод преобразования ненормальных зависимых переменных в наших данных в нормальную форму, что позволяет нам проводить гораздо больше тестов, чем мы могли бы иначе. Считается лучшим, если он может приблизить ненормальную кривую к нормальной кривой.

Ниже код преобразует столбец f с использованием преобразования Бокса-Кокса.

# Transform f column using Box-Cox transformation
fitted_data, fitted_lambda = stats.boxcox(df["f"])
df["f"] = fitted_data

После мы выполнили преобразование Бокса-Кокса. Набор данных будет преобразован. мы можем проверить это, снова создав гистограмму и график QQ.

#Produce Histogram for f column after transformation
fig = plt.figure(figsize=(12,6))
sns.histplot(data = df['f'], kde=True)
plt.title('Histgram for f after transformation')
plt.xlabel('f')
plt.ylabel('count')

# Produce Q-Q Plot for f column  after transformation
fig = plt.figure(figsize=(12,6))
stats.probplot(df['f'], dist="norm", plot=plt)  
plt.title('QQ Plot for f  after transformation')
plt.xlabel('f')

Далее мы собираемся выполнить приведенные ниже коды, чтобы получить график Q-Q и гистограмму для столбца «альфа» и применить преобразования, если это необходимо.

#Produce Histogram for alpha column
fig = plt.figure(figsize=(12,6))
sns.histplot(data = df['alpha'], kde=True)
plt.title('Histgram for alpha')
plt.xlabel('alpha')
plt.ylabel('count')

# Produce Q-Q Plot for alpha column
fig = plt.figure(figsize=(12,6))
stats.probplot(df['alpha'], dist="norm", plot=plt)  
plt.title('QQ Plot for alpha')
plt.xlabel('alpha')

Далее мы собираемся выполнить коды, как описано выше, чтобы получить график Q-Q и гистограмму для столбца «c» и применить преобразования, если это необходимо.

Следующий график Q-Q и гистограмма для столбца «U_infinity» и при необходимости примените преобразования.

Следующий график Q-Q и гистограмма для столбца «дельта» и при необходимости примените преобразования.

Здесь мы должны выполнить преобразование.

fitted_data, fitted_lambda = stats.boxcox(df["delta"])
df["delta"] = fitted_data

Затем мы можем снова проверить гистограмму и график QQ.

Применение подходящих методов кодирования признаков.

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

Масштабирование функций

Feature Scaling — это методы, используемые для нормализации диапазона значений независимых переменных.

Здесь мы будем использовать метод стандартизации для масштабирования функций.

# standardizing the features
cols = ["f", "alpha", "c", "U_infinity","delta"]
X = df[cols].copy()
y = df[["SSPL"]].copy()
scaler = StandardScaler()
scaled_data = scaler.fit_transform(X)
X = pd.DataFrame(scaled_data)
X = X.rename(columns={0: "f", 1: "alpha", 2: "c", 3:"U_infinity", 
                     4:"delta"})
X.head()

Дискретизация признаков

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

Здесь мы будем использовать KBinsDiscretizer sklearn для выполнения дискретизации.

# Discretize features
disc = KBinsDiscretizer(n_bins=8, encode='ordinal', strategy='uniform')
disc.fit(X)
_disc = disc.transform(X)
X = pd.DataFrame(_disc)
X = X.rename(columns={0: "f", 1: "alpha", 2: "c", 3:"U_infinity", 
                     4:"delta"})
X.head()

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

# Checking after discretization
fig = plt.figure(figsize=(24,8))
plt.subplot(1, 5, 1)
X['f'].value_counts().plot(kind='bar')
plt.xlabel('f')
plt.ylabel("Count")
.
.
plt.show()

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

Разработка функций

PCA (анализ основных компонентов) для уменьшения количества функций.

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

pca = PCA()
X_pca = pca.fit(X)
X_reduced = PCA(n_components=3).fit_transform(X)
principalDf = pd.DataFrame(data = X_reduced)
principalDf.head(10)

pca.explained_variance_ratio_

Здесь нам может понадобиться 4 основных компонента. мы можем отбрасывать небольшие значения (0,0081…)

pca = PCA()
X_pca = pca.fit(X)
X_reduced = PCA(n_components=4).fit_transform(X)
f_principalDf = pd.DataFrame(data = X_reduced)
f_principalDf.head(10)

Определите важные и независимые признаки

# Getting correlation matrix of the features
c_matrix = X.corr()
sns.heatmap(c_matrix, annot = True)
plt.title("Correlation Matrix")
plt.show()

Поскольку большинство значений корреляции меньше 0,9, поэтому сильной связи с переменными нет.

Предсказать значение Y для тестового набора данных (K = 10)

Прежде всего, мы разделяем данные на данные обучения и данные тестирования.

X_train, X_test, y_train, y_test = train_test_split(f_principalDf, Y, test_size = 0.2)
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)

I. Линейная регрессия с перекрестной проверкой

Здесь используется перекрестная проверка (CV) с линейной регрессией (она широко используется почти во всех методах моделирования, таких как деревья решений, SVM и т. д.). В первую очередь мы будем использовать sklearn для перекрестной проверки.

model_1 = LinearRegression()
result_1 = cross_val_score(model_1, X_train, y_train, scoring='neg_root_mean_squared_error',
                       cv=KFold(n_splits=10, random_state=1, shuffle=True),
                       n_jobs=-1)
predict_1 = cross_val_predict(model_1, X_train, y_train, cv=10)
accuracy_1 = metrics.r2_score(y_train , predict_1)
print("r2_score : ", accuracy_1)
print("Mean squared error : ", np.mean(np.absolute(result_1)))

II. Лассо-регрессия с перекрестной проверкой

model_2 = Lasso()
result_2 = cross_val_score(model_2, X_train, y_train, scoring='neg_root_mean_squared_error',
                       cv=KFold(n_splits=10, random_state=1, shuffle=True),
                       n_jobs=-1)
predict_2 = cross_val_predict(model_2, X_train, y_train, cv=10)
accuracy_2 = metrics.r2_score(y_train, predict_2)
print("r2_score : ", accuracy_2)
print("Mean squared error : ", np.mean(np.absolute(result_2)))

III. Ридж-регрессия с перекрестной проверкой

model_3 = Ridge()
result_3 = cross_val_score(model_3, X_train, y_train, scoring='neg_root_mean_squared_error',
                       cv=KFold(n_splits=10, random_state=1, shuffle=True),
                       n_jobs=-1)
predict_3 = cross_val_predict(model_3, X_train, y_train, cv=10)
accuracy_3 = metrics.r2_score(y_train, predict_3)
print("r2_score : ", accuracy_3)
print("Mean squared error : ", np.mean(np.absolute(result_3)))

Резюме применимости различных моделей регрессии к данному набору данных

На основе оценок перекрестной проверки было исследовано множество моделей регрессии, и было обнаружено, что регрессия гребня/лассо лучше всего соответствует данным по сравнению со всеми другими методами.

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

Спасибо, что нашли время прочитать мою статью.