所有字符串表都会导致 PickleException:ClassDict 构造的预期零参数(用于 numpy.dtype)

Posted

技术标签:

【中文标题】所有字符串表都会导致 PickleException:ClassDict 构造的预期零参数(用于 numpy.dtype)【英文标题】:All strings table leads to PickleException: expected zero arguments for construction of ClassDict (for numpy.dtype) 【发布时间】:2021-08-11 17:56:56 【问题描述】:

我是 pyspark 的新手,在 python 和 spark 之间转换数据类型。我想将 python 列表转换为 pyspark 数据框,但没有这样做。我搜索了类似的错误,但仍然无法弄清楚。有人可以提供指导吗?任何帮助表示赞赏。

我已创建此列表 output_list 作为数据块中的输出。该列表如下所示:

['id': 'abcd342', 'v1': 'Mickey Mouse', 'v2': 'USA', 'v3': 'Male', 'v4': 'NY', 'v5': 'Artist', 'v6': 'Garden', 'v7': 'Donald', 'v8': 'Duck', 
 'id': 'b4fcef', 'v1': 'Harry Potter', 'v2': 'Britain', 'v3': 'Male', 'v4': 'London', 'v5': 'Compliance Officer', 'v6': 'Dining Room', 'v7': 'Sally', 'v8': 'Human']

然后我尝试使用以下代码将其转换为 pyspark 数据帧:

from pyspark.sql import SparkSession
from pyspark.sql.types import ArrayType, StructField, StructType, StringType, IntegerType, DecimalType
from decimal import Decimal

appName = "Output results"
master = "local"

# Create Spark session
spark = SparkSession.builder \
    .appName(appName) \
    .master(master) \
    .getOrCreate()

# Create a schema for the dataframe
schema = StructType([
    StructField('id', StringType(), True),
    StructField('v1', StringType(), True),
    StructField('v2', StringType(), True),
    StructField('v3', StringType(), True),
    StructField('v4', StringType(), True),
    StructField('v5', StringType(), True),
    StructField('v6', StringType(), True),
    StructField('v7', StringType(), True),
    StructField('v8', StringType(), True)
])

# Convert list to RDD
output_rdd = spark.sparkContext.parallelize(output_list)

# Create data frame
output_df = spark.createDataFrame(output_rdd,schema)
print(output_df.schema)
print(type(output_df))
output_df.show()

然后我得到的结果包括这样的错误消息:

output_df:pyspark.sql.dataframe.DataFrame
id:string
v1:string
v2:string
v3:string
v4:string
v5:string
v6:string
v7:string
v8:string
StructType(List(StructField(id,StringType,true),StructField(v1,StringType,true),StructField(v2,StringType,true),StructField(v3,StringType,true),StructField(v4,StringType,true),StructField(v5,StringType,true),StructField(v6,StringType,true),StructField(v7,StringType,true),StructField(v8,StringType,true)))
<class 'pyspark.sql.dataframe.DataFrame'>
org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 31.0 failed 4 times, most recent failure: Lost task 0.3 in stage 31.0 (TID 127) (10.201.235.14 executor 1): net.razorvine.pickle.PickleException: expected zero arguments for construction of ClassDict (for numpy.dtype)

Py4JJavaError                             Traceback (most recent call last)
<command-88414643813881> in <module>
     32 print(output_df.schema)
     33 print(type(output_df))
---> 34 output_df.show()

/databricks/spark/python/pyspark/sql/dataframe.py in show(self, n, truncate, vertical)
    488         """
    489         if isinstance(truncate, bool) and truncate:
--> 490             print(self._jdf.showString(n, 20, vertical))
    491         else:
    492             print(self._jdf.showString(n, int(truncate), vertical))

/databricks/spark/python/lib/py4j-0.10.9-src.zip/py4j/java_gateway.py in __call__(self, *args)
   1302 
   1303         answer = self.gateway_client.send_command(command)
-> 1304         return_value = get_return_value(
   1305             answer, self.gateway_client, self.target_id, self.name)
   1306 

奇怪的是我尝试了另一种方法来执行相同的过程,并且它有效。我首先打印出格式列表之类的 json,将列表复制并粘贴到一个新变量中。使用这个新变量,它可以毫无问题地转换为 pyspark 数据框。我检查了output_listoutput_list_2的类型,都是&lt;class 'list'&gt;。我应该改变什么才能使我的原始流程正常工作?这是我的测试代码:

output_list_2 = ['id': 'abcd342', 'v1': 'Mickey Mouse', 'v2': 'USA', 'v3': 'Male', 'v4': 'NY', 'v5': 'Artist', 'v6': 'Garden', 'v7': 'Donald', 'v8': 'Duck', 
 'id': 'b4fcef', 'v1': 'Harry Potter', 'v2': 'Britain', 'v3': 'Male', 'v4': 'London', 'v5': 'Compliance Officer', 'v6': 'Dining Room', 'v7': 'Sally', 'v8': 'Human']
from pyspark.sql import SparkSession
from pyspark.sql.types import ArrayType, StructField, StructType, StringType, IntegerType, DecimalType
from decimal import Decimal

appName = "Output results"
master = "local"

# Create Spark session
spark = SparkSession.builder \
    .appName(appName) \
    .master(master) \
    .getOrCreate()

# Create a schema for the dataframe
schema = StructType([
    StructField('id', StringType(), True),
    StructField('v1', StringType(), True),
    StructField('v2', StringType(), True),
    StructField('v3', StringType(), True),
    StructField('v4', StringType(), True),
    StructField('v5', StringType(), True),
    StructField('v6', StringType(), True),
    StructField('v7', StringType(), True),
    StructField('v8', StringType(), True)
])

# Convert list to RDD
output_rdd = spark.sparkContext.parallelize(output_list_2)

# Create data frame
output_df = spark.createDataFrame(output_rdd,schema)
print(output_df.schema)
print(type(output_df))
output_df.show()

仍然不知道为什么它不起作用。但是,我找到了另一种方法来完成这项工作。不完美,但会完成工作。这是我的解决方案:

# Create data frame
# *Old way*
# output_df = spark.createDataFrame(output_rdd,schema)
# print(output_df.schema)
# print(type(output_df))
# output_df.show()

# *New way*
output_df = sqlContext.read.json(output_rdd)
print(type(output_df))
output_df.show()

catch 是输出的顺序。由于它不使用架构,因此列会自动按字母顺序排列。

【问题讨论】:

您好,您有什么理由必须创建 RDD 作为 Dataframe 的中间步骤吗? @BgRva 嗨,我正在按照一些示例进行操作。我愿意接受其他选择。 【参考方案1】:

当您像这样初始化数据时,它会被初始化为字典的列表。

liet_1 = ['id': 'abcd342', 'v1': 'Mickey Mouse', 
          'id': 'b4fcef', 'v1': 'Harry Potter']

但是,如果将数据初始化为元组的列表,则可以直接初始化DataFrame,只要每个元组中的项目顺序相同即可。架构将定义列名:

list_2 = [('abcd342', 'Mickey Mouse'), 
          ('b4fcef', 'Harry Potter')]

schema2 = StructType([
    StructField('id', StringType(), True),
    StructField('v1', StringType(), True)
])

df = spark.createDataFrame(list_2, schema2 )

干杯

【讨论】:

嗨@BgRva,感谢您的支持。我更新了问题中的描述。输入是一个列表,而不是一个 json 文件。它只是遵循相同的格式 [, , ..., ] 。很抱歉之前的混乱。您能否根据此更新提供建议? 我找到了另一种实现目标的方法。不完美,但工作。请在帖子中查看我的更新。不过,我仍然期待您的意见。提前谢谢! 谢谢。是的,它是在字典列表中创建的。为什么它不起作用,这很令人困惑。但是非常感谢您的讨论!它鼓舞人心。

以上是关于所有字符串表都会导致 PickleException:ClassDict 构造的预期零参数(用于 numpy.dtype)的主要内容,如果未能解决你的问题,请参考以下文章

oracle 优化方案小记

怎么从一段复杂的SQL中把所有的表都取出来?

如果所有表都不存在,请添加一列?

Laravel 连接仅在所有连接的表都包含值时出现

`RefreshDatabase` 删除所有表

每次我重新连接到 MySQL 数据库时,所有表都是空的