Nano Hash - криптовалюты, майнинг, программирование

Как использовать структуры для имен столбцов и значений?

Я играю со Spark в Scala. У меня есть эта структура:

case class MovieRatings(movieName: String, rating: Double)
case class MovieCritics(name: String, movieRatings: List[MovieRatings])

Первоклассный фильм и рейтинг, данный каким-то критиком. Это может быть что-то вроде этого:

MovieRatings("Logan", 1.5)

и второй класс, который принимает имя критика и список классифицированных им фильмов. С этим я придумал список кинокритиков, и каждый элемент списка имеет имя и список кинорейтингов. Все идет нормально. Теперь я хочу преобразовать этот список в искровой фрейм данных, чтобы отображать данные в более удобном для пользователя виде. Что-то вроде этого:

Critic | Logan | Zoolander | John Wick | ...
Manuel    1.5       3            2.5
John      2         3.5          3
...

Первый столбец отражает кинокритика, а следующие столбцы представляют фильм и соответствующую оценку, данную критиком. Мой вопрос заключается в том, как преобразовать

List(MovieCritics(name: String, movieRatings: List[MovieRatings]))

в этом представлении.


Ответы:


1

Если у вас есть данные фильмов как

val movieCritics = List(
  MovieCritics("Manual", List(MovieRatings("Logan", 1.5), MovieRatings("Zoolander", 3), MovieRatings("John Wick", 2.5))),
  MovieCritics("John", List(MovieRatings("Logan", 2), MovieRatings("Zoolander", 3.5), MovieRatings("John Wick", 3)))
)

Вы можете создать dataframe, просто вызвав toDF как

import sqlContext.implicits._
val df = movieCritics.toDF

Что должно быть

+------+-----------------------------------------------+
|name  |movieRatings                                   |
+------+-----------------------------------------------+
|Manual|[[Logan,1.5], [Zoolander,3.0], [John Wick,2.5]]|
|John  |[[Logan,2.0], [Zoolander,3.5], [John Wick,3.0]]|
+------+-----------------------------------------------+

Теперь простой select сверху dataframe должен дать вам нужный результат.

import org.apache.spark.sql.functions._
df.select(col("name"), col("movieRatings")(0)("rating").as("Logan"), col("movieRatings")(1)("rating").as("Zoolander"), col("movieRatings")(2)("rating").as("John Wick")).show(false)

В результате окончательный кадр данных должен выглядеть как

+------+-----+---------+---------+
|name  |Logan|Zoolander|John Wick|
+------+-----+---------+---------+
|Manual|1.5  |3.0      |2.5      |
|John  |2.0  |3.5      |3.0      |
+------+-----+---------+---------+
27.06.2017
  • Красивый!!! Это именно то, что я искал. Я повторял списки в списках, чтобы преобразовать исходные данные, но я знал, что это уродливо и должно быть по-другому (я даю свои первые шаги в scala и spark) 27.06.2017
  • Это близко, но не то решение, которое я искал бы :) Это предполагает количество столбцов для фильмов и их названия. Если это цель ОП, хорошо, но подумал, что это будет слишком много предположений. Как насчет этого вызова? Я нахожусь близко... 27.06.2017
  • @Jaceb Laskowski, ты прав, но я делаю маленькие шаги. Теперь я знаю, как преобразовать данные. Следующим шагом будет то, как это сделать, если у меня есть, скажем, 100 фильмов и я априори не знаю их названий. Более динамичная вещь. В любом случае спасибо за помощь 27.06.2017
  • Смотрите мой ответ, который, я думаю, вам может понравиться. У меня ушло больше часа (!) 27.06.2017

  • 2

    как трансформировать List(MovieCritics(name: String, movieRatings: List[MovieRatings]))

    Это так же просто, как использовать toDS на List. Это доступно, только если у вас есть имплициты в области действия, которая (опять же) так же проста, как следующее:

    val sparkSession = SparkSession.builder.getOrCreate()
    import sparkSession.implicits._
    

    Если вы работаете с scala.collection.immutable.Iterable[MovieCritics] или аналогичной структурой данных коллекции, вы должны «отобразить» ее, используя toSeq или toArray перед toDS, чтобы «убежать» из Iterable. Неявные значения недоступны для Iterables.

    Учитывая, что список critics, вам нужно будет сделать следующее:

    critics.toDS
    

    Теперь я хочу преобразовать этот список в искровой фрейм данных, чтобы отображать данные в более удобном для пользователя виде.

    Это самая интересная часть вашего вопроса (мне потребовалось пару часов, чтобы наконец понять и написать решение). Я был бы признателен за комментарии, чтобы сделать его красивее.

    case class MovieRatings(movieName: String, rating: Double)
    case class MovieCritics(name: String, movieRatings: Seq[MovieRatings])
    val movies_critics = Seq(
      MovieCritics("Manuel", Seq(MovieRatings("Logan", 1.5), MovieRatings("Zoolander", 3), MovieRatings("John Wick", 2.5))),
      MovieCritics("John", Seq(MovieRatings("Logan", 2), MovieRatings("Zoolander", 3.5), MovieRatings("John Wick", 3))))
    

    С набором входных данных приходит решение.

    val ratings = movies_critics.toDF
    scala> ratings.show(false)
    +------+-----------------------------------------------+
    |name  |movieRatings                                   |
    +------+-----------------------------------------------+
    |Manuel|[[Logan,1.5], [Zoolander,3.0], [John Wick,2.5]]|
    |John  |[[Logan,2.0], [Zoolander,3.5], [John Wick,3.0]]|
    +------+-----------------------------------------------+
    
    val ratingsCount = ratings.
      withColumn("size", size($"movieRatings")).
      select(max("size")).
      as[Int].
      head
    
    val names_ratings = (0 until ratingsCount).
      foldLeft(ratings) { case (ds, counter) => ds.
        withColumn(s"name_$counter", $"movieRatings"(counter)("movieName")).
        withColumn(s"rating_$counter", $"movieRatings"(counter)("rating")) }
    
    val movieColumns = names_ratings.
      columns.
      drop(1).
      filter(name => name.startsWith("name")).
      map(col)
    val movieNames = names_ratings.select(movieColumns: _*).head.toSeq.map(_.toString)
    val ratingNames = movieNames.indices.map(idx => s"rating_$idx")
    val cols = movieNames.zip(ratingNames).map { case (movie, rn) =>
      col(rn) as movie
    }
    val solution = names_ratings.select(($"name" +: cols): _*)
    scala> solution.show
    +------+-----+---------+---------+
    |  name|Logan|Zoolander|John Wick|
    +------+-----+---------+---------+
    |Manuel|  1.5|      3.0|      2.5|
    |  John|  2.0|      3.5|      3.0|
    +------+-----+---------+---------+
    
    27.06.2017
  • Очень круто @JacekLaskowski, действительно очень круто!! Большое спасибо за усилия. Теперь пришло мое время переварить всю эту информацию. Происходит много всего. И, кстати, теперь у моего первоначального вопроса хорошее название :) 28.06.2017
  • @MLeiria Прошу прощения за первый же неприятный эффект :) Если понравилось, одобряйте. Мне действительно потребовалось некоторое усилие. Надеюсь сэкономить время некоторых людей. И твое тоже. Спасибо за идею! 28.06.2017
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..