PySpark UDF-生成的DF无法显示“值错误:“ mycolumn”名称不在列表中”

时间:2019-08-22 15:33:48

标签: python pyspark apache-spark-sql

该场景与本帖子非常相似,但有一些变化:Pyspark Unsupported literal type class java.util.ArrayList

我有这种格式的数据:

data.show()
+---------------+--------------------+--------------------+
|       features|                meta|           telemetry|
+---------------+--------------------+--------------------+
|   [seattle, 3]|[seattle, 3, 5344...|[[47, 1, 27, 92, ...|
|     [miami, 1]|[miami, 1, 236881...|[[31, 84, 24, 67,...|
|     [miami, 3]|[miami, 3, 02f4ca...|[[84, 5, 4, 93, 2...|
|   [seattle, 3]|[seattle, 3, ec48...|[[43, 16, 94, 93,...|
|   [seattle, 1]|[seattle, 1, 7d19...|[[70, 22, 45, 74,...|
|[kitty hawk, 3]|[kitty hawk, 3, d...|[[46, 15, 56, 94,...|

您可以从以下链接下载生成的.json示例:https://aiaccqualitytelcapture.blob.core.windows.net/streamanalytics/2019/08/21/10/0_43cbc7b0c9e845a187ce182b46eb4a3a_1.json?st=2019-08-22T15%3A20%3A20Z&se=2026-08-23T15%3A20%3A00Z&sp=rl&sv=2018-03-28&sr=b&sig=tsYh4oTNZXWbLnEgYypNqIsXH3BXOG8XyAH5ODi8iQg%3D

尤其是,您可以看到其中的实际数据实际上都是字典:我们感兴趣的“功能”列的格式为:{“ factory_id”:“ seattle”,“ line_id“:” 3“}

我正在尝试通过经典的功能手段将特征中的数据编码为one_hot。

参见下文:

def one_hot(value, categories_list):
  num_cats = len(categories_list)
  one_hot = np.eye(num_cats)[categories_list.index(value)]
  return one_hot

def one_hot_features(row, feature_keys, u_features):
  """
  feature_keys must be sorted.
  """
  cur_key = feature_keys[0]
  vector = one_hot(row["features"][cur_key], u_features[cur_key])
  for i in range(1, len(feature_keys)):
    cur_key = feature_keys[i]
    n_vector = one_hot(row["features"][cur_key], u_features[cur_key])
    vector = np.concatenate((vector,  n_vector), axis=None)
  return vector

在这种情况下,feature_keys和u_features包含以下数据:

feature_keys = ['factory_id', 'line_id']

u_features = {'factory_id': ['kitty hawk', 'miami', 'nags head', 'seattle'], 'line_id': ['1', '2', '3']}

我已经创建了一个udf,并且正在尝试创建一个使用此udf添加了新列的新数据框。下面的代码:

def calc_onehot_udf(feature_keys, u_features):
  return udf(lambda x: one_hot_features(x, feature_keys, u_features))

n_data = data.withColumn("hot_feature", calc_onehot_udf(feature_keys, 
u_features)( col("features") ))

n_data.show()

这会导致以下几组错误:


Py4JJavaError:调用o148257.showString时发生错误。 :org.apache.spark.SparkException:由于阶段失败而导致作业中止:91.0阶段中的任务0失败4次,最近一次失败:91.0阶段中丢失了任务0.3(TID 1404、10.139.64.5,执行者1):org.apache .spark.api.python.PythonException:追溯(最近一次调用):   在 getitem 中的文件“ /databricks/spark/python/pyspark/sql/types.py”第1514行     idx = self。字段 .index(项目) ValueError:“功能”不在列表中

在处理上述异常期间,发生了另一个异常:

回溯(最近通话最近):   主目录中的文件“ /databricks/spark/python/pyspark/worker.py”,第480行     处理()   正在处理文件“ /databricks/spark/python/pyspark/worker.py”,第472行     serializer.dump_stream(out_iter,外文件)   dump_stream中的第456行的文件“ /databricks/spark/python/pyspark/serializers.py”     self.serializer.dump_stream(self._batched(iterator),流)   dump_stream中的文件“ /databricks/spark/python/pyspark/serializers.py”,行149     对于迭代器中的obj:   _batched中的文件“ /databricks/spark/python/pyspark/serializers.py”,第445行     对于迭代器中的项目:   文件“”,第1行,位于   在第87行中输入文件“ /databricks/spark/python/pyspark/worker.py”     返回lambda * a:f(* a)   包装中的文件“ /databricks/spark/python/pyspark/util.py”,行99     返回f(* args,** kwargs)   文件“”,第4行,在   文件“”,第11行,位于one_hot_features中   在 getitem 中的文件“ /databricks/spark/python/pyspark/sql/types.py”第1519行     引发ValueError(item) ValueError:功能


我们非常感谢您的协助。我正在对此进行积极调查。

理想的输出将是带有以下列的新数据帧:“ hot_features”,其中包含来自features列的一维一维热编码数组。

1 个答案:

答案 0 :(得分:0)

事实证明存在一些关键问题:

  1. 应该必须在UDF中指定返回类型。在这种情况下,它是ArrayType(FloatType())
  2. 我不是从one_hot_features返回nd数组,而是调用了vectors.tolist()
  3. 传递col(“ features”)会在要素列中逐行发送实际值,而不是实际行数据;为此,按原先的方式调用row [“ features”]是不正确的,因为没有访问器,因为我已经具有该行的值。因此,我将第一个参数重命名为“ features_val”而不是“ row”,以更好地反映预期的输入。

以下用于one_hot_features的新代码。

def one_hot_features(features_val, feature_keys, u_features):
  cur_key = feature_keys[0]
  vector = one_hot(features_val[cur_key], u_features[cur_key])
  for i in range(1, len(feature_keys)):
    cur_key = feature_keys[i]
    n_vector = one_hot(features_val[cur_key], u_features[cur_key])
    vector = np.concatenate((vector,  n_vector), axis=None)
  return vector.tolist()

根据其他各种文档,我发现在撰写本文时,numpy数组似乎在Spark数据帧中的表现并不特别好,因此最好将它们转换为更通用的python类型。这似乎已经解决了这里面临的问题。

以下udf定义的更新代码:

def calc_onehot_udf(feature_keys, u_features):
  return udf(lambda x: one_hot_features(x, feature_keys, u_features), 
ArrayType(FloatType()))

n_data = data.withColumn("hot_feature", calc_onehot_udf(feature_keys, 
u_features)(col("features")))
n_data.show()

如果遇到这个问题,祝你好运;希望在这里记录会有所帮助。