使用 argparser 解析的 类 初始化对象

Initialize Objects with classes parsed with argparser

我写了一个机器学习脚本,我想从命令行控制它。我已经解析了所有选项,例如 --optimize 400,以在 RandomizedSearchCV 网格上执行 400 次迭代。 但是,我正在努力解决一件事:我想从命令行选择我的估算器,例如 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

我希望任何人都知道如何做到这一点。 非常感谢!

参数始终只是字符串。您需要解析字符串以获得可以调用的函数。

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 参数将字符串参数映射到函数的答案。我误解了 typechoices 的交互方式。)

也许您可以将输入与功能分开。 首先收集用户的输入,然后根据输入运行用户请求的功能。

例如,如果用户 运行:

python script.py -e GradientBoostingRegressor

你会做:

if args.estimator == "GradientBoostingRegressor":
    do stuff...

虽然@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 中效果更好。但还有更进一步的难度 - choiceskeys(),字符串。但是 mytype returns 一个 class,产生如下错误:

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')

为了避免这些困难,我建议将参数分离到 class 映射。这样应该更容易理解和展开:

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 个 class、一个 default 和一个 const 之间进行选择:

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

但这不能推广到更多。 `nargs='?'提供 3 种方式选择 - 默认、const 和用户提供。但是仍然存在将命令行字符串转换为 class 对象的问题。

Subparsers,https://docs.python.org/3/library/argparse.html#sub-commands,展示了如何使用 set_defaults 来设置函数或 classes。但是要使用它,您必须为每个选择定义一个子解析器。

一般来说,最好从简单的 argparse 方法开始,接受字符串和字符串选择,然后进行映射。使用更多 argparse 功能可以稍后使用。

get错误

@chepner's 错误与 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 错误,但用户定义的函数或 lambda 很容易解决。