Suponha que eu esteja fazendo 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...
Mas eu realmente queria o year
as Int
(e talvez transformar algumas outras colunas).
O melhor que eu pude fazer foi
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]
o que é um pouco complicado.
Eu sou do R e estou acostumado a escrever, por exemplo
df2 <- df %>%
mutate(year = year %>% as.integer,
make = make %>% toupper)
Provavelmente estou perdendo alguma coisa, já que deve haver uma maneira melhor de fazer isso no Spark / Scala ...
scala
apache-spark
apache-spark-sql
kevinykuo
fonte
fonte
Respostas:
Editar: versão mais recente
Desde o spark 2.x você pode usar
.withColumn
. Confira os documentos aqui: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
Resposta mais antiga
Desde o Spark versão 1.4, você pode aplicar o método de conversão com DataType na coluna:
Se você estiver usando expressões sql, também poderá fazer:
Para obter mais informações, consulte os documentos: http://spark.apache.org/docs/1.6.0/api/scala/#org.apache.spark.sql.DataFrame
fonte
df.withColumn("ctr", temp("ctr").cast(DecimalType(decimalPrecision, decimalScale)))
Spark 2.x
,df.withColumn(..)
pode adicionar ou substituir uma coluna dependendo docolName
argumento[EDIT: março de 2016: obrigado pelos votos! Embora, na verdade, esta não é a melhor resposta, eu acho que as soluções baseadas em
withColumn
,withColumnRenamed
ecast
apresentada pelo msemelman, Martin Senne e outros são mais simples e mais limpo].Acho que sua abordagem está correta, lembre-se de que um Spark
DataFrame
é um RDD (imutável) de linhas, portanto nunca substituímos uma coluna, apenas criando novas aDataFrame
cada vez com um novo esquema.Supondo que você tenha um df original com o seguinte esquema:
E algumas UDFs definidas em uma ou várias colunas:
A alteração dos tipos de colunas ou a criação de um novo DataFrame a partir de outro pode ser escrito assim:
que produz:
Isso é bem próximo da sua própria solução. Simplesmente, manter as alterações de tipo e outras transformações como
udf val
s separadas torna o código mais legível e reutilizável.fonte
NULL
entrada única ou malformada trava um trabalho inteiro. Não é eficiente porque os UDFs não são transparentes para o Catalyst. Usar UDFs para operações complexas é bom, mas não há razão para usá-los para a conversão de tipos básicos. É por isso que temoscast
método (veja uma resposta de Martin Senne ). Tornar as coisas transparentes para o Catalyst exige mais trabalho, mas a segurança básica é apenas uma questão de colocarTry
eOption
trabalhar.withColumn()
seção a uma seção genérica que itera por todas as colunas?Como a
cast
operação está disponível para o SparkColumn
(e como eu pessoalmente nãoudf
sou a favor , como proposto por @Svend
neste momento), que tal:transmitir para o tipo solicitado? Como um efeito colateral puro, os valores não convertíveis / "conversíveis" nesse sentido se tornarão
null
.Caso você precise disso como um método auxiliar , use:
que é usado como:
fonte
Primeiro , se você quer transmitir o tipo, então isto:
Com o mesmo nome da coluna, a coluna será substituída por uma nova. Você não precisa adicionar e excluir etapas.
Em segundo lugar , sobre Scala vs R .
Este é o código que mais se assemelha ao RI:
Embora o comprimento do código seja um pouco mais longo que o do R. Isso não tem nada a ver com a verbosidade da linguagem. Em R,
mutate
é uma função especial para o dataframe R, enquanto em Scala você pode facilmente ad-hoc, graças ao seu poder expressivo.Em resumo, evita soluções específicas, porque o design do idioma é bom o suficiente para você criar rápida e facilmente seu próprio idioma de domínio.
nota lateral:
df.columns
é surpreendentemente um emArray[String]
vez deArray[Column]
, talvez eles queiram que pareça com o quadro de dados do Python pandas.fonte
import org.apache.spark.sql.types._
e, em vez desql.types.IntegerType
apenasIntegerType
.Você pode usar
selectExpr
para torná-lo um pouco mais limpo:fonte
Código Java para modificar o tipo de dados do DataFrame de String para Inteiro
Simplesmente converterá o existente (tipo de dados String) para Inteiro.
fonte
DataTypes
dentrosql.types
! ele éDataType
. Além disso, pode-se simplesmente importarIntegerType
e lançar.DataTypes.IntegerType
utilizado para estar em modo DeveloperAPI e é estável em v.2.1.0Para converter o ano de string para int, você pode adicionar a seguinte opção ao leitor csv: "inferSchema" -> "true", consulte a documentação do DataBricks
fonte
Portanto, isso realmente funciona se você tiver problemas para salvar em um driver jdbc como o sqlserver, mas é realmente útil para erros nos quais você encontrará erros de sintaxe e tipos.
fonte
Gere um conjunto de dados simples contendo cinco valores e converta
int
para ostring
tipo:fonte
Eu acho que isso é muito mais legível para mim.
Isso converterá a coluna do ano para
IntegerType
a criação de colunas temporárias e a remoção dessas colunas. Se você deseja converter para qualquer outro tipo de dados, pode verificar os tipos dentro doorg.apache.spark.sql.types
pacote.fonte
as respostas que sugerem o uso de elenco, FYI, o método de elenco no spark 1.4.1 estão quebradas.
por exemplo, um quadro de dados com uma coluna de cadeia com o valor "8182175552014127960" quando convertido em bigint tem o valor "8182175552014128100"
Tivemos que enfrentar muitos problemas antes de encontrar esse bug, porque tínhamos grandes colunas em produção.
fonte
fonte
Usando o Spark Sql 2.4.0, você pode fazer isso:
fonte
Você pode usar o código abaixo.
O qual converterá a coluna do ano em
IntegerType
coluna.fonte
Este método descartará a coluna antiga e criará novas colunas com os mesmos valores e novo tipo de dados. Meus tipos de dados originais quando o DataFrame foi criado foram: -
Depois disso, executei o seguinte código para alterar o tipo de dados: -
Depois disso, meu resultado passou a ser: -
fonte
Pode-se alterar o tipo de dados de uma coluna usando cast no spark sql. nome da tabela é tabela e possui apenas duas colunas, o tipo de dados coluna1 e coluna2 e coluna1 deve ser alterado. ex-spark.sql ("selecione conversão (coluna1 como dupla) column1NewName, coluna2 da tabela") No lugar de dupla, escreva seu tipo de dados.
fonte
Caso você precise renomear dezenas de colunas fornecidas pelo nome, o exemplo a seguir adota a abordagem de @dnlbrky e a aplica a várias colunas ao mesmo tempo:
As colunas não transmitidas são mantidas inalteradas. Todas as colunas permanecem na ordem original.
fonte
Tantas respostas e poucas explicações completas
A sintaxe a seguir funciona Usando o Databricks Notebook com Spark 2.4
Observe que você precisa especificar o formato de entrada que possui (no meu caso "MM-dd-aaaa") e a importação é obrigatória, pois o to_date é uma função spark sql
Também tentei essa sintaxe, mas obtive nulos em vez de uma conversão adequada:
(Observe que eu tive que usar colchetes e aspas para que ela seja sintaxicamente correta)
PS: Eu tenho que admitir que isso é como uma selva de sintaxe, existem muitas maneiras possíveis de pontos de entrada e as referências oficiais da API não têm exemplos adequados.
fonte
Outra solução é a seguinte:
1) Mantenha "inferSchema" como False
2) Ao executar as funções 'Map' na linha, você pode ler 'asString' (row.getString ...)
fonte
Por que não fazer como descrito em http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.Column.cast
fonte
fonte
Outra maneira:
fonte
Caso você queira alterar várias colunas de um tipo específico para outro sem especificar nomes de colunas individuais
fonte