雖然 Python 大行其道,但許多中大型企業核心系統還是以Java或C#為主,另外,Python要作出漂亮的UI介面也有困難,因此,筆者一直以來都想使用C#結合Python強大的生態環境(Ecosystem),作出漂亮的資料科學應用程式,日前剛好看到一篇好文『Getting Started With C# DataFrame and XPlot.Plotly』,介紹使用C#操作DataFrame,並繪製漂亮的統計圖,雖然還沒辦法變成獨立的執行檔(Exe),但也算前進了一大步。
步驟如下:
1.安裝 Visual Studio:注意,不是Visual Studio Code,筆者目前仍使用 Visual Studio 2019,若讀者使用Visual Studio 2022,須注意以下套件的版本。
2.安裝在cmd下的互動式工具。
dotnet tool install --global Microsoft.dotnet-interactive --version 1.0.155302
dotnet interactive jupyter install
大功告成,啟動Notebook測試,新增一個C#檔案,如下圖:
在第一格輸入:
Console.WriteLine("hello world !!");
順利輸出hello world !!
如果在網路抓一個C#的Notebook檔案(.ipynb),在開啟檔案後,選擇【Kernel】>【Change kernel】>【.net(C#)】即可。
#r "nuget:EikonDataAPI"
#r "nuget:Microsoft.Data.Analysis,0.4.0"
注意版本,VS 2022應可使用最新版。
using XPlot.Plotly;
using Microsoft.Data.Analysis;
using System.Linq;
using Microsoft.AspNetCore.Html;
// 格式化 DataFrame
Formatter.Register<DataFrame>((df, writer) =>
{
var headers = new List<IHtmlContent>();
headers.Add(th(i("index")));
headers.AddRange(df.Columns.Select(c => (IHtmlContent) th(c.Name)));
var rows = new List<List<IHtmlContent>>();
var take = 100; // 最多只顯示100列,可調整
for (var i = 0; i < Math.Min(take, df.Rows.Count); i++)
{
var cells = new List<IHtmlContent>();
cells.Add(td(i));
foreach (var obj in df.Rows[i])
{
cells.Add(td(obj));
}
rows.Add(cells);
}
var t = table(
thead(
headers),
tbody(
rows.Select(
r => tr(r))));
writer.Write(t);
writer.Write(df.Rows.Count + " x "+df.Columns.Count);
}, "text/html");
// 格式化 DataFrame 的列
Formatter.Register<DataFrameRow>((dataFrameRow, writer) =>
{
var cells = new List<IHtmlContent>();
cells.Add(td(i));
foreach (var obj in dataFrameRow)
{
cells.Add(td(obj));
}
var t = table(
tbody(
cells));
writer.Write(t);
}, "text/html");
var df1 = DataFrame.LoadCsv("");
df1
輸出如下圖:
Microsoft.Data.Analysis 支援 Ploty 統計圖,它是以Javascript開發的,有Tooltip,呈現內容比Matplotlib豐富。
var chart1 = Chart.Plot(
new Graph.Scatter
{
x = df1.Columns["Date"],
y = df1.Columns["Close"],
mode = "lines+markers"
}
);
var chart1_layout = new Layout.Layout{
title="Close Price",
xaxis =new Graph.Xaxis{
title = "Date"
},
yaxis =new Graph.Yaxis{
title = "Price (USD)"
}
};
chart1.WithLayout(chart1_layout);
chart1
輸出如下圖:
// 將 Date 欄位轉成日期資料型態
df1.Columns["Date"] = new PrimitiveDataFrameColumn<DateTime>("Date",
df1.Columns["Date"]
.Cast<object>()
.ToList()
.Select(x => DateTime.ParseExact(x.ToString(), "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture))
.Cast<DateTime>());
var candle_chart = Chart.Candlestick(df1.OrderBy("Date").Rows.Select(row => new Tuple<string, double, double, double, double>(
((DateTime)row[0]).ToString("yyyy-MM-dd"),
double.Parse(row[1].ToString()),
double.Parse(row[2].ToString()),
double.Parse(row[3].ToString()),
double.Parse(row[4].ToString())
)));
candle_chart.WithLayout(new Layout.Layout{
title="OHLC",
xaxis =new Graph.Xaxis{
title = "Date"
},
yaxis =new Graph.Yaxis{
title = "Price (USD)"
}
});
candle_chart
輸出如下圖:
對於 C# 與 Python 整合的議題,本來寄望微軟.net基金會支援的IronPython,不過,它沒辦法支援 Python 套件,版本更新的速度也很緩慢,現在看到Microsoft.Data.Analysis,似乎出現一道曙光,希望未來可以有更多的套件支援。
相關程式在這裡。