【问题标题】:Pandas dataframe to Spark dataframe "Can not merge type error"Pandas 数据框到 Spark 数据框“无法合并类型错误”
【发布时间】:2016-12-12 04:21:10
【问题描述】:

我有 csv 数据并使用 read_csv 创建了 Pandas 数据框,并将所有列强制为字符串。 然后,当我尝试从 Pandas 数据帧创建 Spark 数据帧时,我收到以下错误消息。

from pyspark import SparkContext
from pyspark.sql import SQLContext
from pyspark.sql.types import *
z=pd.read_csv("mydata.csv", dtype=str)
z.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 74044003 entries, 0 to 74044002
Data columns (total 12 columns):
primaryid       object
event_dt        object
age             object
age_cod         object
age_grp         object
sex             object
occr_country    object
drug_seq        object
drugname        object
route           object
outc_cod        object
pt              object
q= sqlContext.createDataFrame(z)
File "<stdin>", line 1, in <module>
File "/usr/hdp/2.4.2.0-258/spark/python/pyspark/sql/context.py", line 425, in createDataFrame
rdd, schema = self._createFromLocal(data, schema)
 File "/usr/hdp/2.4.2.0-258/spark/python/pyspark/sql/context.py", line 341, in _createFromLocal
struct = self._inferSchemaFromList(data)
 File "/usr/hdp/2.4.2.0-258/spark/python/pyspark/sql/context.py", line 241, in _inferSchemaFromList
schema = reduce(_merge_type, map(_infer_schema, data))
 File "/usr/hdp/2.4.2.0-258/spark/python/pyspark/sql/types.py", line 862, in _merge_type
for f in a.fields]
 File "/usr/hdp/2.4.2.0-258/spark/python/pyspark/sql/types.py", line 856, in _merge_type
raise TypeError("Can not merge type %s and %s" % (type(a), type(b)))
TypeError: Can not merge type <class 'pyspark.sql.types.DoubleType'> and <class 'pyspark.sql.types.StringType'>

这是一个例子。我正在下载公共数据并创建 pandas 数据帧,但 spark 不会从 pandas 数据帧创建 spark 数据帧。

import pandas as pd
from pyspark import SparkContext
from pyspark.sql import SQLContext
from pyspark.sql.types import *

url ="http://www.nber.org/fda/faers/2016/demo2016q1.csv.zip"

import requests, zipfile, StringIO
r = requests.get(url, stream=True)
z = zipfile.ZipFile(StringIO.StringIO(r.content))
z.extractall()


z=pd.read_csv("demo2016q1.csv") # creates pandas dataframe

Data_Frame = sqlContext.createDataFrame(z)

【问题讨论】:

  • a) 为什么要在本地读取数据只是为了并行化。这是反模式。 b) 所有被标记为object 的列都暗示了一些 Spark DataFrames 不支持的异构数据。
  • 你是对的,这不是在本地阅读的正确方式,但由于其他选项失败,我希望来自 pandas 的数据帧将易于 spark 处理。正如您所说,这些列是异构的。有没有我可以尝试的解决方法?
  • 你能提供一个minimal reproducible example吗?一些玩具样品将说明那里发生了什么......
  • 我添加了一个带有公共数据的示例代码。

标签: pandas apache-spark dataframe pyspark apache-spark-sql


【解决方案1】:

长话短说不依赖于模式推断。一般来说,它既昂贵又棘手。特别是数据中的某些列(例如event_dt_num)有缺失值,这促使 Pandas 将它们表示为混合类型(字符串表示不缺失,NaN 表示缺失值)。

如果您有疑问,最好将所有数据作为字符串读取,然后再进行转换。如果您有权访问代码簿,则应始终提供架构以避免出现问题并降低总体成本。

最终从驱动程序传递数据是反模式。您应该能够使用csv 格式(Spark 2.0.0+)或spark-csv 库(Spark 1.6 及更低版本)直接读取此数据:

df = (spark.read.format("csv").options(header="true")
    .load("/path/tp/demo2016q1.csv"))

## root
##  |-- primaryid: string (nullable = true)
##  |-- caseid: string (nullable = true)
##  |-- caseversion: string (nullable = true)
##  |-- i_f_code: string (nullable = true)
##  |-- i_f_code_num: string (nullable = true)
##   ...
##  |-- to_mfr: string (nullable = true)
##  |-- occp_cod: string (nullable = true)
##  |-- reporter_country: string (nullable = true)
##  |-- occr_country: string (nullable = true)
##  |-- occp_cod_num: string (nullable = true)

在这种特殊情况下,添加inferSchema="true" 选项应该也可以,但最好避免它。您还可以提供如下架构:

from pyspark.sql.types import StructType

schema = StructType.fromJson({'fields': [{'metadata': {},
   'name': 'primaryid',
   'nullable': True,
   'type': 'integer'},
  {'metadata': {}, 'name': 'caseid', 'nullable': True, 'type': 'integer'},
  {'metadata': {}, 'name': 'caseversion', 'nullable': True, 'type': 'integer'},
  {'metadata': {}, 'name': 'i_f_code', 'nullable': True, 'type': 'string'},
  {'metadata': {},
   'name': 'i_f_code_num',
   'nullable': True,
   'type': 'integer'},
  {'metadata': {}, 'name': 'event_dt', 'nullable': True, 'type': 'integer'},
  {'metadata': {}, 'name': 'event_dt_num', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'mfr_dt', 'nullable': True, 'type': 'integer'},
  {'metadata': {}, 'name': 'mfr_dt_num', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'init_fda_dt', 'nullable': True, 'type': 'integer'},
  {'metadata': {},
   'name': 'init_fda_dt_num',
   'nullable': True,
   'type': 'string'},
  {'metadata': {}, 'name': 'fda_dt', 'nullable': True, 'type': 'integer'},
  {'metadata': {}, 'name': 'fda_dt_num', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'rept_cod', 'nullable': True, 'type': 'string'},
  {'metadata': {},
   'name': 'rept_cod_num',
   'nullable': True,
   'type': 'integer'},
  {'metadata': {}, 'name': 'auth_num', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'mfr_num', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'mfr_sndr', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'lit_ref', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'age', 'nullable': True, 'type': 'double'},
  {'metadata': {}, 'name': 'age_cod', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'age_grp', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'age_grp_num', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'sex', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'e_sub', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'wt', 'nullable': True, 'type': 'double'},
  {'metadata': {}, 'name': 'wt_cod', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'rept_dt', 'nullable': True, 'type': 'integer'},
  {'metadata': {}, 'name': 'rept_dt_num', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'to_mfr', 'nullable': True, 'type': 'string'},
  {'metadata': {}, 'name': 'occp_cod', 'nullable': True, 'type': 'string'},
  {'metadata': {},
   'name': 'reporter_country',
   'nullable': True,
   'type': 'string'},
  {'metadata': {}, 'name': 'occr_country', 'nullable': True, 'type': 'string'},
  {'metadata': {},
   'name': 'occp_cod_num',
   'nullable': True,
   'type': 'integer'}],
 'type': 'struct'})

直接发给读者:

(spark.read.schema(schema).format("csv").options(header="true")
    .load("/path/to/demo2016q1.csv"))

【讨论】:

  • 感谢您的精彩解释。实际上,我切换到 Pandas 是因为我无法成功地将 spark-csv 库添加到 Jupyter。我正在使用 HDP 2.4 (Spark 1.6) 并安装了 Jupyter。我下载了 spark-csv 和 commons-csv 并在 Jupyter notebook 启动器中指定了这些 jar 的路径,但是当我尝试读取 csv 数据时它失败了,说它无法获取库。现在,我从 spark shell 尝试过,一切正常。你曾经在 Jupyter (ipython) notebook 中使用过 spark-csv 库吗?
  • 当然,这种方法应该可以正常工作stackoverflow.com/a/35762809/1560062
  • 它就像魅力一样!谢谢你一百万。我尝试了许多其他选择并花了很多时间。您提供的链接帮助我在几分钟内完成。
  • 很好的答案。我花了几个小时才找到这个完美的
猜你喜欢
  • 2017-01-21
  • 2017-07-10
  • 1970-01-01
  • 2021-06-17
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 2020-10-13
  • 2017-05-23
相关资源
最近更新 更多