В тази публикация ще обсъдим как да създаваме класове, за да избираме конкретни колони/функции, да добавяме нови колони/функции и да ги комбинираме заедно, за да изградим чист конвейер с помощта на Python и Sklearn. В по-късна статия ще продължа темата за тръбопровода с примери за код, за да покажа как да използватеColumnTransformer
и FeatureUnion
.
Без допълнително обожание, нека се заровим в него.
0. Подгответе данните
Първо, нека подготвим данните. Тук ще използвам малка извадка от данни от скорошния ми проект за прогнозиране на класиране в състезание по бягане, за да създам малък набор от данни за илюстрация. X_train тук има само 4 колони/функции, включително пол, възраст, разстояние и единица за разстояние на участника. Целевата променлива y_train е получената продължителност на състезанието (в минути).
# get the X,y X = train_df.drop('time', axis=1) y = train_df['time'] # Split the data into training and test datasets X_train, X_test, y_train, y_test = train_test_split(X, y,test_size=0.5,random_state=0) print(X_train.shape, y_train.shape) X_train.sample(3)
1. Изберете персонализирани колони
С готовите данни, нека създадем прост клас ColumnSelector
, за да изберете по избор подмножество от колони от даден набор от данни. Предимството е, че след като настроим класа, той може директно да се използва като стъпка в конвейер. Ще го видим по-късно в тази статия.
# first, create a custom column selector to select specific columns from sklearn.base import BaseEstimator, TransformerMixin class ColumnSelector(BaseEstimator, TransformerMixin): '''select specific columns of a given dataset''' def __init__(self, subset): self.subset = subset def fit(self, X, y=None): return self def transform(self, X, y=None): return X.loc[:, self.subset] customized_cols = ['distance','unit'] ## test the ColumnSelector class selected_cols = ColumnSelector(customized_cols) selected_cols.transform(X_train).head()
Чудесно, успешно избрахме колоните/функциите, които ни интересуват, и сме готови да извършим други трансформации на намалените данни.
Но изчакайте, какво ще стане, ако имаме нужда от различни трансформации за различни типове данни? Например еднократно кодиране за колоната с единици и мащабиране за колоната за разстояние? Едно решение е да се създадат два класа за разграничаване на типа данни.
2. Изберете всички цифрови и всички категориални колони
След това нека създадем клас NumColSelector
за избиране на всички цифрови колони и друг клас за избиране на всички категориални колони в данните за обучение.
# second, create a numeric-column selector and a categorical-column selector class NumColSelector(BaseEstimator, TransformerMixin): '''select all numeric columns of a given dataset''' def fit(self, X, y=None): return self def transform(self, X, y=None): return X.select_dtypes(include='number') class CatColSelector(BaseEstimator, TransformerMixin): '''select all categorical columns of a given dataset''' def fit(self, X, y=None): return self def transform(self, X, y=None): return X.select_dtypes(include='object') ## test the NumericColSelector class NumColSelector().transform(X_train).head() # CatColSelector().transform(X_train).head()
хубаво. Можем лесно да разделяме категорични и числови колони с помощта на тези два класа и да правим различни трансформации на данни върху тях по-късно.
Какво ще стане, ако искаме да включим нова колона/функция, която не е била в първоначалните данни за обучение? Например, искаме да създадем нова функция, която да опише средната възраст на всяка група от разстояние, което може да бъде полезно за прогнозиране на целевото променливо време.
3. Добавяне на нова колона
Сега нека създадем друг клас AgeMedianByDistGroup
, за да добавим тази нова колона/функция.
# create a class to add a new feature AgeMedianByDistGroup class AgeMedianByDistGroup(BaseEstimator, TransformerMixin): '''get the median age of each distance group''' def __init__(self, train): self.age_median_by_dist_group = train.groupby('distance').apply(lambda x: x['age'].median()) self.age_median_by_dist_group.name = 'age_median_by_dist_group' def fit(self, X=None, y=None): return self def transform(self, X, y=None): new_X = pd.merge(X, self.age_median_by_dist_group, left_on = 'distance', right_index=True, how='left') X['age_median_by_dist_group'] = new_X['age_median_by_dist_group'] return X
Както виждаме, средната възраст за бягане на 5 км е 36, а средната възраст за 8 км е 30.
4. Настройте окончателния тръбопровода
И накрая, нека изградим pipeline
, като свържем всички заедно, използвайки класовете, които създадохме преди това. По принцип ще извършим следните стъпки към данните за обучение:
- Стъпка 1: Добавете нова колона/функция с
AgeMedianByDistGroup
- Стъпка 2: Изберете всички цифрови колони/функции с
NumColSelector
- Стъпка 3: Фиксирайте всички стойности на nan към медианата с
SimpleImputer
- Стъпка 4: Нормализиране на стойностите до [0,1] диапазон с
MinMaxScaler
# build the final pipeline from sklearn.pipeline import Pipeline from sklearn.impute import SimpleImputer from sklearn.preprocessing import MinMaxScaler pipe = Pipeline([ ('add_new_col', AgeMedianByDistGroup(X_train)), ('get_num_cols', NumColSelector()), ('fix_nan', SimpleImputer(missing_values=np.nan, strategy='median')), ('scale_data', MinMaxScaler()) ]) pipe.fit(X_train)
Крайният тръбопровод изглежда ясен, нали? Едно от най-големите предимства на използването на конвейери е, че автоматизира процеса и поддържа нашия код чист и организиран.
Чрез тази поредица от стъпки наборът от тестови данни и наборът от данни за задържане също могат лесно да бъдат трансформирани с помощта на един и същ конвейер без повторно кодиране. Окончателно трансформираните данни за обучение, както е показано по-долу, са нормализиран кадър от данни, такъв без NaN стойности в избраните от нас колони/функции.
Ето! Изградихме няколко трансформатора и ги комбинирахме в елегантен конвейер! Можем да използваме подготвените данни за обучение за по-късно моделиране.
Благодаря, че прочетохте моята статия! Надяваме се, че това ръководство ще ви помогне с текущия или следващия ви проект. Следващата ми публикация ще обсъди как да използвам ColumnTransformer
и FeatureUnion
за трансформация на колони в конвейера.
Последвайте ме и останете на линия! 😺 🍁 ☃️