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

时间:2018-06-11 13:48:09

标签: python argparse

我写了一个机器学习脚本,我想从命令行控制它。我已经解析了所有选项,例如--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

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

3 个答案:

答案 0 :(得分:0)

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

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的交互方式。)

答案 1 :(得分:0)

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

例如,如果用户运行:

python script.py -e GradientBoostingRegressor

你会这样做:

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

答案 2 :(得分:0)

虽然@ 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返回一个类,产生如下错误:

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个班级之间进行选择,defaultconst

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

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

Subparsers https://docs.python.org/3/library/argparse.html#sub-commands显示了set_defaults如何用于设置函数或类。但要使用它,你必须为每个选择定义一个subparser。

一般来说,最好从简单的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 bug或argparse bug,但用户定义的函数或lambda是一个简单的解决方法。