我希望在pyspark的udf中使用lime's explainer
。我以前已经训练过表格解释器,并且按照link
loaded_explainer = dill.load(open('location_to_explainer','rb'))
def lime_explainer(*cols):
selected_cols = np.array([value for value in cols])
exp = loaded_explainer.explain_instance(selected_cols, loaded_model.predict_proba, num_features = 10)
mapping = exp.as_map()[1]
return str(mapping)
然而,这会花费很多时间,因为看起来很多计算都是在驱动程序上进行的。然后,我一直在尝试使用星火广播向执行者广播解释器。
broadcasted_explainer= sc.broadcast(loaded_explainer)
def lime_explainer(*col):
selected_cols = np.array([value for value in cols])
exp = broadcasted_explainer.value.explain_instance(selected_cols, loaded_model.predict_proba, num_features = 10)
mapping = exp.as_map()[1]
return str(mapping)
但是,我在广播中遇到了一个腌制错误。
PicklingError:无法在0x7f69fd5680d0腌制>: 对lime.discretize进行属性查找失败
有人可以帮忙吗?有没有像dill
这样的东西可以代替spark中使用的拾云器?
答案 0 :(得分:2)
我是dill
的作者。我同意@Majaha,并将略微扩展@Majaha的答案。在@Majaha答案的第一个链接中,明确指出了Broadcast
实例被硬连接为使用pickle
...因此建议将dill
设置为字符串,然后取消un {{ 1}}之后就是一个好人。
不幸的是,dill
方法可能对您不起作用。在extend
类中,源使用Broadcast
不能扩展的CPickle
。
如果您查看源代码,它对python 2使用dill
,对python 3使用import CPickle as pickle; ... pickle.dumps
。对python 2使用import pickle; ... pickle.dumps
,对python 3使用import pickle; ... pickle.dumps
,那么import pickle; ... pickle._dumps
可以通过执行dill
来扩展选择器。例如:
import dill
因此,您可以按照@Majaha的建议进行操作(并将调用保留在Python 3.6.6 (default, Jun 28 2018, 05:53:46)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from pickle import _dumps
>>> import dill
>>> _dumps(lambda x:x)
b'\x80\x03cdill._dill\n_create_function\nq\x00(cdill._dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x01K\x00K\x01K\x01KCC\x04|\x00S\x00q\x05N\x85q\x06)X\x01\x00\x00\x00xq\x07\x85q\x08X\x07\x00\x00\x00<stdin>q\tX\x08\x00\x00\x00<lambda>q\nK\x01C\x00q\x0b))tq\x0cRq\rc__main__\n__dict__\nh\nNN}q\x0etq\x0fRq\x10.'
上),也可以修补代码以进行上面概述的替换(需要的地方,但是eh ...) ,或者您可以使用broadcast
来制作自己的派生类来完成这项工作:
dill
如果上述操作失败...您仍然可以通过查明序列化失败发生的位置来使它正常工作(有>>> from pyspark.broadcast import Broadcast as _Broadcast
>>>
>>> class Broadcast(_Broadcast):
... def dump(self, value, f):
... try:
... import dill
... dill.dump(value, f, pickle_protocol)
... ...[INSERT THE REST OF THE DUMP METHOD HERE]...
可以帮助您解决此问题)。
如果您建议dill.detect.trace
使用pyspark
...可能更好的建议是允许用户动态替换序列化程序。 dill
和其他一些软件包就是这样做的。
答案 1 :(得分:0)
看着this source,看来您别无选择,只能使用提供的选择器。因此,我只能建议您将莳萝嵌套在默认的Pickler中。不理想,但是可以工作。尝试类似的东西:
broadcasted_explainer = dill.loads(sc.broadcast(dill.dumps(loaded_explainer)).value)
或者您可以尝试调用Dill extend() method,该方法应该将Dill数据类型添加到默认的pickle包分发中。不知道这是否行得通,但您可以尝试!
答案 2 :(得分:0)
您的location_to_explainer数据架构是什么?也许转换为Spark的数据框更好。
根据dill的描述
dill可用于将python对象存储到文件中,但是主要用法是将python对象作为字节流通过网络发送。 dill非常灵活,可以将任意用户定义的类和函数序列化。因此,莳萝并非旨在防止错误或恶意构建的数据。留给用户决定他们释放的数据是否来自可信赖的来源。
如果要跨不同的编程语言使用数据,则不建议使用pickle。它的协议特定于Python,因此不能保证跨语言兼容性。不同版本的Python本身也是如此。取消选择使用其他版本的Python腌制的文件可能无法始终正常工作,因此必须确保使用的是相同版本,并在必要时执行更新。您还应该尝试不要从不受信任的来源释放数据。解锁后,文件中的恶意代码可能会执行。
根据此discuss,您可以尝试pysparkling
我不认为这是一个莳萝问题,因为我不认为您的代码正在使用莳萝。因此,据我所知,pyspark使用泡菜或泡菜而不是莳萝。但是,如果您确实希望将莳萝与pyspark一起使用,则存在pysparkling(https://pypi.python.org/pypi/pysparkling)...,使用它可能会解决序列化问题。我建议您使用pyspark打开票证或尝试pysparkling,如果失败,请在那儿打开票证-CC CC或参阅此问题,以便我关注该话题。我将关闭此问题...因此,如果我不正确并且您使用的是莳萝,请随时重新打开此问题。