C# Jupyter Notebook





5.00/5 (6投票s)
在本文中,我们将探讨新的 C# Jupyter Notebook 的主要功能。
什么是 .NET Jupyter Notebook
对于那些使用过 Python 或 R 等其他编程语言的 Notebook 的人来说,这将是一项简单的任务。首先,Notebook 的概念提供了一种快速、简单、直接的方式来呈现文本、$ \Latex $、源代码实现及其输出的混合体。这意味着您拥有一个功能齐全的平台来撰写论文或博客文章、演示文稿、讲义和其他教育材料。
Notebook 由单元格组成,用户可以在其中编写代码或 markdown 文本。完成单元格内容后,可以通过按 Ctrl+Enter 或单击 Notebook 工具栏上的运行按钮来确认单元格编辑。下图显示了 Notebook 工具栏,其中包含一个 Run 按钮。弹出组合框显示用户可定义的单元格类型。对于文本,应选择 Markdown
;对于编写源代码,单元格应为 Code
。
要开始编写 C# Notebook 代码,我们首先需要安装 NuGet 包或添加程序集引用并定义 using 语句。为此,以下代码将安装几个 nuget 包
,并声明几个 using 语句
。但在编写代码之前,我们应该通过按 +
工具栏按钮添加一个新单元格。
前几个 NuGet 包是 ML.NET 的包。然后,我们安装 XPlot 包用于 .NET Notebook 中的数据可视化,然后安装一套 Daany 包用于数据分析。首先,我们安装 Daany.DataFrame
用于数据探索和分析,然后安装 Daany.DataFrame.Ext
扩展集用于与 ML.NET 一起使用的数据操作。
//ML.NET Packages
#r "nuget:Microsoft.ML.LightGBM"
#r "nuget:Microsoft.ML"
#r "nuget:Microsoft.ML.DataView"
//Install XPlot package
#r "nuget:XPlot.Plotly"
//Install Daany.DataFrame
#r "nuget:Daany.DataFrame"
#r "nuget:Daany.DataFrame.Ext"
using System;
using System.Linq;
//Daany data frame
using Daany;
using Daany.Ext;
//Plotting functionalities
using XPlot.Plotly;
//ML.NET using
using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.Trainers.LightGbm;
上面代码的输出
成功安装 NuGet 包后,我们就可以开始数据探索了。但在此之前,请声明一些 using
语句。
我们可以全局定义类或方法。以下代码实现了用于在输出单元格中显示 Daany.DataFrame
的格式化方法。
// Temporal DataFrame formatter for this early preview
using Microsoft.AspNetCore.Html;
Formatter<DataFrame>.Register((df, writer) =>
{
var headers = new List<IHtmlContent>();
headers.Add(th(i("index")));
headers.AddRange(df.Columns.Select(c => (IHtmlContent) th(c)));
//renders the rows
var rows = new List<List<IHtmlContent>>();
var take = 20;
//
for (var i = 0; i < Math.Min(take, df.RowCount()); i++)
{
var cells = new List<IHtmlContent>();
cells.Add(td(df.Index[i]));
foreach (var obj in df[i])
{
cells.Add(td(obj));
}
rows.Add(cells);
}
var t = table(
thead(
headers),
tbody(
rows.Select(
r => tr(r))));
writer.Write(t);
}, "text/html");
在本演示中,我们将使用著名的 Iris
数据集。我们将从 Internet 下载该文件,使用 Daany.DataFrame
加载它,并显示前几行。为此,我们运行以下代码。
var url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data";
var cols = new string[] {"sepal_length","sepal_width",
"petal_length", "petal_width", "flower_type"};
var df = DataFrame.FromWeb(url, sep:',',names:cols);
df.Head(5)
输出如下:
可以看到,上一段代码的最后一行没有分号,这意味着该行应该显示在输出单元格中。我们继续,实现两个新列。新列将是花朵的 sepal
(萼片)和 petal
(花瓣)面积。我们将使用的表达式是
$$ PetalArea = petal_width \cdot petal_length;\ SepalArea = sepal_width \cdot sepal_length; $$
可以看到,Notebook 完全支持 $ \LaTeX $。
上述公式在以下代码中实现。
//calculate two new columns into dataset
df.AddCalculatedColumn("SepalArea",
(r, i) => Convert.ToSingle(r["sepal_width"]) * Convert.ToSingle(r["sepal_length"]));
df.AddCalculatedColumn("PetalArea",
(r, i) => Convert.ToSingle(r["petal_width"]) * Convert.ToSingle(r["petal_length"]));
df.Head(5)
数据框有两个新列。它们指示花朵的面积。为了查看每个定义列的基本统计参数,我们调用 Describe
方法。
//see descriptive stats of the final ds
df.Describe(false)
从上表可以看出,flower
列只有 3 个值。最常见的值的频率为 50
,这表明 dataset
(数据集)是平衡的。
数据可视化
Notebook 中最强大的功能是数据可视化。在本节中,我们将绘制一些有趣的图表。
为了在 2D 平面上查看萼片和花瓣面积的分布情况,实现了以下绘图。
//plot the data in order to see how areas are spread in the 2d plane
//XPlot Histogram reference:
//http://tpetricek.github.io/XPlot/reference/xplot-plotly-graph-histogram.html
var faresHistogram = Chart.Plot(new Graph.Histogram(){x = df["flower_type"],
autobinx = false, nbinsx = 20});
var layout = new Layout.Layout(){title="Distribution of iris flower"};
faresHistogram.WithLayout(layout);
display(faresHistogram);
该图表也表明 dataset
(数据集)是平衡的。
现在让我们根据花朵类型绘制面积。
// Plot Sepal vs. Petal area with flower type
var chart = Chart.Plot(
new Graph.Scatter()
{
x = df["SepalArea"],
y = df["PetalArea"],
mode = "markers",
marker = new Graph.Marker()
{
color = df["flower_type"].Select
(x=>x.ToString()=="Iris-virginica"?1:(x.ToString()=="Iris-versicolor"?2:3)),
colorscale = "Jet"
}
}
);
var layout = new Layout.Layout()
{title="Plot Sepal vs. Petal Area & color scale on flower type"};
chart.WithLayout(layout);
chart.WithLegend(true);
chart.WithLabels(new string[3]{"Iris-virginica","Iris-versicolor", "Iris-setosa"});
chart.WithXTitle("Sepal Area");
chart.WithYTitle("Petal Area");
chart.Width = 800;
chart.Height = 400;
display(chart);
从上图可以看出,由于我们使用了花瓣和萼片面积而不是宽度和长度,花朵类型几乎是线性分离的。通过这种转换,我们可以获得 100% 准确的 ML 模型。
机器学习
完成数据转换和可视化后,我们可以在应用机器学习之前定义最终的数据框。为此,我们将只选择两列作为特征,一列作为标签(花朵类型)。
//create new data-frame by selecting only three columns
var derivedDF = df["SepalArea","PetalArea","flower_type"];
derivedDF.Head(5)
由于我们将使用 ML.NET,我们需要声明 Iris
以便将数据加载到 ML.NET 中。
//Define an Iris class for machine learning.
class Iris
{
public float PetalArea { get; set; }
public float SepalArea { get; set; }
public string Species { get; set; }
}
//Create ML COntext
MLContext mlContext = new MLContext(seed:2019);
然后将数据从 Daany 数据框加载到 ML.NET 中。
//Load Data Frame into Ml.NET data pipeline
IDataView dataView = mlContext.Data.LoadFromEnumerable<Iris>
(derivedDF.GetEnumerator<Iris>((oRow) =>
{
//convert row object array into Iris row
var prRow = new Iris();
prRow.SepalArea = Convert.ToSingle(oRow["SepalArea"]);
prRow.PetalArea = Convert.ToSingle(oRow["PetalArea"]);
prRow.Species = Convert.ToString(oRow["flower_type"]);
//
return prRow;
}));
拥有数据后,我们可以将其拆分为 train
(训练)和 test
(测试)集。
//Split dataset in two parts: TrainingDataset (80%) and TestDataset (20%)
var trainTestData = mlContext.Data.TrainTestSplit(dataView, testFraction: 0.2);
var trainData = trainTestData.TrainSet;
var testData = trainTestData.TestSet;
准备数据进行训练的下一步是定义数据转换和特征工程的管道。
//one encoding output category column by defining KeyValues for each category
IEstimator<ITransformer> dataPipeline =
mlContext.Transforms.Conversion.MapValueToKey
(outputColumnName: "Label", inputColumnName: nameof(Iris.Species))
//define features columns
.Append(mlContext.Transforms.Concatenate
("Features",nameof(Iris.SepalArea), nameof(Iris.PetalArea)));
完成准备部分后,我们就可以进行训练部分了。训练通过调用管道的 Fit
来开始。
%%time
// Define LightGbm algorithm estimator
IEstimator<ITransformer> lightGbm = mlContext.MulticlassClassification.Trainers.LightGbm();
//train the ML model
TransformerChain<ITransformer> model = dataPipeline.Append(lightGbm).Fit(trainData);
训练完成后,我们就有了可以评估的训练模型。为了格式化打印评估结果,我们将安装 Daany DataFrame 扩展,其中包含打印结果的实现。
//evaluate train set
var predictions = model.Transform(trainData);
var metricsTrain = mlContext.MulticlassClassification.Evaluate(predictions);
ConsoleHelper.PrintMultiClassClassificationMetrics("TRAIN Iris DataSet", metricsTrain);
ConsoleHelper.ConsoleWriteHeader("Train Iris DataSet Confusion Matrix ");
ConsoleHelper.ConsolePrintConfusionMatrix(metricsTrain.ConfusionMatrix);
//evaluate test set
var testPrediction = model.Transform(testData);
var metricsTest = mlContext.MulticlassClassification.Evaluate(testPrediction);
ConsoleHelper.PrintMultiClassClassificationMetrics("TEST Iris Dataset", metricsTest);
ConsoleHelper.ConsoleWriteHeader("Test Iris DataSet Confusion Matrix ");
ConsoleHelper.ConsolePrintConfusionMatrix(metricsTest.ConfusionMatrix);
可以看出,我们拥有一个 100% 准确的鸢尾花识别模型。现在,让我们在数据框中添加一个名为 Prediction
的新列,以便在数据框中获得模型的预测。
为此,我们将在训练集和测试集上评估模型。一旦我们对两个集合都有了预测,我们就可以将它们连接起来并添加为 Daany 数据框中的单独列。以下代码实现了我们之前描述的功能。
var flowerLabels = DataFrameExt.GetLabels(predictions.Schema).ToList();
var p1 = predictions.GetColumn<uint>("PredictedLabel").Select(x=>(int)x).ToList();
var p2 = testPrediction.GetColumn<uint>("PredictedLabel").Select(x => (int)x).ToList();
//join train and test
p1.AddRange(p2);
var p = p1.Select(x => (object)flowerLabels[x-1]).ToList();
//add new column into df
var dic = new Dictionary<string, List<object>> { { "PredictedLabel", p } };
var dff = derivedDF.AddColumns(dic);
dff.Head()
上面的输出显示了数据框的前几行。要查看数据框的最后几行,我们调用 Tail
方法。
dff.Tail()
在这篇博文中,我们看到了如何通过使用 ML.NET 和 Daany – DAtaANalYtics 库,在 .NET Jupyter Notebook 中更高效地进行机器学习、数据探索和转换。此 Notebook 的完整源代码可以在 GitHub 存储库中找到:https://github.com/bhrnjica/notebooks/blob/master/net_jupyter_notebook_part2.ipynb