データ分析を行うとなると、思いつくプログラミング言語はPythonやRが多いかもしれません。しかし、JavaScriptでも強力なデータ解析が可能です。Danfojsは、JavaScriptでデータ操作と解析を行うためのライブラリで、Pandasに似たAPIを提供しています。
ブラウザやNode.js環境で、データ分析を行う際の選択肢としてDanfojsはとても有用です。本記事では、Danfojsの基本的な使い方を紹介します。
Danfojsのインストール
Danfojsは、npmを使ってインストールできます。
# Node.js環境の場合
npm install danfojs-node
# ブラウザ環境の場合
npm install danfojs
ブラウザ環境は、ReactやVue.jsなどのフレームワークでも利用可能です。また、CDNから直接読み込むこともできます。
<script src="https://cdn.jsdelivr.net/npm/danfojs@1.1.2/lib/bundle.js"></script>
基本的なデータ出力
以下は、Danfojsを使って基本的なデータフレームを作成し、データを出力する例です。グラフ出力する際には、Plotly.jsも利用します。
<script src="https://cdn.plot.ly/plotly-1.2.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/danfojs@1.2.0/lib/bundle.min.js"></
<div id="plot_div"
style="width:100%;height:400px;"
></div>
<script>
df = new dfd.DataFrame({
'pig': [20, 18, 489, 675, 1776],
'horse': [4, 25, 281, 600, 1900]
}, {
index: [1990, 1997, 2003, 2009, 2014]
});
df.plot("plot_div").line();
</script>
実行結果です。
グラフはズームなどが使えて高機能です(これはPlotly.jsの機能です)。
CSVデータの読み込みと表示
Danfojsを使ってCSVデータを読み込み、表示する例です。以下のコードでは、Appleの株価データを読み込み、移動平均線を計算して表示しています。
データはこのCSVです。最初の部分だけ抜粋します。
Date,AAPL.Open,AAPL.High,AAPL.Low,AAPL.Close,AAPL.Volume,AAPL.Adjusted,dn,mavg,up,direction
2015-02-17,127.489998,128.880005,126.919998,127.830002,63152400,122.905254,106.7410523,117.9276669,129.1142814,Increasing
2015-02-18,127.629997,128.779999,127.449997,128.720001,44891700,123.760965,107.842423,118.9403335,130.0382439,Increasing
表示処理です。
<div id="plot_div"></div>
<script>
(async () => {
const df = await dfd.readCSV(
"https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv"
);
let layout = {
title: "A financial charts",
xaxis: {
title: "Date",
},
yaxis: {
title: "Count",
},
};
let config = {
columns: ["AAPL.Open", "AAPL.High"],
};
let new_df = df.setIndex({ column: "Date" });
new_df.plot("plot_div").line({ config, layout });
})();
</script>
実際の表示です。
データ分析系
データフレームの一部を抽出して表示
グラフ表示を行わず、データ分析系の処理もDanfojsで可能です。以下は、データフレームの一部を抽出して表示する例です。
let data = {
"Name": ["Apples", "Mango", "Banana", "Pear"] ,
"Count": [21, 5, 30, 10] ,
"Price": [200, 300, 40, 250]
};
let df = new dfd.DataFrame(data, {index: ["a", "b", "c", "d"]});
df.print();
let sub_df = df.loc({rows: ["a", "c"]});
sub_df.print();
結果は以下の通りです。aとcの行だけ抽出されています。
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║ │ Name │ Count │ Price ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ a │ Apples │ 21 │ 200 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ b │ Mango │ 5 │ 300 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ c │ Banana │ 30 │ 40 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ d │ Pear │ 10 │ 250 ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║ │ Name │ Count │ Price ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ a │ Apples │ 21 │ 200 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ c │ Banana │ 30 │ 40 ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝
行と列の両方を指定して抽出
以下は、行と列の両方を指定してデータフレームの一部を抽出する例です。最初は全データ出力していますが、その後、最初の2行と「Name」と「Price」列だけを抽出しています。
let data = {
"Name": ["Apples", "Mango", "Banana", "Pear"] ,
"Count": [21, 5, 30, 10],
"Price": [200, 300, 40, 250]
};
let df = new dfd.DataFrame(data);
df.print();
// 行と列の両方を指定して抽出
let sub_df = df.loc({ rows: [0,1], columns: ["Name", "Price"] });
sub_df.print();
結果は以下の通りです。
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║ │ Name │ Count │ Price ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ Apples │ 21 │ 200 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ Mango │ 5 │ 300 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ Banana │ 30 │ 40 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ Pear │ 10 │ 250 ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝
╔════════════╤═══════════════════╤═══════════════════╗
║ │ Name │ Price ║
╟────────────┼───────────────────┼───────────────────╢
║ 0 │ Apples │ 200 ║
╟────────────┼───────────────────┼───────────────────╢
║ 1 │ Mango │ 300 ║
╚════════════╧═══════════════════╧═══════════════════╝
欠損値を含む列の削除
以下は、欠損値を含む列を削除する例です。最初にデータフレーム全体を表示し、その後、欠損値( NaN )を含む列を削除したデータフレームを表示しています。
let data = [[1, 2, 3], [NaN, 5, 6], [20, 30, 40], [39, 34, 78]]
let cols = ["A", "B", "C"]
let df = new dfd.DataFrame(data, { columns: cols })
df.print()
// 欠損値を含む列を削除
let df_drop = df.dropNa({ axis: 1 })
df_drop.print();
結果は以下の通りです。
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║ │ A │ B │ C ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ 1 │ 2 │ 3 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ NaN │ 5 │ 6 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ 20 │ 30 │ 40 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ 39 │ 34 │ 78 ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║ │ A │ B │ C ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ 1 │ 2 │ 3 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ 20 │ 30 │ 40 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ 39 │ 34 │ 78 ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝
欠損値の位置を特定
以下は、欠損値の位置を特定する例です。データフレーム全体を表示し、その後、各セルが欠損値かどうかを示すブール値のデータフレームを表示しています。
let data = {"Name":["Apples", "Mango", "Banana", undefined],
"Count": [NaN, 5, NaN, 10],
"Price": [200, 300, 40, 250]}
let df = new dfd.DataFrame(data)
df.isNa().print()
結果は以下の通りです。
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║ │ Name │ Count │ Price ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ false │ true │ false ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ false │ false │ false ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ false │ true │ false ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ true │ false │ false ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝
TensorFlow.jsとの連携
DanfojsはTensorFlow.jsと連携して、機械学習モデルのトレーニングや予測に利用できます。以下は、DanfojsのデータフレームをTensorFlow.jsのテンソルに変換する例です。
let data = {
"Feature1": [1, 2, 3, 4],
"Feature2": [5, 6, 7, 8],
"Label": [0, 1, 0, 1]
};
let df = new dfd.DataFrame(data);
let features = df.loc({ columns: ["Feature1", "Feature2"] }).tensor;
let labels = df.loc({ columns: ["Label"] }).tensor;
features.print();
labels.print();
結果は以下の通りです。
Tensor
[[1, 5],
[2, 6],
[3, 7],
[4, 8]]
Tensor
[[0],
[1],
[0],
[1]]
集計
Danfojsは、データの集計操作もサポートしています。以下は、グループ化と集計の例です。
let data = {
"Category": ["A", "B", "A", "B", "A"],
"Values": [10, 20, 30, 40, 50]
};
let df = new dfd.DataFrame(data);
let grouped = df.groupby(["Category"]).col(["Values"]).sum();
grouped.print();
結果は以下の通りです。
╔════════════╤═══════════════════╤═══════════════════╗
║ │ Category │ Values_sum ║
╟────────────┼───────────────────┼───────────────────╢
║ 0 │ A │ 90 ║
╟────────────┼───────────────────┼───────────────────╢
║ 1 │ B │ 60 ║
╚════════════╧═══════════════════╧═══════════════════╝
出力フォーマット
Danfojsは、データフレームをさまざまなフォーマットで出力できます。対応フォーマットは以下の通りです。
- CSV
- JSON
- Excel
他にも多くの機能がありますので、公式ドキュメントを参照してください。
まとめ
今回はDanfojsの基本的な使い方を紹介しました。JavaScriptでデータ解析を行う際に、Danfojsは非常に強力なツールとなります。ぜひ、Danfojsを活用して、データ分析や機械学習のプロジェクトに取り組んでみてください。
