如何推断pyspark数据帧的模式?

时间:2018-05-23 21:49:30

标签: python-3.x dataframe pyspark rdd

本网站上有很多关于如何将pyspark rdd转换为数据帧的问题。但是他们都没有回答如何在保留类型的同时将SQL表样式rdd转换为数据帧的问题。

我有一个rdd,它正是python中的dicts列表:

>>> rdd.take(1)

[{'se_error': 0, 'se_subjective_count': 0, 'se_word_count': 10, 'se_entity_summary_topic_phrases': {}, 'se_entity_hits': 1, 'se_entity_summary': 'rt @mercuryinrx: disgusting. cut it out FOCALENTITY twitter.com/anons4cetacean', 'se_query_with_hits': 0, 'id': 180034992495.0, 'se_objective_count': 2, 'se_category': {}, 'se_sentence_count': 2, 'se_entity_sentiment': 0.0, 'se_document_sentiment': -0.49000000953674316, 'se_entity_themes': {}, 'se_query_hits': 0, 'se_named_entities': {}}]

>>> rdd.take(1)[0].keys()

dict_keys(['se_error', 'se_subjective_count', 'se_word_count', 'se_entity_summary_topic_phrases', 'se_entity_hits', 'se_entity_summary', 'se_query_with_hits', 'id', 'se_objective_count', 'se_category', 'se_sentence_count', 'se_entity_sentiment', 'se_document_sentiment', 'se_entity_themes', 'se_query_hits', 'se_named_entities'])

所有行都具有相同的列。所有列都具有相同的数据类型。在pandas中变成数据帧是微不足道的。

out = rdd.take(rdd.count())
outdf = pd.DataFrame(out)

这当然违背了使用火花的目的!我可以证明列也是相同的数据类型。

>>> typemap = [{key: type(val) for key, val in row.items()} for row in out]
>>> typedf = pd.DataFrame(typemap)
>>> for col in list(typedf):
>>>     typedf[col].value_counts()

<class 'float'>    1016
Name: id, dtype: int64
<class 'dict'>    1010
Name: se_category, dtype: int64
<class 'float'>    1010
Name: se_document_sentiment, dtype: int64
<class 'int'>    1010
Name: se_entity_hits, dtype: int64
...

它继续走得更远,但它们都是一种类型;否则他们就是非法。

我如何在火花中做到这一点?以下是一些不起作用的尝试:

>>> outputDf = rdd.toDF()

...
ValueError: Some of types cannot be determined by the first 100 rows, please try again with sampling

>>> outputDf = rdd.toDF(sampleRatio=0.1)

...
File "/usr/hdp/current/spark-client/python/pyspark/sql/types.py", line 905, in <lambda>
    return lambda row: dict((kconv(k), vconv(v)) for k, v in row.items())
AttributeError: 'NoneType' object has no attribute 'items'

这是什么问题?为什么在只有一个python数据类型的列中找出数据类型如此困难?

1 个答案:

答案 0 :(得分:0)

此处的解决方案在

<class 'float'>    1016
Name: id, dtype: int64
<class 'dict'>    1010
Name: se_category, dtype: int64

此rdd共有1016行;但是其中6个上升了,列se_category不存在。这就是为什么你只看到1010 dict个对象。这对于pandas来说没有问题,它只是从列的其余部分推断出类型并使用任何适当类型的空对象(list - &gt; []; dict - &gt; {}; float或int - &gt; NaN)到填补空白。

Spark不会这样做。如果从Java的角度考虑它,这是rdd对象的基础语言,这就完全有道理了。由于我一直在编写python,一种动态类型的语言,一段时间以来,我没有立即想到这是一个问题。但是在静态类型的语言中,可以预期某些东西在编译时具有已定义的类型。

解决方案是将每一行作为一组具有类型的对象“声明”返回到rdd;从而模仿静态打字。所以我宣布

{"int_field": 0; "list_field": []; "float_field": 0.0, "string_field": ""}

在我填写任何值之前。这样,如果我的函数没有更新该值,则生成rdd;该行仍然具有所有正确的类型,并且

outputDf = rdd.map(lambda x: Row(**x)).toDF()

成功将此rdd转换为数据帧。