# Kotlin 用于數據科學

數據科學在信息技術中具有特殊地位:它同時包含軟件開發與科學研究兩方面。作為一門學科,數據科學涵蓋了廣泛的領域:數據工程、數據分析、機器學習、可視化等等。
為了涵蓋所有這些不同領域,軟件行業有許多用于數據科學的技術與工具。其中包含框架、特定的 IDE(稱為*notebook*)、繪圖工具以及專為數據分析與數學研究設計的編程語言。
通用語言也可以應用于數據科學領域,而 Kotlin 已經為數據科學所采用。在此我們會介紹一些關于將 Kotlin 用于數據科學時的實用知識。
## 工具
現代軟件開發人員很少會在純文本編輯器中編寫代碼并在命令行運行。相反,大家傾向于使用可以在一個工具中處理所有開發任務的集成開發環境(IDE,Integrated Development Environment)。數據科學家也有類似的工具,稱為 *notebook*。notebook 讓用戶可以進行研究并將其存儲在單個環境中。在一個 notebook 中,可以在代碼旁編寫敘述性文本、執行代碼塊及以任何所需格式(輸出文本、表格、數據可視化等等)查看結果。
Kotlin 提供了與兩個流行的 notebook 的集成:Jupyter 與 Apache Zeppelin,它們都支持編寫及運行 Kotlin 代碼塊。
### Jupyter 內核
開源項目 [Jupyter](https://jupyter.org/) 提供了著名的基于 web 的開發環境 **Jupyter Notebook**。對于代碼執行,Jupyter 使用*內核*的概念——獨立運行的不同組件,并且這些組件根據請求執行代碼,例如,當在一個 notebook 中點擊 **Run** 時。
Jupyter 團隊維護了一個內核——運行 Python 代碼的 IPython。但是,還有其他社區維護的用于不同語言的各種內核。
其中包括**用于 Jupyter notbook 的 Kotlin 內核**。有了這個內核,就可以在 Jupyter notebook 中編寫并運行 Kotlin 代碼,以及使用以 Java 或 Kotlin 編寫的第三方數據科學框架。
#### 設置 Kotlin 內核
Kotlin 內核需要安裝 Java 8。
請使用 [Conda](https://docs.conda.io/projects/conda/en/latest/) 安裝該內核:
```bash
conda install kotlin-jupyter-kernel -c jetbrains
```
一旦內核安裝完畢,就可以運行 Jupyter notebook 并切換到 Kotlin 內核。僅此而已,然后就可以在 notebook 中編寫并運行 Kotlin 了!

可以在[這里](https://github.com/cheptsov/kotlin-jupyter-demo/blob/master/index.ipynb)找到關于 Jupyter 的 Kotlin 內核的更多信息。
### Zeppelin 解釋器
[Apache Zeppelin](http://zeppelin.apache.org/) 是一個流行的基于 web 的交互式數據分析解決方案。Zeppelin 為 [Apache Spark](http://zeppelin.apache.org/docs/latest/interpreter/spark.html)集群計算系統提供了強大的支持,這對于數據工程特別有用。Spark 提供了多種語言的高級 API。
Zeppelin 中的語言支持由*解釋器*提供,解釋器是讓用戶能夠使用指定語言或者數據處理后端的插件。對于不同的編程語言有許多社區維護的解釋器。我們提供了增加 Kotlin 支持的**用于 Apache Zeppelin 的 Kotlin 解釋器**。
#### 設置帶 Kotlin 解釋器的 Zeppelin
目前,最新版本的 Zeppelin(0.8.2)并未內置 Kotlin 解釋器。不過,在 Zeppelin 的 master 分支中有。因此,為了向 Zeppelin 添加 Kotlin 支持,需要從源代碼構建自己的版本。
構建 Zeppelin 的定制版需要:
* [Git](https://git-scm.com/)
* [Maven](https://maven.apache.org/install.html),
* [JDK 8](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
* 列在[此處](https://zeppelin.apache.org/docs/latest/setup/basics/how_to_build.html#build-requirements)各項依賴
首先,從 Zeppelin 版本庫中檢出 master 分支:
```bash
git clone --depth=1 git@github.com:apache/zeppelin.git
```
或者
```bash
git clone --depth=1 https://github.com/apache/zeppelin.git
```
使用 Maven 構建 Zeppelin,請切換到 Zeppelin 目錄并運行以下命令:
```bash
mvn clean package -DskipTests -Pspark-2.4 -Pscala-2.11
```
然后使用以下命令運行 Zeppelin:
```bash
./bin/zeppelin-daemon.sh start
```
現在可以在 `http://localhost:8089` 打開 Zeppelin UI 了。
如需了解如何在 Spark 集群中部署帶 Kotlin 支持的 Zeppelin,請參見[這個說明](/docs/tutorials/zeppelin-spark-cluster.html)。
## 相關庫
對于軟件工程來說,任何領域的重要組成部分都有相關領域框架的可用性。對于數據科學,包括諸如機器學習、數據分析、可視化等領域。幸運的是,已經有很多用 Kotlin 編寫的數據科學框架。更完美的是還有更多用 Java 編寫的框架,因為可以在 Kotlin 代碼中無縫調用 Java 框架。
以下是可能對數據科學有用的庫的兩個簡短列表。
### Kotlin 庫
* [kotlin-statistics](https://github.com/thomasnield/kotlin-statistics) 是一個為探索性統計與生產統計中提供擴展函數的庫。它支持基本的數字列表/序列/數組函數(從 `sum` 到 `skewness`)、切片操作符(諸如 `countBy`、 `simpleRegressionBy`)、分箱(binning)操作符、離散 PDF 采樣、樸素貝葉斯分類器、聚類、線性回歸等等。
* [kmath](https://github.com/mipt-npm/kmath) 是一個受 [NumPy](https://numpy.org/) 啟發的庫。這個庫支持代數結構與運算、類數組結構、數學表達式、直方圖、流運算、[commons-math](http://commons.apache.org/proper/commons-math/) 與[koma](https://github.com/kyonifer/koma) 的包裝等等。
* [krangl](https://github.com/holgerbrandl/krangl) 是一個受 R 語言的 [dplyr](https://dplyr.tidyverse.org/)與 Python 的 [pandas](https://pandas.pydata.org/) 啟發的庫。這個庫提供了采用函數式風格 API進行數據操作的功能;它還包括過濾、轉換、聚合與重塑表格數據的函數。
* [lets-plot](https://github.com/JetBrains/lets-plot) 是一個用 Kotlin 編寫的統計數據繪圖庫。Lets-Plot 是多平臺的,不僅可以用于 JVM,還可以用于 JS 與 Python。更多信息請參見[下文](#lets-plot-for-kotlin)。
* [kravis](https://github.com/holgerbrandl/kravis) 是另一個用于表格數據可視化的庫,其靈感來自于Python 的 [ggplot](https://ggplot2.tidyverse.org/)。
### Java 庫
因為 Kotlin 提供了與 Java 互操作的頭等支持,所以也可以在用于數據科學的 Kotlin 代碼中使用 Java 庫。
以下是這些庫的一些示例:
* [DeepLearning4J](https://deeplearning4j.org/)——一個 Java 深度學習庫
* [ND4J](http://nd4j.org/)——用于 JVM 的高效矩陣數學庫
* [Dex](https://github.com/PatMartin/Dex)——一個基于 Java 的數據可視化工具
* [Smile](https://github.com/haifengl/smile)——一個全面的機器學習、自然語言處理、線性代數、圖、插值與可視化系統
* [Apache Commons Math](http://commons.apache.org/proper/commons-math/)——一個 Java 通用數學、統計與機器學習庫
* [OptaPlanner](https://www.optaplanner.org/)——一個用于優化規劃問題的求解器實用程序
* [Charts](https://github.com/HanSolo/charts)——一個正在開發中的科學 JavaFX 圖表庫
* [CoreNLP](https://stanfordnlp.github.io/CoreNLP/)——一個自然語言處理工具包
* [Apache Mahout](https://mahout.apache.org/)——一個回歸、聚類與推薦的分布式框架
* [Weka](https://www.cs.waikato.ac.nz/ml/index.html)——一組用于數據挖掘任務的機器學習算法
如果這個列表還不能滿足需求,可以在 Thomas Nield 的[**Kotlin 數據科學資源**](https://github.com/thomasnield/kotlin-data-science-resources)摘要中找到更多選項。
### Lets-Plot for Kotlin
**Lets-Plot for Kotlin** 是 [Lets-Plot](https://github.com/JetBrains/lets-plot) 庫的 Kotlin API, Lets-Plot 是一個完全用 Kotlin 編寫的開源的統計數據繪圖庫。Lets-Plot 建立在分層圖形的概念上,該概念首先在 Leland Wilkinson 的著作 [The Grammar of Graphics](https://www.goodreads.com/book/show/2549408.The_Grammar_of_Graphics)中描述,后來在 R 語言的 [ggplot2](https://ggplot2.tidyverse.org/) 包中實現。
Lets-Plot for Kotlin 與[用于 Jupyter notebook 的 Kotlin 內核](http://www.kotlincn.net/docs/reference/data-science-overview.html#jupyter-%E5%86%85%E6%A0%B8)緊密集成。安裝并啟用 Kotlin 內核后,將以下行添加到 Jupyter notebook 中:
```
%use lets-plot
```
就是這樣,現在就可以調用 Lets-Plot 中的函數并查看結果了。

### NumPy 的 Kotlin 綁定
[**KNumpy**](https://github.com/kotlin/kotlin-numpy/)(**NumPy 的 Kotlin 綁定**)是一個能讓 Kotlin 代碼調用 NumPy 函數的 Kotlin 庫。[NumPy](https://numpy.org/)是使用 Python 進行科學計算的一個流行軟件包。它為多維數組處理、線性代數、傅立葉變換、隨機數以及其他數學任務提供了強大的功能。
KNumpy 為 NumPy 函數提供了靜態類型的包裝。由于 Kotlin 的函數式能力,KNumpy 的 API 與對應的 NumPy API 非常相似。這讓有 NumPy 經驗的開發人員可以輕松切換到 KNumpy。
以下是兩份等價代碼的示例:
```python
# Python
import numpy as np
a = np.arange(15).reshape(3, 5)
print(a.shape == (3, 5)) # True
print(a.ndim == 2) # True
print(a.dtype.name) # 'int64'
b = (np.arange(15) ** 2).reshape(3, 5)
```
```kotlin
// Kotlin
import org.jetbrains.numkt.*
fun main() {
val a = arange(15).reshape(3, 5)
println(a.shape.contentEquals(intArrayOf(3, 5))) // true
println(a.ndim == 2) // true
println(a.dtype) // class java.lang.Integer
// 創建一個整型數組,我們將每個元素取平方,然后重塑為 (3, 5)
val b = (arange(15) `**` 2).reshape(3, 5)
}
```
與 Python 不同的是,Kotlin 是一種靜態類型語言。這樣使用 KNumpy 就可以避免運行時的類型錯誤:
Kotlin 編譯器會在更早的階段檢測到相應問題。
```python
# Python
import numpy as np
a = np.ones((3, 3), dtype=int) * 3
b = np.random.random((3, 3))
b *= a # 成功
a *= b # 運行時 TypeError
```
```kotlin
// Kotlin
// ……
val a = ones<Int>(3, 3) * 3
val b = Random.random(3, 3)
b *= a // 成功
a *= b // 編譯錯誤:
// Type mismatch: inferred type is KtNDArray<Double> but KtNDArray<Int> was expected
```
</div>
- 前言
- Kotlin簡介
- IntelliJ IDEA技巧總結
- idea設置類注釋和方法注釋模板
- 像Android Studion一樣創建工程
- Gradle
- Gradle入門
- Gradle進階
- 使用Gradle創建一個Kotlin工程
- 環境搭建
- Androidstudio平臺搭建
- Eclipse的Kotlin環境配置
- 使用IntelliJ IDEA
- Kotlin學習路線
- Kotlin官方中文版文檔教程
- 概述
- kotlin用于服務器端開發
- kotlin用于Android開發
- kotlin用于JavaScript開發
- kotlin用于原生開發
- Kotlin 用于數據科學
- 協程
- 多平臺
- 新特性
- 1.1的新特性
- 1.2的新特性
- 1.3的新特性
- 開始
- 基本語法
- 習慣用法
- 編碼規范
- 基礎
- 基本類型
- 包與導入
- 控制流
- 返回與跳轉
- 類與對象
- 類與繼承
- 屬性與字段
- 接口
- 可見性修飾符
- 擴展
- 數據類
- 密封類
- 泛型
- 嵌套類
- 枚舉類
- 對象
- 類型別名
- 內嵌類
- 委托
- 委托屬性
- 函數與Lambda表達式
- 函數
- Lambda表達式
- 內聯函數
- 集合
- 集合概述
- 構造集合
- 迭代器
- 區間與數列
- 序列
- 操作概述
- 轉換
- 過濾
- 加減操作符
- 分組
- 取集合的一部分
- 取單個元素
- 排序
- 聚合操作
- 集合寫操作
- List相關操作
- Set相關操作
- Map相關操作
- 多平臺程序設計
- 平臺相關聲明
- 以Gradle創建
- 更多語言結構
- 解構聲明
- 類型檢測與轉換
- This表達式
- 相等性
- 操作符重載
- 空安全
- 異常
- 注解
- 反射
- 作用域函數
- 類型安全的構造器
- Opt-in Requirements
- 核心庫
- 標準庫
- kotlin.test
- 參考
- 關鍵字與操作符
- 語法
- 編碼風格約定
- Java互操作
- Kotlin中調用Java
- Java中調用Kotlin
- JavaScript
- 動態類型
- kotlin中調用JavaScript
- JavaScript中調用kotlin
- JavaScript模塊
- JavaScript反射
- JavaScript DCE
- 原生
- 并發
- 不可變性
- kotlin庫
- 平臺庫
- 與C語言互操作
- 與Object-C及Swift互操作
- CocoaPods集成
- Gradle插件
- 調試
- FAQ
- 協程
- 協程指南
- 基礎
- 取消與超時
- 組合掛起函數
- 協程上下文與調度器
- 異步流
- 通道
- 異常處理與監督
- 共享的可變狀態與并發
- Select表達式(實驗性)
- 工具
- 編寫kotlin代碼文檔
- 使用Kapt
- 使用Gradle
- 使用Maven
- 使用Ant
- Kotlin與OSGI
- 編譯器插件
- 編碼規范
- 演進
- kotlin語言演進
- 不同組件的穩定性
- kotlin1.3的兼容性指南
- 常見問題
- FAQ
- 與Java比較
- 與Scala比較(官方已刪除)
- Google開發者官網簡介
- Kotlin and Android
- Get Started with Kotlin on Android
- Kotlin on Android FAQ
- Android KTX
- Resources to Learn Kotlin
- Kotlin樣品
- Kotlin零基礎到進階
- 第一階段興趣入門
- kotlin簡介和學習方法
- 數據類型和類型系統
- 入門
- 分類
- val和var
- 二進制基礎
- 基礎
- 基本語法
- 包
- 示例
- 編碼規范
- 代碼注釋
- 異常
- 根類型“Any”
- Any? 可空類型
- 可空性的實現原理
- kotlin.Unit類型
- kotlin.Nothing類型
- 基本數據類型
- 數值類型
- 布爾類型
- 字符型
- 位運算符
- 變量和常量
- 語法和運算符
- 關鍵字
- 硬關鍵字
- 軟關鍵字
- 修飾符關鍵字
- 特殊標識符
- 操作符和特殊符號
- 算術運算符
- 賦值運算符
- 比較運算符
- 邏輯運算符
- this關鍵字
- super關鍵字
- 操作符重載
- 一元操作符
- 二元操作符
- 字符串
- 字符串介紹和屬性
- 字符串常見方法操作
- 字符串模板
- 數組
- 數組介紹創建及遍歷
- 數組常見方法和屬性
- 數組變化以及下標越界問題
- 原生數組類型
- 區間
- 正向區間
- 逆向區間
- 步長
- 類型檢測與類型轉換
- is、!is、as、as-運算符
- 空安全
- 可空類型變量
- 安全調用符
- 非空斷言
- Elvis操作符
- 可空性深入
- 可空性和Java
- 函數
- 函數式編程概述
- OOP和FOP
- 函數式編程基本特性
- 組合與范疇
- 在Kotlin中使用函數式編程
- 函數入門
- 函數作用域
- 函數加強
- 命名參數
- 默認參數
- 可變參數
- 表達式函數體
- 頂層、嵌套、中綴函數
- 尾遞歸函數優化
- 函數重載
- 控制流
- if表達式
- when表達式
- for循環
- while循環
- 循環中的 Break 與 continue
- return返回
- 標簽處返回
- 集合
- list集合
- list集合介紹和操作
- list常見方法和屬性
- list集合變化和下標越界
- set集合
- set集合介紹和常見操作
- set集合常見方法和屬性
- set集合變換和下標越界
- map集合
- map集合介紹和常見操作
- map集合常見方法和屬性
- map集合變換
- 集合的函數式API
- map函數
- filter函數
- “ all ”“ any ”“ count ”和“ find ”:對集合應用判斷式
- 別樣的求和方式:sumBy、sum、fold、reduce
- 根據人的性別進行分組:groupBy
- 扁平化——處理嵌套集合:flatMap、flatten
- 惰性集合操作:序列
- 區間、數組、集合之間轉換
- 面向對象
- 面向對象-封裝
- 類的創建及屬性方法訪問
- 類屬性和字段
- 構造器
- 嵌套類(內部類)
- 枚舉類
- 枚舉類遍歷&枚舉常量常用屬性
- 數據類
- 密封類
- 印章類(密封類)
- 面向對象-繼承
- 類的繼承
- 面向對象-多態
- 抽象類
- 接口
- 接口和抽象類的區別
- 面向對象-深入
- 擴展
- 擴展:為別的類添加方法、屬性
- Android中的擴展應用
- 優化Snackbar
- 用擴展函數封裝Utils
- 解決煩人的findViewById
- 擴展不是萬能的
- 調度方式對擴展函數的影響
- 被濫用的擴展函數
- 委托
- 委托類
- 委托屬性
- Kotlin5大內置委托
- Kotlin-Object關鍵字
- 單例模式
- 匿名類對象
- 伴生對象
- 作用域函數
- let函數
- run函數
- with函數
- apply函數
- also函數
- 標準庫函數
- takeIf 與 takeUnless
- 第二階段重點深入
- Lambda編程
- Lambda成員引用高階函數
- 高階函數
- 內聯函數
- 泛型
- 泛型的分類
- 泛型約束
- 子類和子類型
- 協變與逆變
- 泛型擦除與實化類型
- 泛型類型參數
- 泛型的背后:類型擦除
- Java為什么無法聲明一個泛型數組
- 向后兼容的罪
- 類型擦除的矛盾
- 使用內聯函數獲取泛型
- 打破泛型不變
- 一個支持協變的List
- 一個支持逆變的Comparator
- 協變和逆變
- 第三階段難點突破
- 注解和反射
- 聲明并應用注解
- DSL
- 協程
- 協程簡介
- 協程的基本操作
- 協程取消
- 管道
- 慕課霍丙乾協程筆記
- Kotlin與Java互操作
- 在Kotlin中調用Java
- 在Java中調用Kotlin
- Kotlin與Java中的操作對比
- 第四階段專題練習
- 朱凱Kotlin知識點總結
- Kotlin 基礎
- Kotlin 的變量、函數和類型
- Kotlin 里那些「不是那么寫的」
- Kotlin 里那些「更方便的」
- Kotlin 進階
- Kotlin 的泛型
- Kotlin 的高階函數、匿名函數和 Lambda 表達式
- Kotlin協程
- 初識
- 進階
- 深入
- Kotlin 擴展
- 會寫「18.dp」只是個入門——Kotlin 的擴展函數和擴展屬性(Extension Functions / Properties)
- Kotlin實戰-開發Android