Załóżmy, że robię coś takiego:
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...
Ale naprawdę chciałem year
as Int
(i być może przekształcić kilka innych kolumn).
Najlepsze, co mogłem wymyślić, to
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]
co jest nieco zawiłe.
Pochodzę z R i jestem przyzwyczajony do pisania np
df2 <- df %>%
mutate(year = year %>% as.integer,
make = make %>% toupper)
Prawdopodobnie czegoś mi brakuje, ponieważ powinien być lepszy sposób na zrobienie tego w Spark / Scala ...
scala
apache-spark
apache-spark-sql
kevinykuo
źródło
źródło
Odpowiedzi:
Edycja: najnowsza wersja
Od Spark 2.x możesz używać
.withColumn
. Sprawdź dokumenty tutaj: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
Najstarsza odpowiedź
Od wersji Spark 1.4 możesz zastosować metodę rzutowania z DataType w kolumnie:
Jeśli używasz wyrażeń sql, możesz również wykonać:
Więcej informacji można znaleźć w dokumentacji: http://spark.apache.org/docs/1.6.0/api/scala/#org.apache.spark.sql.DataFrame
źródło
df.withColumn("ctr", temp("ctr").cast(DecimalType(decimalPrecision, decimalScale)))
Spark 2.x
,df.withColumn(..)
można dodać lub wymienić kolumny w zależności odcolName
argumentu[EDYCJA: marzec 2016 r .: dzięki za głosy! Choć tak naprawdę, to nie jest najlepsza odpowiedź, myślę, że rozwiązania oparte na
withColumn
,withColumnRenamed
acast
podniesione przez msemelman Martin Senne i inni są prostsze i czystsze].Myślę, że twoje podejście jest w porządku, pamiętaj, że Spark
DataFrame
jest (niezmiennym) RDD wierszy, więc tak naprawdę nigdy nie zastępujemy kolumny, po prostu tworzymy nowy zaDataFrame
każdym razem z nowym schematem.Zakładając, że masz oryginalny plik df z następującym schematem:
I niektóre UDF zdefiniowane w jednej lub kilku kolumnach:
Zmiana typów kolumn, a nawet tworzenie nowej ramki DataFrame z innej, można zapisać w następujący sposób:
co daje:
Jest to bardzo zbliżone do twojego własnego rozwiązania. Po prostu zachowanie zmian typu i innych przekształceń jako oddzielnych
udf val
sprawia, że kod jest bardziej czytelny i można go ponownie wykorzystać.źródło
NULL
lub źle sformułowany wpis spowoduje awarię całej pracy. Nie wydajne UDF, ponieważ nie są przezroczyste dla Catalyst. Używanie funkcji UDF do złożonych operacji jest w porządku, ale nie ma powodu, aby używać ich do rzutowania typu podstawowego. Dlatego mamycast
metodę (zobacz odpowiedź Martina Senne ). Zapewnienie przejrzystości Catalyst wymaga więcej pracy, ale podstawowe bezpieczeństwo to tylko kwestia wprowadzeniaTry
iOption
wykonania.withColumn()
sekcji do ogólnej, która iteruje przez wszystkie kolumny?Ponieważ
cast
operacja jest dostępna dla SparkaColumn
(i osobiście nie popieramudf
proponowanej przez @Svend
w tym momencie), co powiesz na:rzutować na żądany typ? Jako fajny efekt uboczny, wartości, których nie można rzutować / „konwertować” w tym sensie, staną się
null
.Jeśli potrzebujesz tego jako metody pomocniczej , użyj:
który jest używany jak:
źródło
Po pierwsze , jeśli chcesz przesyłać typ, to:
Kolumna o tej samej nazwie zostanie zastąpiona nową. Nie musisz dodawać ani usuwać kroków.
Po drugie , o Scala vs R .
Oto kod, który najbardziej przypomina RI:
Chociaż długość kodu jest nieco dłuższa niż R. Nie ma to nic wspólnego z gadatliwością języka. W R
mutate
jest to specjalna funkcja dla R dataframe, natomiast w Scali można ją łatwo ad-hoc dzięki jej ekspresyjnej sile.Słowem, unika konkretnych rozwiązań, ponieważ projekt języka jest wystarczająco dobry, abyś mógł szybko i łatwo zbudować własny język domeny.
uwaga boczna:
df.columns
jest zaskakująco aArray[String]
zamiastArray[Column]
, może chcą, aby wyglądało jak ramka danych pandy w Pythonie.źródło
import org.apache.spark.sql.types._
a następnie zamiast posql.types.IntegerType
prostuIntegerType
.Możesz użyć,
selectExpr
aby uczynić go trochę czystszym:źródło
Kod Java służący do modyfikowania typu danych DataFrame z String na Integer
Po prostu przerzuci istniejący (typ danych String) na liczbę całkowitą.
źródło
DataTypes
wsql.types
! to jestDataType
. Co więcej, można po prostu importowaćIntegerType
i przesyłać.DataTypes.IntegerType
był w trybie DeveloperAPI i jest stabilny w wersji 2.1.0Aby przekonwertować rok ze string na int, możesz dodać następującą opcję do czytnika csv: "inferSchema" -> "true", zobacz dokumentację DataBricks
źródło
Więc to naprawdę działa tylko wtedy, gdy masz problemy z zapisywaniem do sterownika jdbc, takiego jak sqlserver, ale jest naprawdę pomocne w przypadku błędów, które napotkasz ze składnią i typami.
źródło
Wygeneruj prosty zbiór danych zawierający pięć wartości i przekonwertuj
int
nastring
typ:źródło
Myślę, że jest to dla mnie dużo bardziej czytelne.
Spowoduje to konwersję kolumny roku na
IntegerType
z utworzeniem jakichkolwiek kolumn tymczasowych i upuszczeniem tych kolumn. Jeśli chcesz przekonwertować na inny typ danych, możesz sprawdzić typy worg.apache.spark.sql.types
pakiecie.źródło
odpowiedzi sugerujące użycie cast, FYI, metoda cast w Spark 1.4.1 jest zepsuta.
na przykład ramka danych z kolumną łańcuchową o wartości „8182175552014127960” po rzutowaniu na bigint ma wartość „8182175552014128100”
Musieliśmy zmierzyć się z wieloma problemami, zanim znaleźliśmy ten błąd, ponieważ mieliśmy kolumny bigint w produkcji.
źródło
źródło
Używając Spark Sql 2.4.0 możesz to zrobić:
źródło
Możesz użyć poniższego kodu.
Który przekształci kolumnę roku w
IntegerType
kolumnę.źródło
Ta metoda spowoduje usunięcie starej kolumny i utworzenie nowych kolumn z tymi samymi wartościami i nowym typem danych. Moje oryginalne typy danych podczas tworzenia DataFrame to: -
Po tym uruchomiłem następujący kod, aby zmienić typ danych: -
Po tym mój wynik wyszedł: -
źródło
Można zmienić typ danych kolumny za pomocą rzutowania w Spark sql. nazwa tabeli to tabela i ma dwie kolumny, tylko typ danych kolumna1 i kolumna2, a typ danych kolumna1 ma zostać zmieniony. ex-spark.sql ("select cast (column1 as Double) column1NewName, column2 from table") W miejsce double zapisz swój typ danych.
źródło
W przypadku, gdy musisz zmienić nazwę dziesiątek kolumn podanych przez ich nazwę, poniższy przykład przyjmuje podejście @dnlbrky i stosuje je do kilku kolumn jednocześnie:
Nieobrzucone kolumny pozostają niezmienione. Wszystkie kolumny pozostają w pierwotnej kolejności.
źródło
Tyle odpowiedzi i niewiele dokładnych wyjaśnień
Następująca składnia działa przy użyciu Notatnika Databricks ze Spark 2.4
Zauważ, że musisz określić format wpisu jaki posiadasz (w moim przypadku "MM-dd-rrrr"), a import jest obowiązkowy, ponieważ to_date jest funkcją iskrową sql
Wypróbowałem również tę składnię, ale otrzymałem wartości null zamiast prawidłowego rzutowania:
(Uwaga, musiałem użyć nawiasów i cudzysłowów, aby było to poprawne składniowo)
PS: Muszę przyznać, że to jest jak dżungla składni, istnieje wiele możliwych sposobów wejścia, a oficjalne odniesienia do API nie mają odpowiednich przykładów.
źródło
Inne rozwiązanie jest następujące:
1) Zachowaj „inferSchema” jako False
2) Podczas uruchamiania funkcji „Map” w wierszu można odczytać „asString” (row.getString ...)
źródło
Dlaczego nie zrobić tak, jak opisano w http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.Column.cast
źródło
źródło
Inny sposób:
źródło
W przypadku, gdy chcesz zmienić wiele kolumn określonego typu na inne bez określania nazw poszczególnych kolumn
źródło