Инициализируйте Объекты с классами, проанализированными с помощью argparser - PullRequest
0 голосов
/ 11 июня 2018

Я написал скрипт машинного обучения, которым я хочу управлять из командной строки.Я уже проанализировал все параметры, например, --optimize 400, чтобы выполнить 400 итераций по сетке RandomizedSearchCV.Однако я борюсь с одной вещью: я хочу выбрать свой оценщик, например, GradientBoostingRegressor () или Lasso (), из командной строки.Я попробовал две вещи:

def cli()
    p = arg.ArgumentParser(description="Perform ML regression.")
    p.add_argument("-e","--estimator",default=Lasso(), help="Choose between Lasso() and GradientBoostingRegressor()")
return p.parse_args()
args = cli()
estimator = args.estimator

Но когда я пытаюсь открыть программу с помощью:

python script.py -e GradientBoostingRegressor()

, я получаю ошибки из-за "()", а также без ((), потому что это интерпретируется как строка.

Еще одна вещь, которую я попробовал:

def cli()
    p = arg.ArgumentParser(description="Perform ML regression.")
    group = p.add_mutually_exclusive_group()
    group.add_argument("-SVR", nargs='?', default = SVR(),
                   help="Choose Suppor Vector Regression")
group.add_argument("-GBR", nargs='?', default = GradientBoostingRegressor())
return p.parse_args()
args = cli()

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

python script.py -SVR

пространство имен "args" содержит SVR = None и GBR = GradientBoostingRegressor (default_GBR_options), что в точности противоположно тому, что я хочу.

В идеале я мог бы выбратьмежду -SVR и -GBR в командной строке и парсер будет передавать его так же, как мои другие параметры, и я мог бы инициализировать объект следующим образом:

estimator = args.estimator

Надеюсь, у кого-нибудь есть информация о том, как это сделать,Большое спасибо!

Ответы [ 3 ]

0 голосов
/ 11 июня 2018

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

Например, если пользователь запустил:

python script.py -e GradientBoostingRegressor

, вы должны сделать:

if args.estimator == "GradientBoostingRegressor":
    do stuff...
0 голосов
/ 11 июня 2018

Несмотря на то, что @ chepner использует type - хорошее использование argparse, подход может быть сложным для правильного понимания и понимания.

Как написано, в методе add_argument возникает ошибка:

Traceback (most recent call last):
  File "stack50799294.py", line 18, in <module>
    p.add_argument("-e", "--estimator", type=estimators.get, default=Lasso, choices=estimators.keys())
  File "/usr/lib/python3.6/argparse.py", line 1346, in add_argument
    type_func = self._registry_get('type', action.type, action.type)
  File "/usr/lib/python3.6/argparse.py", line 1288, in _registry_get
    return self._registries[registry_name].get(value, default)
TypeError: unhashable type: 'dict'

Проверяется, является ли параметр type элементом в registry или допустимой функцией.Я не уверен, почему возникает эта ошибка.

def mytype(astr):
    return estimators.get(astr)

лучше работает в type=mytype.Но есть еще один уровень сложности - choices - это строка keys().Но mytype возвращает класс, выдающий ошибку вроде:

0942:~/mypy$ python3 stack50799294.py -e GBR
usage: stack50799294.py [-h] [-e {Lasso,GBR}]
stack50799294.py: error: argument -e/--estimator: invalid choice: <class '__main__.GradientBoostingRegressor'> (choose from 'Lasso', 'GBR')

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

import argparse

class Lasso():pass
class GradientBoostingRegressor():pass

# Map an easy-to-type string to each function
estimators = {
  'Lasso': Lasso,
  'GBR': GradientBoostingRegressor
}

p = argparse.ArgumentParser(description="Perform ML regression.")
p.add_argument("-e", "--estimator", default='Lasso', choices=estimators.keys())

args = p.parse_args()

print(args)
estimator = estimators.get(args.estimator, None)
if estimator is not None:
    print(type(estimator()))

образцов:

0946:~/mypy$ python3 stack50799294.py -e GBR
Namespace(estimator='GBR')
<class '__main__.GradientBoostingRegressor'>
0946:~/mypy$ python3 stack50799294.py 
Namespace(estimator='Lasso')
<class '__main__.Lasso'>
0946:~/mypy$ python3 stack50799294.py -e Lasso
Namespace(estimator='Lasso')
<class '__main__.Lasso'>
0946:~/mypy$ python3 stack50799294.py -e lasso
usage: stack50799294.py [-h] [-e {Lasso,GBR}]
stack50799294.py: error: argument -e/--estimator: invalid choice: 'lasso' (choose from 'Lasso', 'GBR')

const параметр

Вы можете использовать store_const для выбора между 2классы, default и const:

parser.add_argument('-e', action='store_const', default=Lasso(), const=GradientBoostingRegressor())

, но это не может быть обобщено на большее.`Nargs = '?'предоставляет 3 варианта выбора - по умолчанию, const и пользовательский.Но все еще существует проблема преобразования строки командной строки в объект класса.

Подпарсеры, https://docs.python.org/3/library/argparse.html#sub-commands, показывает, как set_defaults может использоваться для установки функций или классов.Но чтобы использовать это, вы должны определить подпарсер для каждого выбора.

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

get error

@chepner's error имеет отношение к тому, как Python просматривает метод d.get.Несмотря на то, что он выглядит как метод, он каким-то образом видит dict, а не метод:

In [444]: d = {}
In [445]: d.get(d.get)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-445-c6d679ba4e8d> in <module>()
----> 1 d.get(d.get)

TypeError: unhashable type: 'dict'
In [446]: def foo(astr):
     ...:     return d.get(astr)
     ...: 
     ...: 
In [447]: d.get(foo)

Это можно рассматривать как базовую ошибку Python или ошибку argparse, но определяемую пользователем функцию илиЛямбда - это легкая работа.

0 голосов
/ 11 июня 2018

Аргументы всегда просто строки.Вам нужно проанализировать строку, чтобы получить функцию, которую вы можете вызвать.

import argparse

def Lasso():
    print("Lasso!")


def GradientBoostingRegressor():
    print("GradientBoostingRegressor!")


class GetEstimator(argparse.Action):
    estimators = {
            "Lasso": Lasso,
            "GBR": GradientBoostingRegressor,
            }
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, self.estimators[values])


p = argparse.ArgumentParser()
p.add_argument( "-e", "--estimator", action=GetEstimator, default=Lasso, choices=GetEstimaor.estimators.keys())
args = p.parse_args()
args.estimator()    

(Это заменяет предыдущий ответ, который использовал параметр type для сопоставления строкового аргумента с функцией. Я неправильно понял, как type и choices взаимодействуют.)

...