データ分析を行うとなると、思いつくプログラミング言語は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を活用して、データ分析や機械学習のプロジェクトに取り組んでみてください。

Danfo.js Documentation | Danfo.js