Run this notebook online:\ |Binder| or Colab: |Colab| .. |Binder| image:: https://mybinder.org/badge_logo.svg :target: https://mybinder.org/v2/gh/deepjavalibrary/d2l-java/master?filepath=chapter_preliminaries/tablesaw.ipynb .. |Colab| image:: https://colab.research.google.com/assets/colab-badge.svg :target: https://colab.research.google.com/github/deepjavalibrary/d2l-java/blob/colab/chapter_preliminaries/tablesaw.ipynb .. _sec_tablesaw: 数据预处理 ========== 到目前为止,我们已经介绍了处理存储在\ ``NDArrays``\ 中数据的各种技术。为了能用深度学习来解决现实世界的问题,我们经常从预处理原始数据开始,而不是从那些准备好的\ ``NDArrays``\ 格式数据开始。在Java常用的数据分析工具中,通常使用 ``tablesaw`` 软件包。如果你以前使用过Python的\ ``pandas``\ 你会发现\ ``tablesaw``\ 的API和\ ``pandas``\ 很相似。因此,我们将简要介绍使用 ``tablesaw`` 预处理原始数据并将原始数据转换为\ ``NDAarray``\ 格式的步骤。我们将在后面的章节中介绍更多的数据预处理技术。 导入tablesaw依赖项 ------------------ 在 Jupyter 中使用\ ``tablesaw``\ ,可以用如下的方法导入依赖性项: :: %%loadFromPOM tech.tablesaw tablesaw-jsplot 0.38.1 为了方便使用,我们把\ ``tablesaw``\ 的依赖项以及常用类存到:\ ``plot-utils.ipynb``\ 文件。只要用如下的命令加载即可: .. code:: java %load ../utils/plot-utils.ipynb 读取数据集 ---------- 举一个例子,我们首先(\ **创建一个人工数据集,并存储在csv(逗号分隔值)文件**) ``../data/house_tiny.csv`` 中。以其他格式存储的数据也可以通过类似的方式进行处理。下面的\ ``mkdir_if_not_exist`` 函数可确保目录 ``../data`` 存在。注意,注释 ``#@save``\ 是一个特殊的标记,该标记下方的函数、类或语句将保存在 ``d2l`` 软件包中,以便以后可以直接调用它们(例如 ``d2l.mkdir_if_not_exist(path)``\ )而无需重新定义。 下面我们将数据集按行写入 csv 文件中。 .. code:: java %load ../utils/djl-imports .. code:: java File file = new File("../data/"); file.mkdir(); String dataFile = "../data/house_tiny.csv"; // Create file File f = new File(dataFile); f.createNewFile(); // Write to file try (FileWriter writer = new FileWriter(dataFile)) { writer.write("NumRooms,Alley,Price\n"); // Column names writer.write("NA,Pave,127500\n"); // Each row represents a data example writer.write("2,NA,106000\n"); writer.write("4,NA,178100\n"); writer.write("NA,NA,140000\n"); } 要从创建的 csv 文件中加载原始数据集,我们导入 ``tablesaw`` 包并调用 ``read`` 函数。该数据集有四行三列。其中每行描述了房间数量(“NumRooms”)、巷子类型(“Alley”)和房屋价格(“Price”)。 .. code:: java Table data = Table.read().file("../data/house_tiny.csv"); data .. parsed-literal:: :class: output NumRooms | Alley | Price | --------------------------------- | Pave | 127500 | 2 | | 106000 | 4 | | 178100 | | | 140000 | 处理缺失值 ---------- 注意,有一些字段数据为空。为了处理缺失的数据,典型的方法包括 *插值* 和 *删除*\ ,其中插值用替代值代替缺失值。而删除则忽略缺失值。在这里,我们将考虑插值。 我们将\ ``data``\ 分成\ ``inputs``\ 和\ ``outputs``\ ,其中前者为\ ``data``\ 的前两列,而后者为\ ``data``\ 的最后一列。对于\ ``inputs``\ 中缺少的的数值,我们用同一列的均值替换缺失数据项。对于 ``inputs`` 中缺少的的数值,我们用同一列的均值替换缺失数据项。 .. code:: java Table inputs = data.create(data.columns()); inputs.removeColumns("Price"); Table outputs = data.select("Price"); Column col = inputs.column("NumRooms"); col.set(col.isMissing(), (int) inputs.nCol("NumRooms").mean()); inputs .. parsed-literal:: :class: output NumRooms | Alley | ---------------------- 3 | Pave | 2 | | 4 | | 3 | | 对于 ``inputs`` 中的类别值或离散值,我们将缺失数据视为一个类别。由于 “巷子”(“Alley”)列只接受两种类型的类别值 “Pave” 和缺失数据,\ ``tablesaw`` 可以自动将此列转换为两列 “Alley\_Pave” 和 “Alley\_nan”。巷子类型为 “Pave” 的行会将“Alley\_Pave”的值设置为1,“Alley\_nan”的值设置为0。缺少巷子类型的行会将“Alley\_Pave”和“Alley\_nan”分别设置为0和1。 .. code:: java StringColumn col = (StringColumn) inputs.column("Alley"); List dummies = col.getDummies(); inputs.removeColumns(col); inputs.addColumns(DoubleColumn.create("Alley_Pave", dummies.get(0).asDoubleArray()), DoubleColumn.create("Alley_nan", dummies.get(1).asDoubleArray()) ); inputs .. parsed-literal:: :class: output NumRooms | Alley_Pave | Alley_nan | ----------------------------------------- 3 | 1 | 0 | 2 | 0 | 1 | 4 | 0 | 1 | 3 | 0 | 1 | 转换为NDArray格式 ----------------- 现在 ``inputs`` 和 ``outputs`` 中的所有条目都是数值类型,它们可以转换为NDArray格式。当数据采用张量格式后,可以通过在 :numref:`sec_ndarray` 中引入的那些NDArray函数来进一步操作。 .. code:: java NDManager nd = NDManager.newBaseManager(); NDArray x = nd.create(inputs.as().doubleMatrix()); NDArray y = nd.create(outputs.as().intMatrix()); x .. parsed-literal:: :class: output ND: (4, 3) gpu(0) float64 [[3., 1., 0.], [2., 0., 1.], [4., 0., 1.], [3., 0., 1.], ] .. code:: java y .. parsed-literal:: :class: output ND: (4, 1) gpu(0) int32 [[127500], [106000], [178100], [140000], ] 小结 ---- - 像庞大的 Java 生态系统中的许多其他扩展包一样,\ ``tablesaw`` 可以与NDArray兼容。 - 插值和删除可用于处理缺失的数据。 练习 ---- 创建包含更多行和列的原始数据集。 1. 删除缺失值最多的列。 2. 将预处理后的数据集转换为NDArray格式。