深受 Pandas 啟發的 JavaScript 開源庫 — Danfo.js 現已推出!

思否編輯部發表於2020-09-21

作者:Rising Odegua 與 Stephen Oni | 來源 TensorFlow


Danfo.js 是個 JavaScript 開源庫,提供了高效能、直觀易用的資料結構,支援結構化資料的操作和處理。Danfo.js 深受 Python Pandas 庫的啟發,並提供了類似的介面/API。因此熟悉 Pandas API 且瞭解 JavaScript 的使用者可以輕鬆上手。

Danfo.js 的一大目標是為 JavaScript 開發者提供資料處理、機器學習和 AI 工具。這與我們的願景一致,本質上也符合 TensorFlow.js 團隊向 Web 引入 ML 的目標。Numpy 和 Pandas 等開源庫全面革新了 Python 中資料操作的便利性。因此很多工具都圍繞它們構建,進一步推動了 Python 中 ML 生態系統的蓬勃發展。

Danfo.js 建立在 TensorFlow.js 上。也就是說,就像 Numpy 為 Pandas 的算術運算提供技術支援一樣,我們是利用 TensorFlow.js 為我們的低階算術運算提供技術支援。

Danfo.js 的主要特性

Danfo.js 速度快。它基於 TensorFlow.js 構建,與張量無縫相容。您可以在 Danfo 中載入張量,也可以將 Danfo 資料結構轉換為張量。利用這兩個庫,既有了資料處理庫 (Danfo.js),也有了強大的 ML 庫 (TensorFlow.js)。

以下示例將展示如何從張量物件建立 Danfo DataFrame:

const dfd = require("danfojs-node")
const tf = require("@tensorflow/tfjs-node")
let data = tf.tensor2d([[20,30,40], [23,90, 28]])
let df = new dfd.DataFrame(data)
let tf_tensor = df.tensor
console.log(tf_tensor);
tf_tensor.print()

輸出:

Tensor {
  kept: false,
  isDisposedInternal: false,
  shape: [ 2, 3 ],
  dtype: 'float32',
  size: 6,
  strides: [ 3 ],
  dataId: {},
  id: 3,
  rankType: '2'
}
Tensor
    [[20, 30, 40],
     [23, 90, 28]]

您可以輕鬆地將陣列、JSON 或物件轉換為 DataFrame 物件操作。

JSON 物件到 DataFrame:

const dfd = require("danfojs-node")
json_data = [{ A: 0.4612, B: 4.28283, C: -1.509, D: -1.1352 },
            { A: 0.5112, B: -0.22863, C: -3.39059, D: 1.1632 },
            { A: 0.6911, B: -0.82863, C: -1.5059, D: 2.1352 },
            { A: 0.4692, B: -1.28863, C: 4.5059, D: 4.1632 }]
df = new dfd.DataFrame(json_data)
df.print()

輸出:

帶列標籤的物件陣列到 DataFrame:

const dfd = require("danfojs-node")
obj_data = {'A': [“A1”, “A2”, “A3”, “A4”],
            'B': ["bval1", "bval2", "bval3", "bval4"],
            'C': [10, 20, 30, 40],
            'D': [1.2, 3.45, 60.1, 45],
            'E': ["test", "train", "test", "train"]
            }
df = new dfd.DataFrame(obj_data)
df.print()

輸出:

您可以輕鬆處理浮點和非浮點資料中的缺失資料(以 NaN 表示):

const dfd = require("danfojs-node")
let data = {"Name":["Apples", "Mango", "Banana", undefined],
            "Count": [NaN, 5, NaN, 10],
            "Price": [200, 300, 40, 250]}
let df = new dfd.DataFrame(data)
let df_filled = df.fillna({columns: ["Name", "Count"], values: ["Apples",
df["Count"].mean()]})
df_filled.print()

輸出:

基於智慧標籤的切片、花式索引和大資料集查詢:

const dfd = require("danfojs-node")
let data = { "Name": ["Apples", "Mango", "Banana", "Pear"] ,
            "Count": [21, 5, 30, 10],
             "Price": [200, 300, 40, 250] }
let df = new dfd.DataFrame(data)
let sub_df = df.loc({ rows: ["0:2"], columns: ["Name", "Price"] })
sub_df.print()

輸出:

強大的 IO 工具,用於從平面檔案(CSV 和分隔)載入資料。完整和分塊均可:

const dfd = require("danfojs-node")
//read the first 10000 rows
dfd.read_csv("file:///home/Desktop/bigdata.csv", chunk=10000)
  .then(df => {
    df.tail().print()
  }).catch(err=>{
       console.log(err);
  })

DataFrame 和 Series 支援 OneHotEncoders、LabelEncoders 等強大的資料預處理函式和 StandardScaler 和 MinMaxScaler 等 Scaler:

const dfd = require("danfojs-node")
let data = ["dog","cat","man","dog","cat","man","man","cat"]
let series = new dfd.Series(data)
let encode = new dfd.LabelEncoder()
encode.fit(series)
let sf_enc = encode.transform(series)
let new_sf = encode.transform(["dog","man"])

輸出:

互動式、靈活且直觀的 API,用於在瀏覽器中繪製 DataFrame 和 Series:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/danfojs@0.1.1/dist/index.min.js"></script>
    <title>Document</title>
</head>
<body>
    <div id="plot_div"></div>
    <script>
         dfd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv")
            .then(df => {
                var layout = {
                    title: 'A financial charts',
                    xaxis: {title: 'Date'},
                    yaxis: {title: 'Count'}
                }
    new_df = df.set_index({ key: "Date" })
   new_df.plot("plot_div").line({ columns: ["AAPL.Open", "AAPL.High"], layout: layout
})
            }).catch(err => {
                console.log(err);
            })
    </script>
</body>
</html>

輸出:

示例:泰坦尼克號倖存預測

以下是使用 Danfo.js 和 TensorFlow.js 的簡單端到端分類任務。使用 Danfo 進行資料集的資料載入、操作和預處理,然後匯出張量物件。

const dfd = require("danfojs-node")
const tf = require("@tensorflow/tfjs-node")
async function load_process_data() {
    let df = await dfd.read_csv("https://web.stanford.edu/class/archive/cs/cs109/cs109.1166/stuff/titanic.csv")
    //A feature engineering: Extract all titles from names columns
    let title = df['Name'].apply((x) => { return x.split(".")[0] }).values
    //replace in df
    df.addColumn({ column: "Name", value: title })
    //label Encode Name feature
    let encoder = new dfd.LabelEncoder()
    let cols = ["Sex", "Name"]
    cols.forEach(col => {
        encoder.fit(df[col])
        enc_val = encoder.transform(df[col])
        df.addColumn({ column: col, value: enc_val })
    })
    let Xtrain,ytrain;
    Xtrain = df.iloc({ columns: [`1:`] })
    ytrain = df['Survived']
    // Standardize the data with MinMaxScaler
    let scaler = new dfd.MinMaxScaler()
    scaler.fit(Xtrain)
    Xtrain = scaler.transform(Xtrain)
    return [Xtrain.tensor, ytrain.tensor] //return the data as tensors
}

接下來使用 TensorFlow.js 建立一個簡單的神經網路。

function get_model() {
    const model = tf.sequential();
    model.add(tf.layers.dense({ inputShape: [7], units: 124, activation: 'relu', kernelInitializer: 'leCunNormal' }));
    model.add(tf.layers.dense({ units: 64, activation: 'relu' }));
    model.add(tf.layers.dense({ units: 32, activation: 'relu' }));
    model.add(tf.layers.dense({ units: 1, activation: "sigmoid" }))
    model.summary();
    return model
}

最後進行訓練,首先將模型和處理後的資料載入為張量。這可以直接饋送到神經網路。

async function train() {
    const model = await get_model()
    const data = await load_process_data()
    const Xtrain = data[0]
    const ytrain = data[1]
    model.compile({
        optimizer: "rmsprop",
        loss: 'binaryCrossentropy',
        metrics: ['accuracy'],
    });
    console.log("Training started....")
    await model.fit(Xtrain, ytrain,{
        batchSize: 32,
        epochs: 15,
        validationSplit: 0.2,
        callbacks:{
            onEpochEnd: async(epoch, logs)=>{
                console.log(`EPOCH (${epoch + 1}): Train Accuracy: ${(logs.acc * 100).toFixed(2)},
                                                     Val Accuracy:  ${(logs.val_acc * 100).toFixed(2)}n`);
            }
        }
    });
};
train()

您可能注意到 Danfo 的 API 與 Pandas 非常相似,即使不是 Javascript 程式設計師也可以輕鬆閱讀和理解程式碼。您可參考以上演示的完整原始碼 (https://gist.github.com/risen...

結語

基於網路的機器學習已經日趨成熟,對應的專用高效資料科學工具必不可少。類似 Danfo.js 的工具讓基於網路的應用可以輕鬆支援 ML 特性,從而讓應用生態系統更加豐富多彩。

這場變革始於 TensorFlow.js 為 Python 帶來的 ML 功能。我們希望為 Danfo.js 作為高效的同伴一路提供支援。我們對 Danfo.js 的發展充滿期待!希望它也能成為網路社群的關鍵成員。

相關文章