Supongamos que estoy haciendo algo como:
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...
Pero realmente quería el year
as Int
(y quizás transformar algunas otras columnas).
Lo mejor que se me ocurrió fue
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]
lo cual es un poco complicado.
Vengo de R y estoy acostumbrado a poder escribir, p. Ej.
df2 <- df %>%
mutate(year = year %>% as.integer,
make = make %>% toupper)
Es probable que me falte algo, ya que debería haber una mejor manera de hacer esto en Spark / Scala ...
scala
apache-spark
apache-spark-sql
kevinykuo
fuente
fuente
Respuestas:
Editar: versión más nueva
Desde spark 2.x puedes usar
.withColumn
. Consulta los documentos aquí: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
Respuesta más antigua
Desde Spark versión 1.4, puede aplicar el método de conversión con DataType en la columna:
Si está utilizando expresiones sql, también puede hacer:
Para obtener más información, consulte los documentos: http://spark.apache.org/docs/1.6.0/api/scala/#org.apache.spark.sql.DataFrame
fuente
df.withColumn("ctr", temp("ctr").cast(DecimalType(decimalPrecision, decimalScale)))
Spark 2.x
,df.withColumn(..)
puede agregar o reemplazar una columna según elcolName
argumento[EDITAR: marzo de 2016: gracias por los votos! Aunque en realidad, esto no es la mejor respuesta, creo que las soluciones basadas en
withColumn
,withColumnRenamed
ycast
presentada por msemelman, Martin Senne y otros son más simples y más limpio].Creo que su enfoque está bien, recuerde que un Spark
DataFrame
es un RDD (inmutable) de filas, por lo que nunca estamos reemplazando realmente una columna, solo creando nuevasDataFrame
cada vez con un nuevo esquema.Suponiendo que tiene un df original con el siguiente esquema:
Y algunos UDF definidos en una o varias columnas:
Cambiar los tipos de columna o incluso crear un nuevo DataFrame a partir de otro se puede escribir de esta manera:
cuyos rendimientos:
Esto está bastante cerca de su propia solución. Simplemente, mantener los cambios de tipo y otras transformaciones como elementos separados
udf val
hace que el código sea más legible y reutilizable.fuente
NULL
entrada única o con formato incorrecto bloqueará un trabajo completo. No es eficiente porque los UDF no son transparentes para Catalyst. El uso de UDF para operaciones complejas está bien, pero no hay razón para usarlos para la conversión de tipos básicos. Por eso tenemoscast
método (ver una respuesta de Martin Senne ). Hacer las cosas transparentes para Catalyst requiere más trabajo, pero la seguridad básica es solo cuestión de ponerTry
yOption
trabajar.withColumn()
sección a una genérica que recorra todas las columnas?Como la
cast
operación está disponible para SparkColumn
(y como yo personalmente no estoy a favorudf
de la propuesta por @Svend
en este momento), ¿qué tal si:para emitir al tipo solicitado? Como un efecto secundario ordenado, se convertirán en valores no moldeables / "convertibles" en ese sentido
null
.En caso de que necesite esto como método auxiliar , use:
que se usa como:
fuente
Primero , si quieres emitir un tipo, entonces esto:
Con el mismo nombre de columna, la columna será reemplazada por una nueva. No es necesario agregar ni eliminar pasos.
En segundo lugar , sobre Scala vs R .
Este es el código que más parecido a RI puede tener:
Aunque la longitud del código es un poco más larga que la de R. Eso no tiene nada que ver con la verbosidad del lenguaje. En R the
mutate
es una función especial para el marco de datos R, mientras que en Scala puede ad-hoc fácilmente gracias a su poder expresivo.En resumen, evita soluciones específicas, porque el diseño del lenguaje es lo suficientemente bueno para que pueda construir rápida y fácilmente su propio idioma de dominio.
nota al margen:
df.columns
es sorprendentemente un enArray[String]
lugar deArray[Column]
, tal vez quieren que se vea como el marco de datos de los pandas de Python.fuente
import org.apache.spark.sql.types._
y luego en lugar desql.types.IntegerType
soloIntegerType
.Puedes usar
selectExpr
para hacerlo un poco más limpio:fuente
Código Java para modificar el tipo de datos del DataFrame de String a Integer
Simplemente lanzará el (tipo de datos de cadena) existente a Integer.
fuente
DataTypes
adentrosql.types
! esDataType
. Además, uno simplemente puede importarIntegerType
y emitir.DataTypes.IntegerType
solía estar en modo DeveloperAPI y es estable en v.2.1.0Para convertir el año de cadena a int, puede agregar la siguiente opción al lector csv: "inferSchema" -> "true", consulte la documentación de DataBricks
fuente
Entonces, esto realmente solo funciona si tiene problemas para guardar en un controlador jdbc como sqlserver, pero es realmente útil para los errores con los que se encontrará con la sintaxis y los tipos.
fuente
Genere un conjunto de datos simple que contenga cinco valores y conviértalo
int
astring
tipo:fuente
Creo que esto es mucho más legible para mí.
Esto convertirá su columna de año en
IntegerType
crear columnas temporales y soltar esas columnas. Si desea convertir a cualquier otro tipo de datos, puede verificar los tipos dentro delorg.apache.spark.sql.types
paquete.fuente
las respuestas sugieren usar cast, para su información, el método de lanzamiento en spark 1.4.1 está roto.
por ejemplo, un marco de datos con una columna de cadena que tiene el valor "8182175552014127960" cuando se convierte en bigint tiene el valor "8182175552014128100"
Tuvimos que enfrentar muchos problemas antes de encontrar este error porque teníamos grandes columnas en producción.
fuente
fuente
Usando Spark Sql 2.4.0 puede hacer eso:
fuente
Puedes usar el siguiente código.
Lo que convertirá año columna en
IntegerType
columna.fuente
Este método eliminará la columna anterior y creará nuevas columnas con los mismos valores y un nuevo tipo de datos. Mis tipos de datos originales cuando se creó el DataFrame fueron: -
Después de esto, ejecuté el siguiente código para cambiar el tipo de datos: -
Después de esto, mi resultado resultó ser: -
fuente
Se puede cambiar el tipo de datos de una columna utilizando cast in spark sql. el nombre de la tabla es table y solo tiene dos columnas column1 y column2 y el tipo de datos column1 se debe cambiar. ex-spark.sql ("seleccione cast (column1 como Double) column1NewName, column2 from table") En lugar de double escriba su tipo de datos.
fuente
En caso de que tenga que cambiar el nombre de docenas de columnas dadas por su nombre, el siguiente ejemplo toma el enfoque de @dnlbrky y lo aplica a varias columnas a la vez:
Las columnas no emitidas se mantienen sin cambios. Todas las columnas permanecen en su orden original.
fuente
Tantas respuestas y pocas explicaciones exhaustivas
La siguiente sintaxis funciona con Databricks Notebook con Spark 2.4
Tenga en cuenta que debe especificar el formato de entrada que tiene (en mi caso "MM-dd-aaaa") y la importación es obligatoria ya que to_date es una función de sql spark
También probé esta sintaxis pero obtuve nulos en lugar de un reparto adecuado:
(Tenga en cuenta que tuve que usar corchetes y citas para que sea sintácticamente correcto)
PD: Tengo que admitir que esto es como una jungla de sintaxis, hay muchas formas posibles de puntos de entrada, y las referencias oficiales de la API carecen de ejemplos adecuados.
fuente
Otra solución es la siguiente:
1) Mantenga "inferSchema" como falso
2) Mientras ejecuta las funciones 'Mapa' en la fila, puede leer 'asString' (row.getString ...)
fuente
¿Por qué no hacer lo que se describe en http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.Column.cast
fuente
fuente
De otra manera:
fuente
En caso de que desee cambiar varias columnas de un tipo específico a otro sin especificar nombres de columnas individuales
fuente