Supposons que je fasse quelque chose comme:
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...
Mais je voulais vraiment le year
as Int
(et peut-être transformer d'autres colonnes).
Le mieux que je pouvais trouver était
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]
ce qui est un peu alambiqué.
Je viens de R, et j'ai l'habitude de pouvoir écrire, par exemple
df2 <- df %>%
mutate(year = year %>% as.integer,
make = make %>% toupper)
Il me manque probablement quelque chose, car il devrait y avoir une meilleure façon de le faire dans Spark / Scala ...
scala
apache-spark
apache-spark-sql
kevinykuo
la source
la source
Réponses:
Edit: version la plus récente
Depuis spark 2.x, vous pouvez utiliser
.withColumn
. Consultez les documents ici: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
La plus ancienne réponse
Depuis Spark version 1.4, vous pouvez appliquer la méthode cast avec DataType sur la colonne:
Si vous utilisez des expressions SQL, vous pouvez également faire:
Pour plus d'informations, consultez la documentation: http://spark.apache.org/docs/1.6.0/api/scala/#org.apache.spark.sql.DataFrame
la source
df.withColumn("ctr", temp("ctr").cast(DecimalType(decimalPrecision, decimalScale)))
Spark 2.x
,df.withColumn(..)
peut ajouter ou remplacer une colonne en fonction de l'colName
argument[EDIT: mars 2016: merci pour les votes! Bien que vraiment, ce n'est pas la meilleure réponse, je pense que les solutions basées sur
withColumn
,withColumnRenamed
etcast
mis en avant par msemelman, Martin Senne et d' autres sont plus simples et plus propre].Je pense que votre approche est ok, rappeler qu'une Spark
DataFrame
est un (immuable) RDD de lignes, donc nous ne sommes jamais vraiment remplacer une colonne, juste créer une nouvelle àDataFrame
chaque fois avec un nouveau schéma.En supposant que vous ayez un df original avec le schéma suivant:
Et certains UDF définis sur une ou plusieurs colonnes:
Changer les types de colonnes ou même construire un nouveau DataFrame à partir d'un autre peut être écrit comme ceci:
ce qui donne:
C'est assez proche de votre propre solution. Simplement, garder les changements de type et autres transformations comme des
udf val
s séparés rend le code plus lisible et réutilisable.la source
NULL
entrée unique ou mal formée plantera un travail entier. Pas efficace car les UDF ne sont pas transparents pour Catalyst. Utiliser des UDF pour des opérations complexes est très bien, mais il n'y a aucune raison de les utiliser pour la conversion de type de base. C'est pourquoi nous avons lacast
méthode (voir une réponse de Martin Senne ). Rendre les choses transparentes pour Catalyst nécessite plus de travail, mais la sécurité de base n'est qu'une question de miseTry
etOption
de travail.withColumn()
section à une section générique qui parcourt toutes les colonnes?Comme l'
cast
opération est disponible pour SparkColumn
(et comme je ne suis personnellement pas favorable àudf
celle proposée par @Svend
à ce stade), que diriez-vous:cast au type demandé? En tant qu'effet secondaire soigné, les valeurs non castables / "convertibles" dans ce sens deviendront
null
.Si vous en avez besoin comme méthode d'assistance , utilisez:
qui est utilisé comme:
la source
Premièrement , si vous voulez lancer du type, alors ceci:
Avec le même nom de colonne, la colonne sera remplacée par une nouvelle. Vous n'avez pas besoin d'ajouter et de supprimer des étapes.
Deuxièmement , à propos de Scala vs R .
Voici le code le plus similaire à RI:
Bien que la longueur du code soit un peu plus longue que celle de R. Cela n'a rien à voir avec la verbosité de la langue. Dans R, il
mutate
existe une fonction spéciale pour R dataframe, tandis que dans Scala, vous pouvez facilement en ad-hoc grâce à sa puissance expressive.En bref, cela évite les solutions spécifiques, car la conception du langage est suffisamment bonne pour que vous puissiez créer rapidement et facilement votre propre langage de domaine.
note latérale:
df.columns
est étonnamment unArray[String]
au lieu deArray[Column]
, peut-être qu'ils veulent que cela ressemble au dataframe de pandas Python.la source
import org.apache.spark.sql.types._
et alors au lieu desql.types.IntegerType
simplementIntegerType
.Vous pouvez utiliser
selectExpr
pour le rendre un peu plus propre:la source
Code Java pour modifier le type de données du DataFrame de String en Integer
Il convertira simplement le (type de données String) existant en Integer.
la source
DataTypes
dedanssql.types
! c'estDataType
. De plus, on peut simplement importerIntegerType
et lancer.DataTypes.IntegerType
était en mode DeveloperAPI et il est stable dans la v.2.1.0Pour convertir l'année de chaîne en entier, vous pouvez ajouter l'option suivante au lecteur csv: "inferSchema" -> "true", voir la documentation DataBricks
la source
Donc, cela ne fonctionne vraiment que si vous rencontrez des problèmes pour enregistrer dans un pilote jdbc comme sqlserver, mais c'est vraiment utile pour les erreurs que vous rencontrerez avec la syntaxe et les types.
la source
Générez un jeu de données simple contenant cinq valeurs et convertissez-le
int
enstring
type:la source
Je pense que c'est beaucoup plus lisible pour moi.
Cela convertira votre colonne d'année en
IntegerType
en créant des colonnes temporaires et en supprimant ces colonnes. Si vous souhaitez convertir en un autre type de données, vous pouvez vérifier les types à l'intérieur duorg.apache.spark.sql.types
package.la source
les réponses suggérant d'utiliser la fonte, FYI, la méthode de fonte dans l'étincelle 1.4.1 est cassée.
par exemple, une trame de données avec une colonne de chaîne ayant la valeur "8182175552014127960" lorsqu'elle est convertie en bigint a la valeur "8182175552014128100"
Nous avons dû faire face à de nombreux problèmes avant de trouver ce bogue car nous avions des colonnes bigint en production.
la source
la source
En utilisant Spark Sql 2.4.0, vous pouvez le faire:
la source
Vous pouvez utiliser le code ci-dessous.
Qui convertira la colonne de l' année en
IntegerType
colonne.la source
Cette méthode supprimera l'ancienne colonne et créera de nouvelles colonnes avec les mêmes valeurs et un nouveau type de données. Mes types de données d'origine lors de la création du DataFrame étaient: -
Après cela, j'ai exécuté le code suivant pour changer le type de données: -
Après cela, mon résultat est devenu: -
la source
On peut changer le type de données d'une colonne en utilisant cast dans spark sql. Le nom de la table est table et il a deux colonnes, seuls les types de données colonne1 et colonne2 et colonne1 doivent être modifiés. ex-spark.sql ("sélectionnez cast (colonne1 comme double) colonne1NouveauNom, colonne2 de la table") À la place de double, écrivez votre type de données.
la source
Si vous devez renommer des dizaines de colonnes données par leur nom, l'exemple suivant adopte l'approche de @dnlbrky et l'applique à plusieurs colonnes à la fois:
Les colonnes non castées restent inchangées. Toutes les colonnes restent dans leur ordre d'origine.
la source
Tant de réponses et peu d'explications approfondies
La syntaxe suivante fonctionne avec Databricks Notebook avec Spark 2.4
Notez que vous devez spécifier le format d'entrée que vous avez (dans mon cas "MM-jj-aaaa") et l'importation est obligatoire car le to_date est une fonction Spark SQL
J'ai également essayé cette syntaxe, mais j'ai obtenu des valeurs nulles au lieu d'une conversion appropriée:
(Notez que j'ai dû utiliser des crochets et des guillemets pour que la syntaxe soit correcte)
PS: Je dois admettre que c'est comme une jungle de syntaxe, il existe de nombreuses façons possibles de points d'entrée, et les références officielles de l'API manquent d'exemples appropriés.
la source
Une autre solution est la suivante:
1) Gardez "inferSchema" comme False
2) Lors de l'exécution des fonctions 'Map' sur la ligne, vous pouvez lire 'asString' (row.getString ...)
la source
Pourquoi ne pas simplement faire comme décrit sous http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.Column.cast
la source
la source
Autrement:
la source
Si vous souhaitez remplacer plusieurs colonnes d'un type spécifique par une autre sans spécifier de noms de colonnes individuels
la source