pandas の代わりに使える danfo.js というツールがあることを知る。 pandas は Pythonのツールなので、JavaScript の方が慣れている人にとって danfo.js はありがたい。
こんなエクセルデータがあったとして、これを danfo.js で操作していく覚え書き。
$ node --version
v16.15.0
$ npm -version
8.5.5
$ mkdir hello-danfo
$ cd hello-danfo
$ npm init -y
$ npm install danfojs-node
pandas 互換になっているらしいので、さまざまな操作ができると思う。 ここでは、以前のエントリーで pandas を使って特定の列を抜き出し新しいエクセルデータを作り出す操作をやってみる。
まずは、冒頭のエクセルのファイル ./maclist.xlsx を読み込み:
//
// index.js
//
const dfd = require('danfojs-node');
const proc = async ()=>{
const df = await dfd.readExcel('maclist.xlsx');
df.print();
};
proc();
実行:
$ node index.js
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║ │ id │ kind │ name │ price ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ mba │ laptop │ MacBook Air │ 98000 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ mbp │ laptop │ MacBook Pro │ 248000 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ mm │ desktop │ Mac mini │ 78000 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ im │ desktop │ iMac │ 154800 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 4 │ mp │ desktop │ MacPro │ 715000 ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝
できた!(データを読み込めただけだが)
それでは本題の、name と price 列だけを取り出した DataFrame を新規に作成して、それをエクセルデータとして保存をやってみる。
まず、既存の df から name 列を取り出してみよう.
console.log(df['name']);
実行:
$ node index.js
Series {
'$dataIncolumnFormat': [ 'MacBook Air', 'MacBook Pro', 'Mac mini', 'iMac', 'MacPro' ],
'$index': [ 0, 1, 2, 3, 4 ],
'$columns': [ 'name' ],
'$dtypes': [ 'string' ],
'$isSeries': true,
'$config': Configs {
tableDisplayConfig: {},
tableMaxRow: 10,
tableMaxColInConsole: 10,
dtypeTestLim: 20,
lowMemoryMode: false
},
'$data': [ 'MacBook Air', 'MacBook Pro', 'Mac mini', 'iMac', 'MacPro' ]
}
df['カラム名'] すると Series オブジェクトが返ってくる。
ならば df['name'].values すれば、その列の配列が返るであろう。
console.log(df['name'].values);
実行:
$ node index.js
[ 'MacBook Air', 'MacBook Pro', 'Mac mini', 'iMac', 'MacPro' ]
意図通り、name 列の値が配列で取得できました。
新規のデータフレームを作成して、 初期値として name2 列を入れてみます。
const df2 = new dfd.DataFrame([df['name'].values], {columns: ['name2']});
df2.print();
実行してみると:
$ node index.js
Error: ParamError: Column names length mismatch. You provided a column of length 1 but Ndframe columns has length of 5
エラー。列数は1 を指定されているがデータは5列分ある、というエラーメッセージ。 つまり、[df['name'].values] を転置して与える必要があるようだ。
ならば、underscore を使って転置したデータを使って、再トライ!
$ npm install underscore
該当箇所を修正します。 転置(行と列の入れ替え)は transpose すればOKです。
const df2 = new dfd.DataFrame(_.transpose([df['name'].values]), {columns: ['name2']});
コード全体は:
//
// index.js
//
const dfd = require('danfojs-node')
const _ = require('underscore')
const proc = async ()=>{
const df = await dfd.readExcel('maclist.xlsx');
console.log(df['name'].values);
const df2 = new dfd.DataFrame(_.transpose([df['name'].values]), {columns: ['name2']});
df2.print();
};
proc();
実行:
$ node index.js
[ 'MacBook Air', 'MacBook Pro', 'Mac mini', 'iMac', 'MacPro' ]
╔════════════╤═══════════════════╗
║ │ name2 ║
╟────────────┼───────────────────╢
║ 0 │ MacBook Air ║
╟────────────┼───────────────────╢
║ 1 │ MacBook Pro ║
╟────────────┼───────────────────╢
║ 2 │ Mac mini ║
╟────────────┼───────────────────╢
║ 3 │ iMac ║
╟────────────┼───────────────────╢
║ 4 │ MacPro ║
╚════════════╧═══════════════════╝
今度はうまくいきました。
それではここに price 列を追加してみましょう。
df2.addColumn('price2', df['price'].values, {inplace: true});
df2.print();
実行:
$ node index.js
╔════════════╤═══════════════════╤═══════════════════╗
║ │ name2 │ price2 ║
╟────────────┼───────────────────┼───────────────────╢
║ 0 │ MacBook Air │ 98000 ║
╟────────────┼───────────────────┼───────────────────╢
║ 1 │ MacBook Pro │ 248000 ║
╟────────────┼───────────────────┼───────────────────╢
║ 2 │ Mac mini │ 78000 ║
╟────────────┼───────────────────┼───────────────────╢
║ 3 │ iMac │ 154800 ║
╟────────────┼───────────────────┼───────────────────╢
║ 4 │ MacPro │ 715000 ║
╚════════════╧═══════════════════╧═══════════════════╝
これで、既存のエクセルから name, price 列を取り出した新しいデータフレームを生成できました。
最後に、name2 と price2 列の情報をマージした新しい text 列を追加してみます。
const textValues = _.map(_.transpose([df2['name2'].values, df2['price2'].values]), (row)=>{
return `${row[0]} : ${row[1]}yen`
});
df2.addColumn('text', textValues, {inplace: true});
df2.print();
実行:
$ node index.js
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║ │ name2 │ price2 │ text ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ MacBook Air │ 98000 │ MacBook Air : 9… ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ MacBook Pro │ 248000 │ MacBook Pro : 2… ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ Mac mini │ 78000 │ Mac mini : 7800… ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ iMac │ 154800 │ iMac : 154800yen ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 4 │ MacPro │ 715000 │ MacPro : 715000… ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝
できました!
あとはこれをCSVとして保存:
dfd.toCSV(df2, {filePath: 'result.csv'});
実行して、 result.csv を確認:
$ cat result.csv
name2,price2,text
MacBook Air,98000,MacBook Air : 98000yen
MacBook Pro,248000,MacBook Pro : 248000yen
Mac mini,78000,Mac mini : 78000yen
iMac,154800,iMac : 154800yen
MacPro,715000,MacPro : 715000yen
問題ありません。
最後にここまで書いたコード全体を掲載します。
//
// index.js
//
const dfd = require('danfojs-node')
const _ = require('underscore')
const proc = async ()=>{
const df = await dfd.readExcel('maclist.xlsx');
//console.log(df['name'].values);
const df2 = new dfd.DataFrame(_.transpose([df['name'].values]), {columns: ['name2']});
df2.addColumn('price2', df['price'].values, {inplace: true});
const textValues = _.map(_.transpose([df2['name2'].values, df2['price2'].values]), (row)=>{
return `${row[0]} : ${row[1]}yen`
});
df2.addColumn('text', textValues, {inplace: true});
df2.print();
dfd.toCSV(df2, {filePath: 'result.csv'});
};
proc();
以上です。
danfo.js 簡単に扱えました。 公式ドキュメントが充実していて助かります。
pandasで同じことをしている以前のエントリー と同じ手順で、元になるエクセルデータから name, price 列を抜き出して新しいデータフレームを生成するコード。
//
// index.js
//
const dfd = require('danfojs-node')
const proc = async ()=>{
const df = await dfd.readExcel('maclist.xlsx');
const nameValues = df['name'].values;
const priceValues = df['price'].values;
const df2 = new dfd.DataFrame( {name: nameValues, price: priceValues} )
df2.print();
};
proc();
こちらのほうが簡単に記述できました。