Часто используемые простые, важные и распространенные методы столбцов для эффективного управления фреймами данных / наборами данных.
Большинство операций, которые мы выполняем в Spark, обычно связаны с интенсивным использованием объектов столбцов. Spark имеет богатые функции для манипулирования и преобразования данных столбца. Столбец Dataframe / Dataset в Spark похож на столбец в традиционной базе данных.
Рассмотрим приведенный ниже пример фрейма данных, id
и name
- это столбцы здесь, и они представляют столбец в наборе данных / фрейме данных, который является контейнером для выражения Catalyst (мы можем поговорить о катализаторе как-нибудь в другой раз). В двух словах, катализатор - это структура для работы с деревом, а выражения - это узлы дерева выражений. Для пользователя Spark API id
и name
подобны столбцам таблицы User, как старый добрый SQL.
scala> val got = Seq((1,"Bran"),(2,"Jon")).toDF("id","name") got: org.apache.spark.sql.DataFrame = [id: int, name: string] scala> got.show +---+----+ | id|name| +---+----+ | 1|Bran| | 2| Jon| +---+----+
В Spark есть множество методов для поддержки большого количества операций со столбцами.
Чтобы получить доступ к столбцу из набора данных / фрейма данных:
Допустим, вы хотите получить доступ только к name
из got
фрейма данных. Есть несколько способов сделать это.
scala> import org.apache.spark.sql.functions.col import org.apache.spark.sql.functions.col scala> got.select(col("id")) res17: org.apache.spark.sql.DataFrame = [id: int] scala> import org.apache.spark.sql.functions.column import org.apache.spark.sql.functions.column scala> got.select(column("id")) res18: org.apache.spark.sql.DataFrame = [id: int] scala> import spark.implicits.StringToColumn import spark.implicits.StringToColumn scala> got.select($"id") res19: org.apache.spark.sql.DataFrame = [id: int] scala> import spark.implicits.symbolToColumn import spark.implicits.symbolToColumn scala> got.select('id) res20: org.apache.spark.sql.DataFrame = [id: int] scala> got.select('id).show +---+ | id| +---+ | 1| | 2| +---+
Примечание: если вы используете Spark-Shell, весь этот импорт осуществляется бесплатно. В противном случае некоторые операции импорта придется выполнять вручную. Неявный импорт может быть непростым.
В общем, я считаю, что люди предпочитают сделать import spark.implicits._
и покончить с этим. Кроме того, если вам интересно, какие имплициты используются в scala. Есть удобный способ сделать это.
scala> import scala.reflect.runtime.universe.reify import scala.reflect.runtime.universe.reify scala> println(reify(Seq((1,"Bran"),(2,"Jon")).toDF("id","name"))) Expr[org.apache.spark.sql.DataFrame]($iw.$line3$read.$iw.$iw.spark.implicits.localSeqToDatasetHolder(Seq.apply(Tuple2.apply(1, "Bran"), Tuple2.apply(2, "Jon")))($iw.$line3$read.$iw.$iw.spark.implicits.newProductEncoder(Predef.this.implicitly)).toDF("id", "name"))
Кроме того, у нас могут быть типизированные столбцы, которые в основном представляют собой столбцы с кодировщиком выражений, указанным для ожидаемого типа ввода и возврата.
scala> val name = $"name".as[String] name: org.apache.spark.sql.TypedColumn[Any,String] = name scala> val name = $"name" name: org.apache.spark.sql.ColumnName = name
Существует более 50 методов (67 в последний раз, когда я насчитал), которые можно использовать для преобразований объекта столбца. Мы рассмотрим некоторые из важных методов, которые обычно используются.
!==, +, <=, >, apply, asc_nulls_last, bitwiseXOR, desc_nulls_first, eqNullSafe, expr, gt, isNotNull, like, multiply, otherwise, startsWith, unary_-, %, -, <=>, >=, as, between, cast, desc_nulls_last, equalTo, geq, hashCode, isNull, lt, name, over, substr, when, &&, /, =!=, alias, asc, bitwiseAND, contains, divide, equals, getField, isInCollection, isin, minus, notEqual, plus, toString, ||, *, <, ===, and, asc_nulls_first, bitwiseOR, desc, endsWith, explain, getItem, isNaN, leq, mod, or, rlike, unary_!
Предположим, у нас есть набор данных GOT!
scala> val gotData = Seq((101,"Bran",10,"Stark"),(221,"Jon",16,null),(11,"Ned",50,"Stark"),(21,"Tyrion",40,"Lanister")).toDF("id","name","age","house") gotData: org.apache.spark.sql.DataFrame = [id: int, name: string ... 2 more fields] scala> gotData.show +---+------+---+--------+ | id| name|age| house| +---+------+---+--------+ |101| Bran| 10| Stark| |221| Jon| 16| null| | 11| Ned| 50| Stark| | 21|Tyrion| 40|Lanister| +---+------+---+--------+
1) +
Допустим, вам нужен текущий возраст звезд GOT, добавьте 8 лет к возрасту каждого персонажа и получите новый столбец с текущим возрастом. У нас есть +
для этого:
scala> gotData.withColumn("char_current_age", col("age").+(8)).show() scala> gotData.withColumn("char_current_age", col("age") +8 ).show() +---+------+---+--------+----------------+ | id| name|age| house|char_current_age| +---+------+---+--------+----------------+ |101| Bran| 10| Stark| 18| |221| Jon| 16| null| 24| | 11| Ned| 50| Stark| 58| | 21|Tyrion| 40|Lanister| 48| +---+------+---+--------+----------------+
Вы также можете создать новый фрейм данных, добавив его в столбцы. Но добавляемые типы данных должны, иначе результирующий фрейм данных будет нулевым. Скажем, если вы сделаете gotData(“age”) + gotData(“name”)
, результирующий фрейм данных будет нулевым фреймом. Кроме того, theplus
- это метод, эквивалентный Java.
scala> gotData.select( gotData("age") + gotData("id") ).show +----------+ |(age + id)| +----------+ | 111| | 237| | 61| | 61| +----------+ scala> gotData.select( gotData("age") plus gotData("id") )
2) -
scala> gotData.withColumn("older_than_bran", col("age") - 10 ).show() +---+------+---+--------+---------------+ | id| name|age| house|older_than_bran| +---+------+---+--------+---------------+ |101| Bran| 10| Stark| 0| |221| Jon| 16| null| 6| | 11| Ned| 50| Stark| 40| | 21|Tyrion| 40|Lanister| 30| +---+------+---+--------+---------------+ scala> gotData.withColumn("older_than_bran", col("age") minus 10 )
3)
Точно так же у нас есть *
для умножения, /
для деления и %
для получения мода столбца.
scala> gotData.withColumn("multiply_10", col("age") * 10) scala> gotData.withColumn("multiply_10", col("age") multiply 10) scala> gotData.withColumn("divide_10", col("age") / 10) scala> gotData.withColumn("divide_10", col("age") divide 10) scala> gotData.withColumn("mod_10", col("age") mod 10) scala> gotData.withColumn("mod_10", col("age") % 10)
4) isin (есть в)
Он создает новый столбец с логическим значением, и оценивается предоставленная коллекция ._*
требуется, когда мы проверяем, присутствует ли элемент в коллекции, поскольку метод asin
ожидает переменных аргументов (Any*
). Это особый случай приписывания типа, который сообщает компилятору Scala обрабатывать один аргумент типа последовательности как varargs
.
scala> val teenage = (15 to 25) teenage: scala.collection.immutable.Range.Inclusive = Range(15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25) scala> gotData.withColumn("teenage",col("age").isin(teenage:_*)).show() +---+------+---+--------+-------+ | id| name|age| house|teenage| +---+------+---+--------+-------+ |101| Bran| 10| Stark| false| |221| Jon| 16| null| true| | 11| Ned| 50| Stark| false| | 21|Tyrion| 40|Lanister| false| +---+------+---+--------+-------+ scala> gotData.withColumn("teenage",col("age").isin(15 to 25:_*)) scala> gotData.withColumn("is_Stark",col("house").isin("Stark"))
Мы можем использовать isInCollection
, если вы хотите просто сослаться на коллекцию. Он дает тот же результат. isInCollection
выполняет преобразование в varargs
нотацию.
scala> gotData.withColumn("teenage",col("age").isInCollection(15 to 25))
5) like (нравится)
Это подобное выражение SQL, которое проверяет, содержит ли столбец эти конкретные данные, и возвращает логическое значение. Это также чувствительно к регистру. like(“b%”)
вернет false
.
scala> gotData.withColumn("starts with B",col("name").like("B%")).show() +---+------+---+--------+-------------+ | id| name|age| house|starts with B| +---+------+---+--------+-------------+ |101| Bran| 10| Stark| true| |221| Jon| 16| null| false| | 11| Ned| 50| Stark| false| | 21|Tyrion| 40|Lanister| false| +---+------+---+--------+-------------+ scala> gotData.withColumn("has O ",col("name").like("%o%")).show() +---+------+---+--------+------+ | id| name|age| house|has O | +---+------+---+--------+------+ |101| Bran| 10| Stark| false| |221| Jon| 16| null| true| | 11| Ned| 50| Stark| false| | 21|Tyrion| 40|Lanister| true| +---+------+---+--------+------+
Точно так же есть функция rlike
, которая может использоваться для сопоставления с регулярным выражением.
scala> gotData.withColumn("has O ",col("name").rlike("^(Bran|Jon)")) .show() +---+------+---+--------+------+ | id| name|age| house|has O | +---+------+---+--------+------+ |101| Bran| 10| Stark| true| |221| Jon| 16| null| true| | 11| Ned| 50| Stark| false| | 21|Tyrion| 40|Lanister| false| +---+------+---+--------+------+
Добавление !
отменяет логический вывод и может использоваться для реализации not like
и not rlike
функций.
gotData.withColumn("has O ",!col("name").like("%o%")) gotData.withColumn("has O ",!col("name").rlike("^(Bran|Jon)"))
6) isNull и isNotNull
scala>gotData.withColumn("house_unknown",col("house").isNull).show() +---+------+---+--------+-------------+ | id| name|age| house|house_unknown| +---+------+---+--------+-------------+ |101| Bran| 10| Stark| false| |221| Jon| 16| null| true| | 11| Ned| 50| Stark| false| | 21|Tyrion| 40|Lanister| false| +---+------+---+--------+-------------+ scala>gotData.withColumn("houseNotnull",col("house").isNotNull) .show()
Я расскажу о некоторых других важных методах, которые могут пригодиться в следующей части этой статьи. Спасибо за прочтение! Пожалуйста, поделитесь статьей, если она вам понравилась. Любые комментарии и предложения приветствуются! Ознакомьтесь с другими моими статьями здесь.