从 RapidMiner Studio 中的执行 Python 处理器返回 pandas DataFrame 时出现 ValueError

ValueError when returning pandas DataFrame from Execute Python processor in RapidMiner Studio

在 RapidMiner Studio 9.5.1 中,在我的 python 脚本完成后,我可以打印生成的数据框,并看到它是按预期生成的,具有正确的列。 rapidminer 处理器仍然失败并显示消息:

Exception: com.rapidminer.operator.OperatorException
Message: Script terminated abnormally: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Stack trace:
  com.rapidminer.extension.pythonscripting.operator.scripting.AbstractScriptRunner.run(AbstractScriptRunner.java:137)
  com.rapidminer.extension.pythonscripting.operator.scripting.AbstractScriptingLanguageOperator.doWork(AbstractScriptingLanguageOperator.java:210)
  com.rapidminer.extension.pythonscripting.operator.scripting.python.PythonScriptingOperator.doWork(PythonScriptingOperator.java:434)
  com.rapidminer.operator.Operator.execute(Operator.java:1032)
  com.rapidminer.operator.execution.SimpleUnitExecutor.execute(SimpleUnitExecutor.java:77)
  com.rapidminer.operator.ExecutionUnit.run(ExecutionUnit.java:812)
  com.rapidminer.operator.ExecutionUnit.run(ExecutionUnit.java:807)
  java.security.AccessController.doPrivileged(Native Method)
  com.rapidminer.operator.ExecutionUnit.execute(ExecutionUnit.java:807)
  com.rapidminer.operator.OperatorChain.doWork(OperatorChain.java:423)
  com.rapidminer.operator.Operator.execute(Operator.java:1032)
  com.rapidminer.Process.executeRoot(Process.java:1378)
  com.rapidminer.Process.lambda$executeRootInPool(Process.java:1357)
  com.rapidminer.studio.concurrency.internal.AbstractConcurrencyContext$AdaptedCallable.exec(AbstractConcurrencyContext.java:328)
  java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
  java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
  java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
  java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

没有提供任何其他见解,也没有在脚本中引用我的代码中的一行。我已经更新了 numpy 库,以防它是旧版本的兼容性问题,但仍然没有解决方案。

numpy                     1.14.5                   pypi_0    pypi
numpy-base                1.16.4           py36hc3f5095_0    defaults
numpydoc                  0.9.1                      py_0    defaults
pandas                    0.25.3           py36ha925a31_0    defaults

此外,当检查 python 环境是否正常(Anaconda env)时,从设置>首选项>Python RapidMiner 中的脚本,所有测试都成功通过。

.rmp 文件中的处理器 xml 是:

  <operator activated="true" class="python_scripting:execute_python" compatibility="9.5.000" expanded="true" height="103" name="Execute Python" width="90" x="313" y="34">
    <parameter key="script" value="import pandas&#10;&#10;# rm_main is a mandatory function, &#10;# the number of arguments has to be the number of input ports (can be none)&#10;def rm_main(data):&#10;    print('Hello, world!')&#10;    # output can be found in Log View&#10;    print(type(data))&#10;&#10;    #your code goes here&#10;&#10;    #for example:&#10;    data2 = pandas.DataFrame([3,5,77,8])&#10;&#10;    # connect 2 output ports to see the results&#10;    return data, data2"/>
    <parameter key="script_file" value="%{ResourcePath}\detect_aggressive_language.py"/>
    <parameter key="notebook_cell_tag_filter" value=""/>
    <parameter key="use_default_python" value="true"/>
    <parameter key="package_manager" value="conda (anaconda)"/>
    <description align="center" color="transparent" colored="false" width="126">Detect Script</description>
  </operator>

到目前为止,我已经尝试过:
1.用我的计算列和return更新初始DataFrame(数据)。
2. 使用我的列和 return 创建一个新的 DataFrame,单独或作为数据后的第二个参数。
3. 创建一个方法(在脚本中)接受初始 DataFrame 数据作为参数,修改它,然后 return 它。
4. Pickle 新的 DataFrame,保存,加载并return它。
所有这些尝试都导致了上述相同的错误。

我的猜测是 RapidMiner 对使用产生上述错误的代码的处理器完成进行某种检查,因此它失败并且处理器终止。

RapidMiner 中是否有特殊的正确方法来处理和 return DataFrames 以绕过错误,或者是否有其他任何我可以检查以找出问题所在的方法?

为了进一步调试问题,我开始将新列一一添加到生成的 DataFrame 中。这让我有了以下发现:

当DataFrame包含一列(pandas.DataFrame.Series),其元素为numpy.ndarrays或列表,其元素为所有个零(整数或浮动)。当 "Execute Python" 处理器 returns 时,RapidMiner 尝试确定 DataFrame 的每个单元格是否返回 Null 或是否有值。为此,基于异常堆栈跟踪,代码必须检查单元格的内容是否为 None,当元素是列表或 numpy ndarrays 时,这不是进行此检查的有效方法。因此,异常消息告诉我们,当数组中存在多个元素时,无法确定真值(或是否为 None,尽管它们全为零。

因此,在这种情况下,解决方案是确保当返回的 DataFrame 具有包含列表或数组的列时,它们的任何实例都不包含全零。还可以避免将列表或数组放入返回的 DataFrame 中。另一件可行的事情是在代码中进行适当的无效检查(使用 array.all()),当找到一个包含所有零元素的数组或列表时,整个单元格的内容将替换为 None 或结果的接收者将解释为 null 的另一个值。当然,也可以等下一个版本的RapidMiner Studio,它可能会以正确的方式进行检查。