Примеры кода на Kotlin в Jupyter Notebook — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Добавление зависимостей)
(Функциональный стиль с библиотекой krangl)
(не показано 12 промежуточных версий этого же участника)
Строка 23: Строка 23:
  
  
Также Котлин имеет имеет такую особенность дизайна языка, как ''null-safety'' и предоставляет такие операторы, как: ''safe call operator, elvis operator, not-null assertion operator'', что позволяет ему быть более типобезопасным, по сравнению с Python:
+
Также Котлин имеет имеет такую особенность дизайна языка, как ''null-safety'' и предоставляет такие операторы, как: ''safe call operator, elvis operator, not-null assertion operator'', что позволяет ему быть более типобезопасным, по сравнениюc с Python:
'''Kotlin'''
 
  
 
  var a: String = "abc"
 
  var a: String = "abc"
Строка 33: Строка 32:
 
Помимо функционального синтаксиса и конструкций, Котлин также предоставляет набор математических и machine learning библиотек, а также инструментов для Data Science, в том числе, интегрированность с Jupyter Notebook.
 
Помимо функционального синтаксиса и конструкций, Котлин также предоставляет набор математических и machine learning библиотек, а также инструментов для Data Science, в том числе, интегрированность с Jupyter Notebook.
  
==Kotlin в Jupyter Notebook==
+
==Установка Kotlin в Jupyter Notebook==
  
 
'''Kernel в Jupyter Notebook '''- это вычислительный движок, который исполняет код в данном документе и запускается автоматически при запуске ассоциированного с ним Jupyter Notebook документа. Они существуют для разных языков, например, ipython kernel исполняет Pythod код, а Kotlin kernel - Kotlin код в Jupyter Notebook. Именно '''Kotlin kernel''' позволяет писать и запускать код в Jupyter Notebook, а также использовать библиотеки и фреймворки, написанные на Java и Kotlin.
 
'''Kernel в Jupyter Notebook '''- это вычислительный движок, который исполняет код в данном документе и запускается автоматически при запуске ассоциированного с ним Jupyter Notebook документа. Они существуют для разных языков, например, ipython kernel исполняет Pythod код, а Kotlin kernel - Kotlin код в Jupyter Notebook. Именно '''Kotlin kernel''' позволяет писать и запускать код в Jupyter Notebook, а также использовать библиотеки и фреймворки, написанные на Java и Kotlin.
Строка 41: Строка 40:
 
Обратите внимание, что Kotlin Jupyter требует установленной Java 8:
 
Обратите внимание, что Kotlin Jupyter требует установленной Java 8:
 
  apt-get install openjdk-8-jre
 
  apt-get install openjdk-8-jre
 
  
 
==Поддерживаемые библиотеки==
 
==Поддерживаемые библиотеки==
* '''[https://github.com/thomasnield/kotlin-statistics kotlin-statistics''']''' $-$ предоставляет расширения для функций для подсчета статистики. Поддерживает основные list/sequence/array functions, slicing operators (countBy, simpleRegressionBy, etc), binning operations, discrete PDF sampling, naive bayes classifier, clustering, linear regression, и другое
+
* '''[https://github.com/thomasnield/kotlin-statistics kotlin-statistics]''' - предоставляет расширения для функций для подсчета статистики. Поддерживает основные list/sequence/array functions, slicing operators (countBy, simpleRegressionBy, etc), binning operations, discrete PDF sampling, naive bayes classifier, clustering, linear regression, и другое
* '''[https://github.com/mipt-npm/kmath kmath''']''' $-$ поддерживает алгебраические структуры и операторы, математические выражения,  гистограммы, потоковые операции, обертки над  commons-math и  koma, и другое. Вдохновлена numpy
+
* '''[https://github.com/mipt-npm/kmath kmath'''] - поддерживает алгебраические структуры и операторы, математические выражения,  гистограммы, потоковые операции, обертки над  commons-math и  koma, и другое. Вдохновлена numpy
* '''[https://github.com/holgerbrandl/krangl Krangl''']''' $-$ предоставляет функционал для обработки данных в функциональном стиле(filter, transform, aggregate, reshape и др.) Вдохновлена pandas
+
* '''[https://github.com/holgerbrandl/krangl Krangl'''] - предоставляет функционал для обработки данных в функциональном стиле(filter, transform, aggregate, reshape и др.) Вдохновлена pandas
* '''[https://github.com/JetBrains/lets-plot lets-plot''']''' $-$ Мультиплатформенная библиотека для создания графиков из данных. Может использоваться не только в JVM, но также JS and Python.
+
* '''[https://github.com/JetBrains/lets-plot lets-plot]''' - Мультиплатформенная библиотека для создания графиков из данных. Может использоваться не только в JVM, но также JS and Python.
* '''[https://github.com/holgerbrandl/kravis kravis''']''' $-$ библиотека для визуализации данных.
+
* '''[https://github.com/holgerbrandl/kravis kravis]''' - библиотека для визуализации данных.
* '''[https://github.com/cbeust/klaxon klaxon''']''' $-$ Котлин JSON парсер
+
* '''[https://github.com/cbeust/klaxon klaxon]''' $-$ Котлин JSON парсер
* '''[https://github.com/apache/spark spark''']''' $-$  Фреймворк для распределённой обработки неструктурированных и слабоструктурированных данных
+
* '''[https://github.com/apache/spark spark'''] $-$  Фреймворк для распределённой обработки неструктурированных и слабоструктурированных данных
* '''[https://github.com/eseifert/gral gral''']''' $-$ Java библиотека для отображения графиков
+
* '''[https://github.com/eseifert/gral gral'''] $-$ Java библиотека для отображения графиков
* '''[https://koma.kyonifer.com/index.html koma''']''' $-$ Котлин библиотека для научных вычислений
+
* '''[https://koma.kyonifer.com/index.html koma'''] $-$ Котлин библиотека для научных вычислений
* '''[https://github.com/Kotlin/kotlin-numpy numpy''']''' $-$ Kотлин обертка над Python NumPy  
+
* '''[https://github.com/Kotlin/kotlin-numpy numpy'''] $-$ Kотлин обертка над Python NumPy  
* '''[https://github.com/JetBrains/Exposed exposed''']''' $-$ Kотлин SQL фреймворк
+
* '''[https://github.com/JetBrains/Exposed exposed]''' $-$ Kотлин SQL фреймворк
* '''[https://github.com/mysql/mysql-connector-j mysql''']''' $-$ MySql JDBC
+
* '''[https://github.com/mysql/mysql-connector-j mysql'''] $-$ MySql JDBC
  
 
==Добавление зависимостей==
 
==Добавление зависимостей==
Строка 79: Строка 77:
 
==Работа с JSON==
 
==Работа с JSON==
 
Пример парсинга датасета в формате JSON с Котлин библиотекой Klaxon:
 
Пример парсинга датасета в формате JSON с Котлин библиотекой Klaxon:
  '''%use klaxon'''
+
  %use klaxon
  '''import java.io.*'''
+
  import java.io.*
  
  '''data class User('''
+
  data class User(
  ''' val age: Int, '''
+
  val age: Int,  
  ''' val firstName: String ="", '''
+
  val firstName: String ="",  
  ''' val lastName: String ="", '''
+
  val lastName: String ="",  
  ''' val eyeColor: String'''
+
  val eyeColor: String
  ''')'''
+
  )
  
  '''val users = Klaxon().parseArray<User>(File("users.json").readText())!!'''
+
  val users = Klaxon().parseArray<User>(File("users.json").readText())!!
  '''users.count()'''
+
  users.count()
  
 
==Функциональный стиль с библиотекой krangl==
 
==Функциональный стиль с библиотекой krangl==
Примеры обработки данных в функциональном стиле с Kotlin stdlib:
+
'''Примеры обработки данных в функциональном стиле с Kotlin stdlib:'''
'''users.filter{it.eyeColor == "green"}'''
+
users.filter{it.eyeColor == "green"}
  
  '''users.groupBy { user -> user.eyeColor }'''
+
  users.groupBy { user -> user.eyeColor }
       ''' .mapValues { mapEntry ->'''
+
       .mapValues { mapEntry ->
          '''  mapEntry.value.map { user -> user.firstName}  
+
            mapEntry.value.map { user -> user.firstName}  
         '''}'''
+
         }
  
 
'''Примеры обработки данных в функциональном стиле с krangl'''
 
'''Примеры обработки данных в функциональном стиле с krangl'''
 +
 
Используемые функции:
 
Используемые функции:
 
* '''addColumn''' $-$  добавление новой вычисленной по заданной функции колонки
 
* '''addColumn''' $-$  добавление новой вычисленной по заданной функции колонки
 
* '''filter ''' $-$  подвыборка строк по заданному условию:
 
* '''filter ''' $-$  подвыборка строк по заданному условию:
   '''df.filter { it["age"] eq 23 }'''
+
   df.filter { it["age"] eq 23 }
   '''df.filter { it["weight"] gt 50 }'''
+
   df.filter { it["weight"] gt 50 }
   '''df.filter({ it["last_name"].isMatching { startsWith("Do")  }})'''
+
   df.filter({ it["last_name"].isMatching { startsWith("Do")  }})
 
* '''sortedBy''' $-$ сортировка, можно передавать множество значений, которые будут учитываться в сортировке в соответствующем порядке
 
* '''sortedBy''' $-$ сортировка, можно передавать множество значений, которые будут учитываться в сортировке в соответствующем порядке
   '''df.sortedBy("age", "weight")'''
+
   df.sortedBy("age", "weight")
   '''df.sortedByDescending("age")'''
+
   df.sortedByDescending("age")
 
* '''select и remove''' $-$ подвыборка строк
 
* '''select и remove''' $-$ подвыборка строк
   '''df.select2 { it is IntCol }      // functional style column selection  '''
+
   df.select2 { it is IntCol }      // functional style column selection   
   '''df.select("last_name", "weight") // positive selection  '''
+
   df.select("last_name", "weight") // positive selection   
   '''df.remove("weight", "age")      // negative selection  '''
+
   df.remove("weight", "age")      // negative selection   
   '''df.select({ endsWith("name") })  // selector mini-language  '''
+
   df.select({ endsWith("name") })  // selector mini-language   
  
 
Обработка строк:
 
Обработка строк:
  '''fun readFromJsonString(s: String) ='''
+
  fun readFromJsonString(s: String) =
    ''' s.removePrefix("JsonArray(value=[")'''
+
    s.removePrefix("JsonArray(value=[")
    ''' .removeSuffix("])")'''
+
    .removeSuffix("])")
    ''' .split(',')'''
+
    .split(',')
    ''' .dropLastWhile{it.isEmpty()}'''
+
    .dropLastWhile{it.isEmpty()}
    ''' .toList()'''
+
    .toList()
 +
 
 +
val channels = DataFrame
 +
        .fromJson("channels.json")
 +
        .addColumn("groups") { it["groups"].map<String>{value -> readFromJsonString(value)}}
  
  '''val channels = DataFrame '''
+
  val modifiedChannels = channels
        '''.fromJson("channels.json")'''
+
                      .addColumn("count"){it["groups"].map<List<*>>{it.count()}}
        '''.addColumn("groups") { it["groups"].map<String>{value -> readFromJsonString(value)}} '''
+
                      .filter{it["score"] gt 50}
 +
                      .filter{it["age (y)"] lt 40}
 +
                      .select("name", "score", "count", "groups")
 +
                      .sortedByDescending("score")
  
'''val modifiedChannels = channels'''
+
Больше примеров с ипользованием библиотеки krangl - https://github.com/Kotlin/kotlin-jupyter/blob/master/samples/Krangl.ipynb
                    '''  .addColumn("count"){it["groups"].map<List<*>>{it.count()}}'''
 
                    '''  .filter{it["score"] gt 50}'''
 
                    '''  .filter{it["age (y)"] lt 40}'''
 
                    '''  .select("name", "score", "count", "groups")'''
 
                    '''  .sortedByDescending("score")'''
 
  
 
==Построение графиков==
 
==Построение графиков==
Строка 140: Строка 141:
  
 
Подробнее о настройках и параметрах графиков в Lets-plot: https://github.com/JetBrains/lets-plot-kotlin/blob/master/docs/guide/user_guide.ipynb
 
Подробнее о настройках и параметрах графиков в Lets-plot: https://github.com/JetBrains/lets-plot-kotlin/blob/master/docs/guide/user_guide.ipynb
  '''lets_plot(eyes) + stat_count() + ggsize(500,300)'''
+
  lets_plot(eyes) + stat_count() + ggsize(500,300)
 
   [[Файл:I04n3zFx68s.jpg |600px|thumb|center|]]
 
   [[Файл:I04n3zFx68s.jpg |600px|thumb|center|]]
  
 +
val rand = java.util.Random()
  
  '''val rand = java.util.Random()'''
+
  val data = mapOf<String, Any>(
'''val data = mapOf<String, Any>('''
+
    "rating" to List(200) { rand.nextGaussian() } + List(200) { rand.nextGaussian() * 1.5 + 1.5 },
  ''' "rating" to List(200) { rand.nextGaussian() } + List(200) { rand.nextGaussian() * 1.5 + 1.5 },'''
+
    "cond" to List(200) { "A" } + List(200) { "B" }
  '''  "cond" to List(200) { "A" } + List(200) { "B" }'''
+
  )
''')'''
+
  var p = lets_plot(data)
  '''var p = lets_plot(data)'''
+
  p += geom_density(color="dark_green", alpha=.3) {x="rating"; fill="cond"}
  '''p += geom_density(color="dark_green", alpha=.3) {x="rating"; fill="cond"}'''
+
  p + ggsize(500, 250)
  '''p + ggsize(500, 250)'''
 
 
  [[Файл:2-_1xADOor0.jpg |700px|thumb|center|]]
 
  [[Файл:2-_1xADOor0.jpg |700px|thumb|center|]]
  
  
  
  '''lets_plot(mapOf('''
+
  lets_plot(mapOf(
     '''"date" to usages.select("DateTime").collectAsList().map{(it[0] as Timestamp).getTime()},'''
+
     "date" to usages.select("DateTime").collectAsList().map{(it[0] as Timestamp).getTime()},
     '''"usage" to usages.select("users").collectAsList().map{it[0]}'''
+
     "usage" to usages.select("users").collectAsList().map{it[0]}
  ''')) +'''
+
  )) +'''
  '''geom_bar(stat = Stat.identity){x = "date"; y = "usage"; fill ="usage"} +'''
+
  geom_bar(stat = Stat.identity){x = "date"; y = "usage"; fill ="usage"} +
  '''scale_x_datetime() +'''
+
  scale_x_datetime() +
  '''scale_fill_hue()+'''
+
  scale_fill_hue()+
  '''qqsize(800, 400)'''
+
  qqsize(800, 400)
 
  [[Файл:YG1W2uqtTSc.jpg |700px|thumb|center|]]
 
  [[Файл:YG1W2uqtTSc.jpg |700px|thumb|center|]]
  
Строка 169: Строка 170:
  
 
'''Библиотека Kravis'''
 
'''Библиотека Kravis'''
  '''%use kravis, krangl '''
+
 
  '''val sleepData = DataFrame.fromJson("data.json"). '''
+
Подробнее - https://github.com/holgerbrandl/kravis
     '''.addColumn("rem_proportion") { it["sleep_rem"] / it["sleep_total"] } '''
+
 
     '''.plot(x = "sleep_total", y = "rem_proportion", color = "vore", size = "brainwt") '''
+
  %use kravis, krangl '''
      '''  .geomPoint(alpha = 0.7) '''
+
  val sleepData = DataFrame.fromJson("data.json").  
    '''    .guides(size = LegendType.none) '''
+
     .addColumn("rem_proportion") { it["sleep_rem"] / it["sleep_total"] }  
      '''  .title("Correlation between dream and total sleep time") '''
+
     .plot(x = "sleep_total", y = "rem_proportion", color = "vore", size = "brainwt")  
 +
        .geomPoint(alpha = 0.7)  
 +
        .guides(size = LegendType.none)  
 +
        .title("Correlation between dream and total sleep time")  
 
[[Файл:YKNvj0bWuO8.jpg |700px|thumb|center|]]
 
[[Файл:YKNvj0bWuO8.jpg |700px|thumb|center|]]
  

Версия 21:34, 19 апреля 2020

Kotlin и Data Science

Kotlin - это прагматичный, статически типизированный JVM язык, который поддерживает написание кода как в ООП, так и в функциональном стилях, а также компилируется в различные платформы: JVM, JS, Native. Благодаря статической типизации, Котлин более производителен в больших проектах, по сравнению с Python, а также позволяет избежать Runtime errors. Сравним аналогичные примеры кода на Python и Kotlin:

Python:

import numpy as np
# ...
a = np.ones((3, 3), dtype=int) * 3
b = np.random.random((3, 3))
b *= a # Success
a *= b # TypeError at runtime


Kotlin:

// ...
val a = ones<Int>(3, 3) * 3
val b = Random.random(3, 3)
b *= a // Success
a *= b // Compilation error: 
//Type mismatch: inferred type is KtNDArray<Double> but KtNDArray<Int> was expected


Также Котлин имеет имеет такую особенность дизайна языка, как null-safety и предоставляет такие операторы, как: safe call operator, elvis operator, not-null assertion operator, что позволяет ему быть более типобезопасным, по сравнениюc с Python:

var a: String = "abc"
a = null // compilation error
var b: String? = "abc"
b = null // ok

Помимо функционального синтаксиса и конструкций, Котлин также предоставляет набор математических и machine learning библиотек, а также инструментов для Data Science, в том числе, интегрированность с Jupyter Notebook.

Установка Kotlin в Jupyter Notebook

Kernel в Jupyter Notebook - это вычислительный движок, который исполняет код в данном документе и запускается автоматически при запуске ассоциированного с ним Jupyter Notebook документа. Они существуют для разных языков, например, ipython kernel исполняет Pythod код, а Kotlin kernel - Kotlin код в Jupyter Notebook. Именно Kotlin kernel позволяет писать и запускать код в Jupyter Notebook, а также использовать библиотеки и фреймворки, написанные на Java и Kotlin.

На данный момент, установить Kotlin kernel можно только через conda:

conda install kotlin-jupyter-kernel -c jetbrains

Обратите внимание, что Kotlin Jupyter требует установленной Java 8:

apt-get install openjdk-8-jre

Поддерживаемые библиотеки

  • kotlin-statistics - предоставляет расширения для функций для подсчета статистики. Поддерживает основные list/sequence/array functions, slicing operators (countBy, simpleRegressionBy, etc), binning operations, discrete PDF sampling, naive bayes classifier, clustering, linear regression, и другое
  • kmath - поддерживает алгебраические структуры и операторы, математические выражения, гистограммы, потоковые операции, обертки над commons-math и koma, и другое. Вдохновлена numpy
  • Krangl - предоставляет функционал для обработки данных в функциональном стиле(filter, transform, aggregate, reshape и др.) Вдохновлена pandas
  • lets-plot - Мультиплатформенная библиотека для создания графиков из данных. Может использоваться не только в JVM, но также JS and Python.
  • kravis - библиотека для визуализации данных.
  • klaxon $-$ Котлин JSON парсер
  • spark $-$ Фреймворк для распределённой обработки неструктурированных и слабоструктурированных данных
  • gral $-$ Java библиотека для отображения графиков
  • koma $-$ Котлин библиотека для научных вычислений
  • numpy $-$ Kотлин обертка над Python NumPy
  • exposed $-$ Kотлин SQL фреймворк
  • mysql $-$ MySql JDBC

Добавление зависимостей

По умолчанию возможно добавлять зависимости из следующих репозиториев:

Способы подключения зависимости:

@file:Repository("https://jcenter.bintray.com")
@file:DependsOn("com.beust:klaxon:5.0.1")
import com.beust.klaxon.*

Или коротким способом:

%use klaxon

Также можно указать конкретную версию зависимости:

%use krangl(0.10)

Можно указать свойства library descriptor (обязательно использовать именованные аргументы):

%use spark(scala=2.11.10, spark=2.4.2)

Подключить несколько библиотек одним выражением:

%use lets-plot, krangl, mysql(8.0.15)

Работа с JSON

Пример парсинга датасета в формате JSON с Котлин библиотекой Klaxon:

%use klaxon
import java.io.*
data class User(
val age: Int, 
val firstName: String ="", 
val lastName: String ="", 
val eyeColor: String
)
val users = Klaxon().parseArray<User>(File("users.json").readText())!!
users.count()

Функциональный стиль с библиотекой krangl

Примеры обработки данных в функциональном стиле с Kotlin stdlib:

users.filter{it.eyeColor == "green"}
users.groupBy { user -> user.eyeColor }
      .mapValues { mapEntry ->
           mapEntry.value.map { user -> user.firstName} 
       }

Примеры обработки данных в функциональном стиле с krangl

Используемые функции:

  • addColumn $-$ добавление новой вычисленной по заданной функции колонки
  • filter $-$ подвыборка строк по заданному условию:
 df.filter { it["age"] eq 23 }
 df.filter { it["weight"] gt 50 }
 df.filter({ it["last_name"].isMatching { startsWith("Do")  }})
  • sortedBy $-$ сортировка, можно передавать множество значений, которые будут учитываться в сортировке в соответствующем порядке
 df.sortedBy("age", "weight")
 df.sortedByDescending("age")
  • select и remove $-$ подвыборка строк
 df.select2 { it is IntCol }      // functional style column selection  
 df.select("last_name", "weight") // positive selection  
 df.remove("weight", "age")       // negative selection  
 df.select({ endsWith("name") })  // selector mini-language  

Обработка строк:

fun readFromJsonString(s: String) =
    s.removePrefix("JsonArray(value=[")
    .removeSuffix("])")
    .split(',')
    .dropLastWhile{it.isEmpty()}
    .toList()
val channels = DataFrame 
       .fromJson("channels.json")
       .addColumn("groups") { it["groups"].map<String>{value -> readFromJsonString(value)}} 
val modifiedChannels = channels
                      .addColumn("count"){it["groups"].map<List<*>>{it.count()}}
                      .filter{it["score"] gt 50}
                      .filter{it["age (y)"] lt 40}
                      .select("name", "score", "count", "groups")
                      .sortedByDescending("score")

Больше примеров с ипользованием библиотеки krangl - https://github.com/Kotlin/kotlin-jupyter/blob/master/samples/Krangl.ipynb

Построение графиков

Lets-plot

Подробнее о настройках и параметрах графиков в Lets-plot: https://github.com/JetBrains/lets-plot-kotlin/blob/master/docs/guide/user_guide.ipynb

lets_plot(eyes) + stat_count() + ggsize(500,300)
I04n3zFx68s.jpg
val rand = java.util.Random()
val data = mapOf<String, Any>(
    "rating" to List(200) { rand.nextGaussian() } + List(200) { rand.nextGaussian() * 1.5 + 1.5 },
    "cond" to List(200) { "A" } + List(200) { "B" }
 )
var p = lets_plot(data)
p += geom_density(color="dark_green", alpha=.3) {x="rating"; fill="cond"}
p + ggsize(500, 250)
2- 1xADOor0.jpg


lets_plot(mapOf(
   "date" to usages.select("DateTime").collectAsList().map{(it[0] as Timestamp).getTime()},
   "usage" to usages.select("users").collectAsList().map{it[0]}
)) +
geom_bar(stat = Stat.identity){x = "date"; y = "usage"; fill ="usage"} +
scale_x_datetime() +
scale_fill_hue()+
qqsize(800, 400)
YG1W2uqtTSc.jpg


Библиотека Kravis

Подробнее - https://github.com/holgerbrandl/kravis

%use kravis, krangl 
val sleepData = DataFrame.fromJson("data.json"). 
    .addColumn("rem_proportion") { it["sleep_rem"] / it["sleep_total"] } 
    .plot(x = "sleep_total", y = "rem_proportion", color = "vore", size = "brainwt") 
        .geomPoint(alpha = 0.7) 
        .guides(size = LegendType.none) 
        .title("Correlation between dream and total sleep time") 
YKNvj0bWuO8.jpg


Библиотека Gral

Источники

  1. Kotlinlang — Официальный сайт языка Kotlin
  2. Kotlin For Python Developers Documentation — Документация языка Kotlin для разработчиков на Python
  3. kotlin-jupyter on GitHub
  4. Примеры kotlin-jupyter
  5. KotlinConf 2019: Using Kotlin for Data Science