在火花上使用python石灰作为udf

时间:2019-03-26 08:55:32

标签: python apache-spark pickle dill

我希望在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中使用的拾云器?

3 个答案:

答案 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非常灵活,可以将任意用户定义的类和函数序列化。因此,莳萝并非旨在防止错误或恶意构建的数据。留给用户决定他们释放的数据是否来自可信赖的来源。

还有When Not To Use pickle

  

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

根据此discuss,您可以尝试pysparkling

  

我不认为这是一个莳萝问题,因为我不认为您的代码正在使用莳萝。因此,据我所知,pyspark使用泡菜或泡菜而不是莳萝。但是,如果您确实希望将莳萝与pyspark一起使用,则存在pysparkling(https://pypi.python.org/pypi/pysparkling)...,使用它可能会解决序列化问题。我建议您使用pyspark打开票证或尝试pysparkling,如果失败,请在那儿打开票证-CC CC或参阅此问题,以便我关注该话题。我将关闭此问题...因此,如果我不正确并且您使用的是莳萝,请随时重新打开此问题。

了解更多Reading pyspark pickles locally

相关问题