عندما أستخدم ColumnTransformer لمعالجة الأعمدة المختلفة (بما في ذلك الأرقام والفئة والنص) مع خط الأنابيب ، لا يمكنني الحصول على أسماء الميزات للبيانات المحولة النهائية ، والتي يصعب تصحيحها.
ها هو الكود:
titanic_url = ('https://raw.githubusercontent.com/amueller/'
'scipy-2017-sklearn/091d371/notebooks/datasets/titanic3.csv')
data = pd.read_csv(titanic_url)
target = data.pop('survived')
numeric_columns = ['age','sibsp','parch']
category_columns = ['pclass','sex','embarked']
text_columns = ['name','home.dest']
numeric_transformer = Pipeline(steps=[
('impute',SimpleImputer(strategy='median')),
('scaler',StandardScaler()
)
])
category_transformer = Pipeline(steps=[
('impute',SimpleImputer(strategy='constant',fill_value='missing')),
('ohe',OneHotEncoder(handle_unknown='ignore'))
])
text_transformer = Pipeline(steps=[
('cntvec',CountVectorizer())
])
preprocesser = ColumnTransformer(transformers=[
('numeric',numeric_transformer,numeric_columns),
('category',category_transformer,category_columns),
('text',text_transformer,text_columns[0])
])
preprocesser.fit_transform(data)
preprocesser.get_feature_names()
:AttributeError: Transformer numeric (type Pipeline) does not provide get_feature_names.
ColumnTransformer
, text_transformer
يمكن فقط معالجة سلسلة (مثل "Sex") ، لكن ليس قائمة سلسلة مثل text_columns
هذه ليست مشكلة حول ColumnTransformer.
eli5
بتنفيذ وظيفة أسماء الميزات التي يمكن أن تدعم خط الأنابيب.إعادة 2. ربما تكون محقًا في أنه من غير الود أنه ليس لدينا طريقة نظيفة لتطبيق ناقل النص على كل عمود. لست متأكدًا من كيفية تحقيق ذلك بشكل نظيف ، إلا إذا بدأنا ببساطة في دعم عدة أعمدة من المدخلات في CountVectorizer وما إلى ذلك.
هذه ليست مشكلة حول ColumnTransformer.
- هو عن خط الأنابيب. لاحظ أن
eli5
بتنفيذ وظيفة أسماء الميزات التي يمكن أن تدعم خط الأنابيب.إعادة 2. ربما تكون محقًا في أنه من غير الود أنه ليس لدينا طريقة نظيفة لتطبيق ناقل النص على كل عمود. لست متأكدًا من كيفية تحقيق ذلك بشكل نظيف ، إلا إذا بدأنا ببساطة في دعم عدة أعمدة من المدخلات في CountVectorizer وما إلى ذلك.
شكرا لردك اللطيف!
كما أعلم ، عندما أعالج عمودًا مسبقًا باستخدام طرق يمكنها تغيير عمود واحد إلى أعمدة متعددة مثل OneHotEncoder
، CountVectorizer
، يمكنني الحصول على أسماء أعمدة البيانات الجديدة من محول الخطوة الأخيرة في خط الأنابيب عن طريق الوظيفة get_feature_names
، عند استخدام الطرق التي لا تنشئ أعمدة جديدة ، يمكنك فقط تعيين اسم الأعمدة الأولية.
def get_column_names_from_ColumnTransformer(column_transformer):
col_name = []
for transformer_in_columns in column_transformer.transformers_[:-1]:#the last transformer is ColumnTransformer's 'remainder'
raw_col_name = transformer_in_columns[2]
if isinstance(transformer_in_columns[1],Pipeline):
transformer = transformer_in_columns[1].steps[-1][1]
else:
transformer = transformer_in_columns[1]
try:
names = transformer.get_feature_names()
except AttributeError: # if no 'get_feature_names' function, use raw column name
names = raw_col_name
if isinstance(names,np.ndarray): # eg.
col_name += names.tolist()
elif isinstance(names,list):
col_name += names
elif isinstance(names,str):
col_name.append(names)
return col_name
باستخدام الرمز أعلاه ، يمكنني الحصول على أسماء أعمدة preprocesser
الخاصة بي.
هل هذه الشفرة تحل هذا السؤال؟
اعتبارًا من eli5 ، لا أجد هذه الوظيفة ، هل يمكنك إعطائي رابطًا للمثال الصريح أو api لـ eli5؟
فيما يتعلق eli5 ، انظر transform_feature_names (المستخدمة من قبل شرح الأوزان)
1 هو نسخة مكررة من # 6425 ، أليس كذلك؟ أريد أن أكتب نومًا عن ذلك.
أعتقد أن دعم أعمدة نصية متعددة أمر سهل للغاية باستخدام ColumnTransformer
. إنه ليس الرمز الأكثر جمالًا ولكن يمكنك فقط إضافة CountVectorizer لكل عمود نصي.
ولا يحل المقتطف الخاص بك المشكلة حقًا لأنه لا يوجد get_feature_names
لا يعني أنه يمكنك فقط استخدام أسماء الأعمدة.
1 هو نسخة مكررة من # 6425 ، أليس كذلك؟ أريد أن أكتب نومًا عن ذلك.
أعتقد أن دعم أعمدة نصية متعددة أمر سهل للغاية باستخدامColumnTransformer
. إنه ليس الرمز الأكثر جمالًا ولكن يمكنك فقط إضافة CountVectorizer لكل عمود نصي.ولا يحل المقتطف الخاص بك المشكلة حقًا لأنه لا يوجد
get_feature_names
لا يعني أنه يمكنك فقط استخدام أسماء الأعمدة.
نعم ، بعد تغذي Pandas DataFrame في خط أنابيب المعالجة المسبقة ، من الأفضل الحصول على أسماء الميزات حتى تتمكن من معرفة ما حدث بالضبط من البيانات التي تم إنشاؤها.
حسنًا ، سيتم الإغلاق كنسخة مكررة.
هذه ليست مشكلة حول ColumnTransformer.
- هو عن خط الأنابيب. لاحظ أن
eli5
بتنفيذ وظيفة أسماء الميزات التي يمكن أن تدعم خط الأنابيب.إعادة 2. ربما تكون محقًا في أنه من غير الود أنه ليس لدينا طريقة نظيفة لتطبيق ناقل النص على كل عمود. لست متأكدًا من كيفية تحقيق ذلك بشكل نظيف ، إلا إذا بدأنا ببساطة في دعم عدة أعمدة من المدخلات في CountVectorizer وما إلى ذلك.
شكرا لردك اللطيف!
كما أعلم ، عندما أعالج عمودًا مسبقًا باستخدام طرق يمكنها تغيير عمود واحد إلى أعمدة متعددة مثلOneHotEncoder
،CountVectorizer
، يمكنني الحصول على أسماء أعمدة البيانات الجديدة من محول الخطوة الأخيرة في خط الأنابيب عن طريق الوظيفةget_feature_names
، عند استخدام الطرق التي لا تنشئ أعمدة جديدة ، يمكنك فقط تعيين اسم الأعمدة الأولية.def get_column_names_from_ColumnTransformer(column_transformer): col_name = [] for transformer_in_columns in column_transformer.transformers_[:-1]:#the last transformer is ColumnTransformer's 'remainder' raw_col_name = transformer_in_columns[2] if isinstance(transformer_in_columns[1],Pipeline): transformer = transformer_in_columns[1].steps[-1][1] else: transformer = transformer_in_columns[1] try: names = transformer.get_feature_names() except AttributeError: # if no 'get_feature_names' function, use raw column name names = raw_col_name if isinstance(names,np.ndarray): # eg. col_name += names.tolist() elif isinstance(names,list): col_name += names elif isinstance(names,str): col_name.append(names) return col_name
باستخدام الرمز أعلاه ، يمكنني الحصول على أسماء أعمدة
preprocesser
الخاصة بي.
هل هذه الشفرة تحل هذا السؤال؟
اعتبارًا من eli5 ، لا أجد هذه الوظيفة ، هل يمكنك إعطائي رابطًا للمثال الصريح أو api لـ eli5؟
لقد أجريت تحسينًا بسيطًا لاستعادة الاسم مثل rawname_value لنماذج onehot:
def get_column_names_from_ColumnTransformer(column_transformer):
col_name = []
for transformer_in_columns in column_transformer.transformers_[:-1]:#the last transformer is ColumnTransformer's 'remainder'
raw_col_name = transformer_in_columns[2]
raw_col_name_reverse = raw_col_name[::-1]
if isinstance(transformer_in_columns[1],Pipeline):
transformer = transformer_in_columns[1].steps[-1][1]
else:
transformer = transformer_in_columns[1]
try:
names = transformer.get_feature_names()
exchange_name = [(_.split("_")) for _ in preprocessor.transformers_[:-1][0][1].steps[-1][1].get_feature_names()]
last_pre_name = ""
last_raw_name = ""
for pre_name,value in exchange_name:
if pre_name==last_pre_name:
col_name.append(last_raw_name+"_"+value)
if pre_name!=last_pre_name:
last_pre_name=pre_name
last_raw_name=raw_col_name_reverse.pop()
col_name.append(last_raw_name+"_"+value)
except AttributeError: # if no 'get_feature_names' function, use raw column name
names = raw_col_name
if isinstance(names,np.ndarray): # eg.
col_name += names.tolist()
elif isinstance(names,list):
col_name += names
elif isinstance(names,str):
col_name.append(names)
return col_name
هذه ليست مشكلة حول ColumnTransformer.
- هو عن خط الأنابيب. لاحظ أن
eli5
بتنفيذ وظيفة أسماء الميزات التي يمكن أن تدعم خط الأنابيب.إعادة 2. ربما تكون محقًا في أنه من غير الود أنه ليس لدينا طريقة نظيفة لتطبيق ناقل النص على كل عمود. لست متأكدًا من كيفية تحقيق ذلك بشكل نظيف ، إلا إذا بدأنا ببساطة في دعم عدة أعمدة من المدخلات في CountVectorizer وما إلى ذلك.
شكرا لردك اللطيف!
كما أعلم ، عندما أعالج عمودًا مسبقًا باستخدام طرق يمكنها تغيير عمود واحد إلى أعمدة متعددة مثلOneHotEncoder
،CountVectorizer
، يمكنني الحصول على أسماء أعمدة البيانات الجديدة من محول الخطوة الأخيرة في خط الأنابيب عن طريق الوظيفةget_feature_names
، عند استخدام الطرق التي لا تنشئ أعمدة جديدة ، يمكنك فقط تعيين اسم الأعمدة الأولية.def get_column_names_from_ColumnTransformer(column_transformer): col_name = [] for transformer_in_columns in column_transformer.transformers_[:-1]:#the last transformer is ColumnTransformer's 'remainder' raw_col_name = transformer_in_columns[2] if isinstance(transformer_in_columns[1],Pipeline): transformer = transformer_in_columns[1].steps[-1][1] else: transformer = transformer_in_columns[1] try: names = transformer.get_feature_names() except AttributeError: # if no 'get_feature_names' function, use raw column name names = raw_col_name if isinstance(names,np.ndarray): # eg. col_name += names.tolist() elif isinstance(names,list): col_name += names elif isinstance(names,str): col_name.append(names) return col_name
باستخدام الرمز أعلاه ، يمكنني الحصول على أسماء أعمدة
preprocesser
الخاصة بي.
هل هذه الشفرة تحل هذا السؤال؟
اعتبارًا من eli5 ، لا أجد هذه الوظيفة ، هل يمكنك إعطائي رابطًا للمثال الصريح أو api لـ eli5؟
ماذا لو قمت بتطبيق Simpleimputer مع add_indicator في خط الأنابيب؟ هذا النهج لن ينجح.
ماذا لو قمت بتطبيق Simpleimputer مع add_indicator في خط الأنابيب؟ هذا النهج لن ينجح.
سيكون من الجيد أن يكون لديك طريقة get_feature_names لهذا التكوين.
ماذا لو قمت بتطبيق Simpleimputer مع add_indicator في خط الأنابيب؟ هذا النهج لن ينجح.
ها هي مساهمتي في الحل قصير المدى. يقوم بإجبار جميع أنواع المصفوفات المختلفة على القوائم ، ويتعامل مع حالة SimpleImputer (add_indicate = True). إنه أيضًا مطول أكثر بقليل.
def get_column_names_from_ColumnTransformer(column_transformer):
col_name = []
for transformer_in_columns in column_transformer.transformers_[:-1]: #the last transformer is ColumnTransformer's 'remainder'
print('\n\ntransformer: ', transformer_in_columns[0])
raw_col_name = list(transformer_in_columns[2])
if isinstance(transformer_in_columns[1], Pipeline):
# if pipeline, get the last transformer
transformer = transformer_in_columns[1].steps[-1][1]
else:
transformer = transformer_in_columns[1]
try:
if isinstance(transformer, OneHotEncoder):
names = list(transformer.get_feature_names(raw_col_name))
elif isinstance(transformer, SimpleImputer) and transformer.add_indicator:
missing_indicator_indices = transformer.indicator_.features_
missing_indicators = [raw_col_name[idx] + '_missing_flag' for idx in missing_indicator_indices]
names = raw_col_name + missing_indicators
else:
names = list(transformer.get_feature_names())
except AttributeError as error:
names = raw_col_name
print(names)
col_name.extend(names)
return col_name
لمعلوماتك ، لقد كتبت بعض التعليمات البرمجية ومدونة حول كيفية استخراج أسماء الميزات من خطوط الأنابيب ومحولات الأعمدة المعقدة. الكود هو تحسين على رسالتي السابقة. https://towardsdatascience.com/extracting-plotting-feature-names-importance-from-scikit-learn-pipelines-eb5bfa6a31f4
@ kylegilde مقالة رائعة وشكراً على الكود. يعمل كالسحر. للحصول على تفسيرات عالمية ، كنت أتصارع مع handle_unkown='ignore'
إليك نسخة أخرى من مقتطف pjgao تتضمن أعمدة من التذكير:
def get_columns_from_transformer(column_transformer, input_colums):
col_name = []
for transformer_in_columns in column_transformer.transformers_[:-1]: #the last transformer is ColumnTransformer's 'remainder'
raw_col_name = transformer_in_columns[2]
if isinstance(transformer_in_columns[1],Pipeline):
transformer = transformer_in_columns[1].steps[-1][1]
else:
transformer = transformer_in_columns[1]
try:
names = transformer.get_feature_names(raw_col_name)
except AttributeError: # if no 'get_feature_names' function, use raw column name
names = raw_col_name
if isinstance(names,np.ndarray): # eg.
col_name += names.tolist()
elif isinstance(names,list):
col_name += names
elif isinstance(names,str):
col_name.append(names)
[_, _, reminder_columns] = column_transformer.transformers_[-1]
for col_idx in reminder_columns:
col_name.append(input_colums[col_idx])
return col_name
ما رأيك في إضافة وظيفة مماثلة لقاعدة الكود الأساسية؟
التعليق الأكثر فائدة
شكرا لردك اللطيف!
كما أعلم ، عندما أعالج عمودًا مسبقًا باستخدام طرق يمكنها تغيير عمود واحد إلى أعمدة متعددة مثل
OneHotEncoder
،CountVectorizer
، يمكنني الحصول على أسماء أعمدة البيانات الجديدة من محول الخطوة الأخيرة في خط الأنابيب عن طريق الوظيفةget_feature_names
، عند استخدام الطرق التي لا تنشئ أعمدة جديدة ، يمكنك فقط تعيين اسم الأعمدة الأولية.باستخدام الرمز أعلاه ، يمكنني الحصول على أسماء أعمدة
preprocesser
الخاصة بي.هل هذه الشفرة تحل هذا السؤال؟
اعتبارًا من eli5 ، لا أجد هذه الوظيفة ، هل يمكنك إعطائي رابطًا للمثال الصريح أو api لـ eli5؟