Предположим, я делаю что-то вроде:
val df = sqlContext.load("com.databricks.spark.csv", Map("path" -> "cars.csv", "header" -> "true"))
df.printSchema()
root
|-- year: string (nullable = true)
|-- make: string (nullable = true)
|-- model: string (nullable = true)
|-- comment: string (nullable = true)
|-- blank: string (nullable = true)
df.show()
year make model comment blank
2012 Tesla S No comment
1997 Ford E350 Go get one now th...
Но я действительно хотел year
как Int
(и, возможно, преобразовать некоторые другие столбцы).
Лучшее, что я мог придумать, было
df.withColumn("year2", 'year.cast("Int")).select('year2 as 'year, 'make, 'model, 'comment, 'blank)
org.apache.spark.sql.DataFrame = [year: int, make: string, model: string, comment: string, blank: string]
что немного запутано.
Я из R, и я привык писать, например,
df2 <- df %>%
mutate(year = year %>% as.integer,
make = make %>% toupper)
Я, вероятно, что-то упускаю, так как должен быть лучший способ сделать это в Spark / Scala ...
scala
apache-spark
apache-spark-sql
kevinykuo
источник
источник
Ответы:
Редактировать: новейшая версия
С spark 2.x вы можете использовать
.withColumn
. Проверьте документы здесь:https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.sql.Dataset@withColumn(colName:String,col:org.apache.spark.sql.Column) : org.apache.spark.sql.DataFrame
Самый старый ответ
Начиная с версии Spark 1.4 вы можете применить метод cast с DataType к столбцу:
Если вы используете выражения SQL, вы также можете сделать:
Для получения дополнительной информации проверьте документы: http://spark.apache.org/docs/1.6.0/api/scala/#org.apache.spark.sql.DataFrame
источник
df.withColumn("ctr", temp("ctr").cast(DecimalType(decimalPrecision, decimalScale)))
Spark 2.x
,df.withColumn(..)
можно добавить или заменить столбец в зависимости отcolName
аргумента[EDIT: март 2016: спасибо за голоса! Хотя на самом деле, это не самый лучший ответ, я думаю , что решения , основанные на
withColumn
,withColumnRenamed
иcast
выдвинутую msemelman, Мартин Senne и другие проще и чище].Я думаю, что ваш подход в порядке, напомним, что Spark
DataFrame
- это (неизменяемый) RDD Rows, поэтому мы никогда не заменяем столбец, а просто создаемDataFrame
каждый раз новую схему.Предполагая, что у вас есть оригинальный df со следующей схемой:
И некоторые UDF определены в одном или нескольких столбцах:
Изменение типов столбцов или даже создание нового DataFrame из другого можно записать так:
что дает:
Это довольно близко к вашему собственному решению. Проще говоря, хранение изменений типа и других преобразований в качестве отдельных
udf val
элементов делает код более читабельным и пригодным для повторного использования.источник
NULL
или неправильно сформированная запись приведет к краху всей работы. Не эффективный , потому что UDFs не является прозрачным для катализатора. Использование UDF для сложных операций - это нормально, но нет причин использовать их для приведения типов. Вот почему у нас естьcast
метод (см. Ответ Мартина Сенне ). Чтобы сделать Catalyst прозрачным, требуется больше работы, но базовая безопасность - это только вопрос «положиTry
иOption
работай».withColumn()
раздел до общего, который проходит по всем столбцам?Поскольку
cast
операция доступна для SparkColumn
(и, как я лично не одобряюudf
, как предложено @Svend
на данном этапе), как насчет:привести к запрошенному типу? В качестве аккуратного побочного эффекта станут значения, не подлежащие преобразованию / преобразованию в этом смысле
null
.Если вам нужно это как вспомогательный метод , используйте:
который используется как:
источник
Во-первых , если вы хотите использовать тип, то это:
С тем же именем столбца столбец будет заменен новым. Вам не нужно добавлять и удалять шаги.
Во- вторых , о Scala против R .
Это код, который больше всего похож на RI:
Хотя длина кода немного больше, чем у R. Это не имеет ничего общего с многословием языка. В R
mutate
это специальная функция для данных R, а в Scala вы можете легко использовать ее благодаря своей выразительной силе.Словом, он избегает конкретных решений, потому что языковой дизайн достаточно хорош, чтобы вы могли быстро и легко создать свой собственный язык домена.
примечание:
df.columns
на удивлениеArray[String]
вместоArray[Column]
, может быть, они хотят, чтобы он выглядел как датафрейм Python-панд.источник
import org.apache.spark.sql.types._
и тогда, а неsql.types.IntegerType
простоIntegerType
.Вы можете использовать,
selectExpr
чтобы сделать его немного чище:источник
Java-код для изменения типа данных DataFrame с String на Integer
Он просто приведёт существующий тип данных String к Integer.
источник
DataTypes
вsql.types
! этоDataType
. Более того, можно просто импортироватьIntegerType
и разыграть.DataTypes.IntegerType
был в режиме DeveloperAPI, и он стабилен в v.2.1.0Чтобы преобразовать год из строки в int, вы можете добавить следующую опцию в программу чтения csv: "inferSchema" -> "true", см. Документацию DataBricks.
источник
Так что это действительно работает, только если у вас возникли проблемы с сохранением в драйвер jdbc, такой как sqlserver, но это действительно полезно для ошибок, с которыми вы столкнетесь с синтаксисом и типами.
источник
Создайте простой набор данных, содержащий пять значений, и преобразуйте его
int
вstring
тип:источник
Я думаю, что это намного более читабельно для меня.
Это преобразует ваш столбец года в
IntegerType
создание временных столбцов и удаление этих столбцов. Если вы хотите преобразовать в любой другой тип данных, вы можете проверить типы внутриorg.apache.spark.sql.types
пакета.источник
ответы, предлагающие использовать cast, FYI, метод cast в spark 1.4.1 не работает.
например, кадр данных со строковым столбцом, имеющим значение "8182175552014127960" при приведении к bigint, имеет значение "8182175552014128100"
Нам пришлось столкнуться с множеством проблем, прежде чем найти эту ошибку, потому что у нас были колонки bigint в производстве.
источник
источник
Используя Spark Sql 2.4.0, вы можете сделать это:
источник
Вы можете использовать приведенный ниже код.
Какой будет конвертировать год столбец в
IntegerType
колонке.источник
Этот метод удалит старый столбец и создаст новые столбцы с такими же значениями и новым типом данных. Мои оригинальные типы данных при создании DataFrame были: -
После этого я запустил следующий код, чтобы изменить тип данных: -
После этого мой результат оказался:
источник
Можно изменить тип данных столбца, используя приведение в spark sql. имя таблицы - таблица, и она имеет только два столбца: столбец1 и столбец2 и тип данных столбца1 должны быть изменены. ex-spark.sql («выберите приведение (column1 как Double) column1NewName, column2 из таблицы») Вместо двойного запишите свой тип данных.
источник
Если вам нужно переименовать десятки столбцов, заданных их именами, в следующем примере используется подход @dnlbrky и он применяется к нескольким столбцам одновременно:
Неклассированные столбцы остаются без изменений. Все столбцы остаются в исходном порядке.
источник
Так много ответов, а не так много подробных объяснений.
Следующий синтаксис работает с помощью Блокнота данных в Spark 2.4
Обратите внимание, что вы должны указать формат записи, который у вас есть (в моем случае «MM-dd-yyyy»), и импорт является обязательным, поскольку to_date является функцией spark sql.
Также попробовал этот синтаксис, но получил нулевые значения вместо правильного приведения:
(Обратите внимание, что я должен был использовать скобки и кавычки, чтобы это было синтаксически правильным)
PS: Я должен признать, что это похоже на синтаксические джунгли, есть много возможных путей входа, и в официальных ссылках API отсутствуют надлежащие примеры.
источник
Другое решение заключается в следующем:
1) Держите "inferSchema" как ложное
2) Во время выполнения функций «Карта» в строке вы можете прочитать «asString» (row.getString ...)
источник
Почему бы просто не сделать, как описано в http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.Column.cast
источник
источник
По-другому:
источник
В случае, если вы хотите изменить несколько столбцов одного типа на другой без указания имен отдельных столбцов
источник