Прогноз прочности бетона на сжатие с использованием машинного обучения

Применение машинного обучения в гражданском строительстве

Прочность бетона на сжатие

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

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

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

Описание набора данных

Набор данных состоит из 1030 экземпляров с 9 атрибутами и не имеет пропущенных значений. Есть 8 входных переменных и 1 выходная переменная. Семь входных переменных представляют количество сырья (измеряется в кг / м³), а одна представляет возраст (в днях). Целевая переменная - прочность бетона на сжатие, измеряемая в (МПа - мегапаскаль). Мы исследуем данные, чтобы увидеть, как входные характеристики влияют на прочность на сжатие.

Исследовательский анализ данных

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

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

corr = data.corr() sns.heatmap(corr, annot=True, cmap='Blues')

Мы можем наблюдать высокую положительную корреляцию между прочностью на сжатие (CC_Strength) и цементом. это верно, потому что прочность бетона действительно увеличивается с увеличением количества цемента, используемого для его приготовления. Кроме того, возраст и суперпластификатор являются двумя другими факторами, влияющими на прочность на сжатие.

Есть и другие сильные корреляции между функциями,

  • Сильная отрицательная корреляция между суперпластификатором и водой.
  • положительная корреляция между суперпластификатором и летучей золой, мелким заполнителем.

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

sns.pairplot(data)

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

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

CC_Strength vs (Цемент, Возраст, Вода)

sns.scatterplot(y="CC_Strength", x="Cement", hue="Water",size="Age", data=data, ax=ax, sizes=(50, 300))

Наблюдения, которые мы можем сделать из этого сюжета,

  • Прочность на сжатие увеличивается по мере увеличения количества цемента, поскольку точки перемещаются вверх, когда мы перемещаемся вправо по оси x.
  • Прочность на сжатие увеличивается с возрастом (поскольку размер точек представляет возраст), это не всегда так, но может быть в определенной степени.
  • Цементу с меньшим возрастом требуется больше цемента для большей прочности, поскольку меньшие точки перемещаются вверх, когда мы движемся вправо по оси x.
  • Чем старше цемент, тем больше воды ему требуется, это можно подтвердить, наблюдая за цветом точек. Более крупные точки темного цвета указывают на преклонный возраст и больше воды.
  • Прочность бетона увеличивается, когда при его приготовлении используется меньше воды, поскольку точки на нижней стороне (ось Y) темнее, а точки на верхней стороне (ось Y) ярче.

Прочность CC против (мелкого заполнителя, суперпластификатора, летучей золы)

sns.scatterplot(y="CC_Strength", x="FineAggregate", hue="FlyAsh",
   size="Superplasticizer", data=data, ax=ax, sizes=(50, 300))

Наблюдения,

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

Мы можем визуально понимать 2D, 3D и максимум до 4D графиков (функции, представленные цветом и размером), как показано выше, мы можем дополнительно использовать функции построения по строкам и столбцам с помощью seaborn для дальнейшего анализа, но все же нам не хватает возможность самостоятельно отслеживать все эти корреляции. По этой причине мы можем обратиться к машинному обучению, чтобы зафиксировать эти отношения и лучше понять проблему.

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

Прежде чем мы подгоним модели машинного обучения к данным, нам нужно разделить данные на обучающие и тестовые разбиения. Функции можно масштабировать, чтобы получить среднее значение, равное нулю, и стандартное отклонение, равное 1, то есть все функции попадают в один и тот же диапазон.

X = data.iloc[:,:-1] # Features 
y = data.iloc[:,-1] # Target 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=2) 
sc = StandardScaler() 
X_train = sc.fit_transform(X_train) 
X_test = sc.transform(X_test)

Построение модели

После подготовки данных мы можем сопоставить различные модели с данными обучения и сравнить их производительность, чтобы выбрать алгоритм с хорошей производительностью. Поскольку это проблема регрессии, мы можем использовать RMSE (среднеквадратическую ошибку) и оценку $ R² $ в качестве показателей оценки.

1. Линейная регрессия

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

Где w_i соответствует коэффициенту признака x_i.

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

# Importing models 
from sklearn.linear_model import LinearRegression, Lasso, Ridge 
# Linear Regression 
lr = LinearRegression() 
# Lasso Regression 
lasso = Lasso() 
# Ridge Regression 
ridge = Ridge() 
# Fitting models on Training data 
lr.fit(X_train, y_train) 
lasso.fit(X_train, y_train) 
ridge.fit(X_train, y_train) 
# Making predictions on Test data 
y_pred_lr = lr.predict(X_test) 
y_pred_lasso = lasso.predict(X_test) 
y_pred_ridge = ridge.predict(X_test) 

from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score 
print("Model\t\t\t RMSE \t\t R2") 
print("""LinearRegression \t {:.2f} \t\t{:.2f}""".format(  np.sqrt(mean_squared_error(y_test, y_pred_lr)), r2_score(y_test, y_pred_lr))) 
print("""LassoRegression \t {:.2f} \t\t{:.2f}""".format( np.sqrt(mean_squared_error(y_test, y_pred_lasso)), r2_score(y_test, y_pred_lasso))) print("""RidgeRegression \t {:.2f} \t\t{:.2f}""".format( np.sqrt(mean_squared_error(y_test, y_pred_ridge)), r2_score(y_test, y_pred_ridge)))

Выход

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

coeff_lr = lr.coef_ 
coeff_lasso = lasso.coef_ 
coeff_ridge = ridge.coef_ 
labels = req_col_names[:-1] 
x = np.arange(len(labels)) 
width = 0.3 
fig, ax = plt.subplots(figsize=(10,6)) 
rects1 = ax.bar(x - 2*(width/2), coeff_lr, width, label='LR') 
rects2 = ax.bar(x, coeff_lasso, width, label='Lasso') 
rects3 = ax.bar(x + 2*(width/2), coeff_ridge, width, label='Ridge') 
ax.set_ylabel('Coefficient') 
ax.set_xlabel('Features') 
ax.set_title('Feature Coefficients') 
ax.set_xticks(x) 
ax.set_xticklabels(labels, rotation=45) 
ax.legend() 
def autolabel(rects): 
   """Attach a text label above each bar in *rects*, displaying its height.""" 
   for rect in rects: 
      height = rect.get_height() 
      ax.annotate('{:.2f}'.format(height), xy=(rect.get_x() + rect.get_width() / 2, height), xytext=(0, 3), textcoords="offset points", ha='center', va='bottom') 
autolabel(rects1) 
autolabel(rects2) 
autolabel(rects3) 
fig.tight_layout() 
plt.show()

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

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

fig, (ax1, ax2, ax3) = plt.subplots(1,3, figsize=(12,4)) ax1.scatter(y_pred_lr, y_test, s=20) 
ax1.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2) 
ax1.set_ylabel("True") 
ax1.set_xlabel("Predicted") 
ax1.set_title("Linear Regression") 
ax2.scatter(y_pred_lasso, y_test, s=20) 
ax2.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2) ax2.set_ylabel("True") 
ax2.set_xlabel("Predicted") 
ax2.set_title("Lasso Regression") 
ax3.scatter(y_pred_ridge, y_test, s=20) 
ax3.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2) 
ax3.set_ylabel("True") 
ax3.set_xlabel("Predicted") 
ax3.set_title("Ridge Regression") 
fig.suptitle("True vs Predicted") 
fig.tight_layout(rect=[0, 0.03, 1, 0.95])

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

2. Деревья решений

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

from sklearn.tree import DecisionTreeRegressor 
dtr = DecisionTreeRegressor() 
dtr.fit(X_train, y_train) 
y_pred_dtr = dtr.predict(X_test) 
print("Model\t\t\t\t RMSE \t\t R2") 
print("""Decision Tree Regressor \t {:.2f} \t\t{:.2f}""".format( np.sqrt(mean_squared_error(y_test, y_pred_dtr)), r2_score(y_test, y_pred_dtr))) 
plt.scatter(y_test, y_pred_dtr) 
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2) 
plt.xlabel("Predicted") 
plt.ylabel("True") 
plt.title("Decision Tree Regressor") plt.show()

Среднеквадратичная ошибка (RMSE) снизилась с 10,29 до 7,31, поэтому регрессор дерева решений значительно повысил производительность. Это можно увидеть на графике, так как больше точек находится ближе к линии.

3. Случайные леса

Использование регрессора дерева решений улучшило нашу производительность, мы можем улучшить производительность за счет объединения большего количества деревьев. Random Forest Regressor обучает случайно инициализированные деревья со случайными подмножествами данных, выбранных из обучающих данных, это сделает нашу модель более устойчивой.

from sklearn.ensemble import RandomForestRegressor 
rfr = RandomForestRegressor(n_estimators=100) 
rfr.fit(X_train, y_train) 
y_pred_rfr = rfr.predict(X_test) 
print("Model\t\t\t\t RMSE \t\t R2") print("""Random Forest Regressor \t {:.2f} \t\t{:.2f}""".format( np.sqrt(mean_squared_error(y_test, y_pred_rfr)), r2_score(y_test, y_pred_rfr))) 
plt.scatter(y_test, y_pred_rfr) 
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2) 
plt.xlabel("Predicted") 
plt.ylabel("True") 
plt.title("Random Forest Regressor") 
plt.show()

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

feature_dtr = dtr.feature_importances_ 
feature_rfr = rfr.feature_importances_ 
labels = req_col_names[:-1] 
x = np.arange(len(labels)) 
width = 0.3 
fig, ax = plt.subplots(figsize=(10,6)) 
rects1 = ax.bar(x-(width/2), feature_dtr, width, label='Decision Tree') 
rects2 = ax.bar(x+(width/2), feature_rfr, width, label='Random Forest') 
ax.set_ylabel('Importance') 
ax.set_xlabel('Features') 
ax.set_title('Feature Importance') 
ax.set_xticks(x) 
ax.set_xticklabels(labels, rotation=45) 
ax.legend(loc="upper left", bbox_to_anchor=(1,1)) 
autolabel(rects1) 
autolabel(rects2) 
fig.tight_layout() 
plt.show()

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

Сравнение

Наконец, сравним результаты всех алгоритмов.

models = [lr, lasso, ridge, dtr, rfr] 
names = ["Linear Regression", "Lasso Regression", "Ridge Regression", "Decision Tree Regressor", "Random Forest Regressor"] rmses = [] 
for model in models: 
   rmses.append(np.sqrt(mean_squared_error(y_test, model.predict(X_test)))) 
x = np.arange(len(names)) 
width = 0.3 
fig, ax = plt.subplots(figsize=(10,7)) 
rects = ax.bar(x, rmses, width) 
ax.set_ylabel('RMSE') 
ax.set_xlabel('Models') 
ax.set_title('RMSE with Different Algorithms') 
ax.set_xticks(x) 
ax.set_xticklabels(names, rotation=45) 
autolabel(rects) 
fig.tight_layout() 
plt.show()

Заключение

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

использованная литература

  1. И-Ченг Йе, Моделирование прочности высокоэффективного бетона с использованием искусственных нейронных сетей, Исследования цемента и бетона, Vol. 28, №12, с. 1797–1808 (1998).
  2. Ахсанул Кабир, М.Д. Монджурул Хасан, Хасро Миа, Модель прогнозирования прочности для бетона, ACEE Int. J. по гражданской и экологической инженерии, Vol. 2, №1, август 2013 г.
  3. Https://archive.ics.uci.edu/ml/datasets/Concrete+Compressive+Strength

Первоначально опубликовано на https://pranaymodukuru.github.io 5 марта 2020 г.