繁体   English   中英

使用python lime作为火花上的udf

[英]Using python lime as a udf on spark

我想在pyspark的udf中使用lime的 explainer器。 我之前已经训练了表格解释器,并且存储了如链接中所建议的莳萝模型

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)

然而这需要花费很多时间,因为看起来很多计算都发生在驱动程序上。 我当时一直在尝试使用spark广播将解释器广播给执行者。

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东西我们可以用而不是火花中使用的cloudpickler?

我是dill作者。 我同意@Majaha,并会稍微延长@ Majaha的回答。 在@ Majaha的答案的第一个链接中,它清楚地指出一个Broadcast实例是硬连线使用pickle ...所以建议dill到一个字符串,然后unill dill后是一个很好的。

不幸的是, extend方法可能不适合你。 Broadcast类中,源使用CPickledill无法扩展。 如果查看源代码,它会使用import CPickle as pickle; ... pickle.dumps import CPickle as pickle; ... pickle.dumps用于python 2的import CPickle as pickle; ... pickle.dumps ,以及import pickle; ... pickle.dumps import pickle; ... pickle.dumps用于python的import pickle; ... pickle.dumps 3.它是否使用了import pickle; ... pickle.dumps import pickle; ... pickle.dumps用于python 2的import pickle; ... pickle.dumps ,以及import pickle; ... pickle._dumps import pickle; ... pickle._dumps用于python 3的import pickle; ... pickle._dumps ,然后dill可以通过执行import dill dill来扩展import pickle; ... pickle._dumps 例如:

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

因此,您可以执行@Majaha建议的操作(以及对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 ...一个可能更好的建议是允许用户动态替换序列化器。 这就是mpi4py和其他一些软件包所做的事情。

看看这个来源 ,似乎你别无选择,只能使用提供的pickler。 因此,我只能建议您将莳萝嵌套在默认的pickler中。 不理想,但它可以工作。 尝试类似的东西:

broadcasted_explainer = dill.loads(sc.broadcast(dill.dumps(loaded_explainer)).value)

或者您可以尝试调用Dill extend()方法 ,该方法应该将Dill数据类型添加到默认的pickle包调度中。 不知道这是否有效,但你可以尝试一下!

你的location_to_explainer数据模式是什么? 也许最好转换为spark的数据帧。

根据莳萝的说法

dill可用于将python对象存储到文件中,但主要用途是将python对象作为字节流通过网络发送。 dill非常灵活,允许序列化任意用户定义的类和函数。 因此,dill不是为了防止错误或恶意构造的数据。 由用户决定他们取消的数据是否来自可信赖的来源。

什么时候不使用泡菜

如果要跨不同编程语言使用数据,建议不要使用pickle。 它的协议特定于Python,因此不保证跨语言兼容性。 对于不同版本的Python本身也是如此。 取消在不同版本的Python中腌制的文件可能并不总是正常工作,因此您必须确保使用相同的版本并在必要时执行更新。 您还应该尝试不从不受信任的来源中取消数据。 解压缩时可能会执行文件中的恶意代码。

根据这个讨论 ,你可以试试pysparkling

我不认为这是一个莳萝问题,因为我不认为你的代码是使用莳萝。 所以,据我所知,pyspark使用泡菜或云雀而不是莳萝。 但是,如果您确实希望将dill与pyspark一起使用,则可以使用pysparkling( https://pypi.python.org/pypi/pysparkling )...并使用它可能会清除序列化问题。 我建议你打开一张带有pyspark的门票或尝试pysparkling,如果失败,请在那里打开一张票 - 然后给我CC或参考这个问题,这样我就可以按照这个问题进行操作了。 我要关闭这个...所以,如果我不正确并且您正在使用莳萝,请随时重新打开此问题。

阅读更多在当地阅读pyspark泡菜

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM