본문 바로가기

TechTrend

JavaScript에서도 pandas 같은 라이브러리를? Danfo.js를 소개합니다.

August 25, 2020

본 게시글은 독립 연구원 Rising Odegua, 나이지리아 데이터 과학자 Stephen Oni의 포스팅을 번역하였습니다.

 

Danfo.js는 구조화된 데이터를 조작하고 처리할 수 있는 직관적이고

사용하기 쉬운 고성능 데이터구조를 제공하는 오픈 소스 JavaScript 라이브러리다.

Danfo.js는 Python Pandas 라이브러리에서 크게 영감을 받았으며

유사한 인터페이스와 API를 제공한다.

이는, Pandas API에 익숙하고 JavaScript를 알고있는

사용자가 쉽게 선택할 수 있음을 의미한다.

Danfo.js의 주요 목표 중 하나는

JavaScript 개발자에게 데이터처리, 기계학습 및 AI 도구를 제공하는 것이다.

이는 근본적으로 웹에 머신러닝을 가져온 TensorFlow.js 팀의 비전과 일치한다.

Numpy 및 Pandas와 같은 오픈 소스 라이브러리는

Python에서 데이터를 쉽게 조작할 수 있도록 혁명을 일으켰고

이를 기반으로 많은 도구가 구축되어 Python에서 머신러닝의 시대를 열었다.

 

Danfo.js는 TensorFlow.js를 기반으로 한다.

즉, Numpy가 Pandas 산술 연산을 지원하듯

Danfo.js는 TensorFlow.js의 산술 연산을 지원한다.

 

Danfo.js의 주요 기능들

Danfo.js는 TensorFlow.js를 기반으로 하기에 텐서를 지원하며, 연산 속도가 빠르다.

즉, Danfo.js에서 Tensor를 로드하여 Danfo 데이터 구조를 Tensor로 변환할 수도 있다.

 

아래의 예는 Tensor 객체에서 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()

 

Output :

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()

 

Output :

 

칼럼이 있는 배열 객체를 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()

 

Output :

 

고정 소수점 데이터뿐만 아니라 부동 소수점 데이터에서도 누락된 데이터(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()

 

Output :

 

레이블 기반 슬라이싱, 고급 인덱싱, 큰 데이터셋의 쿼리 :

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()

 

Output :

 

플랫 파일(CSV 및 Delimited)에서 데이터를 로드하기 위한 강력한 IO 도구.

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);
  })

 

OneHotEncoders, LabelEncoders 와 같은 강력한 데이터 전처리 기능과

StandardScaler 및 MinMaxScaler와 같은 스케일러는 DataFrame 및 Series에서 지원한다.

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"])

sf_enc.print()
new_sf.print()

 

Output :

 

브라우저에서 DataFrame 및 Series를 좌표에 그리기 위한 대화형의 유연하고 직관적인 API :

<!DOCTYPE html>
<html lang="en">
<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>

 

Output :

Danfo.js 및 TensorFlow.js를 사용한 Titanic Survival Prediction

아래에서는 Danfo.js 및 TensorFlow.js를 사용하는 간단한 종단간(end-to-end) 분류 작업을 보여 준다.

데이터로드, 데이터 셋의 조작 및 전처리에 Danfo를 사용한 다음 Tensor 객체를 내보낸다.

(인공지능에서 end-to-end는 처음부터 끝까지라는 뜻으로

데이터(입력)에서 목표한 결과(출력)까지를 사람의 개입없는 얻는다는 의미입니다.)

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
}

 

마지막으로 모델과 처리된 데이터를 Tensor로 로드하여 학습을 수행한다.

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와 매우 유사하며

꼭 자바스크립트 프로그래머가 아니더라도 코드를 쉽게 읽고 이해할 수 있다.

위 데모의 전체 소스 코드는 여기에서 찾을 수 있다.

 

맺음말

웹 기반 머신러닝이 발전함에 따라 그에 맞는 효율적인 데이터 과학 도구를 갖추는 것은 필수적이다.

Danfo.js와 같은 도구를 사용하면 웹 기반 애플리케이션이 머신러닝 기능을 쉽게 지원할 수 있으므로

흥미로운 애플리케이션 생태계가 열린다. TensorFlow.js는 Python에서만 사용할 수 있는 머신러닝 기능을

웹에 제공하여 혁명을 이끌었고, Danfo.js가 이 여정에 효율적인 파트너가 되길 바란다.

Danfo.js가 성장하는 것을 보고만 있을 수 없다! 웹 커뮤니티에서도 없어서는 안될 존재가 될 것이다!

 

쥬피터 노트북등의 플랫폼에서의 데이터분석도 있지만

내부적으로 브라우저 기반의 모바일앱이 많이 출시되는 추세로 보아

앞으로의 웹, 모바일앱시장에서의 인공지능에 많은 기대가 됩니다.

긴 글을 읽어주셔서 감사합니다. : )