Как вывести схему для фрейма данных pyspark? - PullRequest
0 голосов
/ 24 мая 2018

На этом сайте много вопросов относительно того, как преобразовать pyspark rdd в фрейм данных.Но ни один из них не отвечает на вопрос о том, как преобразовать стиль таблицы rdd SQL в фрейм данных, сохранив при этом тип.

У меня есть rdd, который представляет собой список слов в python:

>>> 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'])

Все строки имеют одинаковые столбцы.Все столбцы имеют одинаковый тип данных.Это тривиально превратить в панду в информационный фрейм.

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 голосов
/ 25 мая 2018

Решение здесь находится в строке

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

Всего в этом rdd 1016 строк;но в 6 из этих роз столбец se_category отсутствует.Вот почему вы видите только 1010 dict объектов.Это не проблема для панд, которые просто выводят тип из остальной части столбца и используют пустой объект любого подходящего типа (list -> []; dict -> {}; float или int -> NaN) для заполненияПробелы.

Спарк не делает этого.Если вы думаете об этом с точки зрения 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 в кадр данных.

...