ValueError: X has 156 features, but CustomLogisticRegression is expecting
157 features as input
из этого кода:
top_k_indices, top_k_probs = clf.predict_top_k(test, k=12)
Вот что я выяснил и попробовал:
- Проблема, скорее всего, связана с моей единственной горячей кодировкой. Я знаю это, потому что перед применением OHE количество столбцов в обучении и тесте одинаково.
- Я уже добавил параметр handle_unknown = 'ignore' в свой экземпляр OHE, что должно означать что новые невидимые категории в тестовом наборе не должны быть проблемой.
- Я пытался сравнить функции, сгенерированные OHE, при их применении к кадру данных поезда и тестовому набору данных - но это оказалось быть бесполезным методом - поскольку handle_unknown = Параметр «игнорировать» просто устанавливает новые невидимые категории в новый столбец, в котором все нули. (Это может показаться новой функцией, но, поскольку все значения равны 0, это не имеет значения)
- Я не думаю, что проблема связана с удалением столбцов между поездом и тестом, так как я удаляю все одни и те же столбцы.
Этот следующий блок предназначен для импорта соответствующих библиотек и импорта всех соответствующих файлов.
import pandas as pd
from sklearn.preprocessing import LabelEncoder
import matplotlib.pyplot as plt
from sklearn.impute import SimpleImputer
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LogisticRegression
customers = pd.read_csv(path)
products = pd.read_csv(path)
transactions = pd.read_csv(path)
train = pd.read_csv(path)
test = pd.read_csv(path)
В следующем разделе выполняется объединение и создается важная функция, которая суммирует покупки в один столбец
train = pd.merge(train, customers, how='inner', on='customer_id') #merges customers with train to get customer data in one df
transactions = pd.merge(transactions, products, how="inner", on="product_id") #merging transactions-which is customer transaction history, with products for similar reason as other merge here
def customer_profile(customer_id): #this function summarizes all purchases made by the user by adding 3 new columns for each category. Each of the top 3 cols are 1st, 2nd, and 3rd most popular product name within that category for that customer
purchases = transactions.loc[transactions["customer_id"] == customer_id]
mean_price = purchases["price"].mean()
columns = ["product_group_name", "product_type_name", "department_name",
"index_name", "index_group_name", "section_name", "garment_group_name"]
global_most_common = {
col: transactions[col].mode()[0] for col in columns
}
top_three = {}
suffix = {0: "one", 1: "two", 2: "three"}
for col in columns:
top_items = purchases[col].value_counts().head(3)
for i in range(3):
if i < len(top_items):
item = top_items.index
else:
item = global_most_common[col]
top_three[f"{col}_{suffix}"] = item
return mean_price, top_three
В следующем разделе применяется функция и объединяются ее результаты обратно в поезд, а также удаляются несколько ненужных столбцов.
profile_df_test = train["customer_id"][:13].apply(lambda x: pd.Series(customer_profile(x)))
expanded_df = pd.json_normalize(profile_df_test[1]) expanded_df["mean_price"] = profile_df_test[0]
train = pd.concat([train[:13], expanded_df], axis = 1)
train = train.drop(["FN", "Active", "postal_code", "time_date"], axis=1)
В этом разделе определяются столбцы для использования категориального импутера.
imputer = SimpleImputer(strategy='most_frequent')
cols = []
train[cols] = imputer.fit_transform(train[cols])
В этом разделе код разбивается на X и y, а также определяются категориальные и числовые столбцы для шага кодирования.
y_train, X_train = train.iloc[:, 1], train.drop(train.columns[1], axis=1)
categorical_cols = X_train.select_dtypes(include=['category', 'object']).columns.tolist()
numerical_features = X_train.drop(columns=categorical_cols).to_numpy()
label_encoding_cols = ["member_status", "news_frequency"]
ohe_cols = X_train.select_dtypes(include=['category', 'object']).columns.tolist()
это преобразователь столбцов, содержащий OHE
column_transformer = ColumnTransformer(
transformers=[
('cat', OneHotEncoder(handle_unknown='ignore'), ohe_cols) #consistent encoding - T4 GPU colab
],
remainder='passthrough'
)
label_encoder = LabelEncoder()
for col in label_encoding_cols:
X_train[col] = label_encoder.fit_transform(X_train[col])
label_encoded_features = X_train[label_encoding_cols].to_numpy()
X_train_one_hot = column_transformer.fit_transform(X_train)
X_train = np.hstack([numerical_features, label_encoded_features, X_train_one_hot.toarray()])
class CustomLogisticRegression(LogisticRegression):
def predict_top_k(self, X, k=12):
all_probs = super().predict_proba(X)
top_k_indices = np.argpartition(-all_probs, k, axis=1)[:, :k]
top_k_probs = np.take_along_axis(all_probs, top_k_indices, axis=1)
sorted_indices = np.argsort(-top_k_probs, axis=1)
top_k_indices = np.take_along_axis(top_k_indices, sorted_indices, axis=1)
top_k_probs = np.take_along_axis(top_k_probs, sorted_indices, axis=1)
return top_k_indices, top_k_probs
clf = CustomLogisticRegression(multi_class='multinomial', solver='saga', max_iter=900)
clf.fit(csr_matrix(X_train), y_train)
test = pd.merge(test, customers, how='inner', on='customer_id')
profile_df_test_final = test["customer_id"][:13].apply(lambda x: pd.Series(customer_profile(x)))
expanded_df_test = pd.json_normalize(profile_df_test_final[1])
expanded_df_test["mean_price"] = profile_df_test_final[0]
test = pd.concat([test[:13], expanded_df_test], axis = 1)
y_test_placeholder = test['list_product_id'].copy()
test = test.drop(["FN", "Active", "postal_code", "list_product_id"], axis=1)
imputer_test = SimpleImputer(strategy='most_frequent')
imputer_test_mean = SimpleImputer(strategy='mean')
cols = [] #this is another large list of cols to impute, but too many to include here
test[cols] = imputer_test.fit_transform(test[cols])
test["mean_price"] = imputer_test_mean.fit_transform(test[["mean_price"]])
categorical_cols = test.select_dtypes(include=['category', 'object']).columns.tolist()
numerical_features = test.drop(columns=categorical_cols).to_numpy()
label_encoding_cols = ["news_frequency", "member_status"]
ohe_cols = test.select_dtypes(include=['category', 'object']).columns.tolist()
for col in label_encoding_cols:
test[col] = label_encoder.fit_transform(test[col])
label_encoded_features = test[label_encoding_cols].to_numpy()
test_one_hot = column_transformer.fit_transform(test)
test = np.hstack([numerical_features, label_encoded_features, test_one_hot.toarray()])
top_k_indices, top_k_probs = clf.predict_top_k(test, k=12)
Подробнее здесь: https://stackoverflow.com/questions/792 ... atch-issue