"use strict"
* @深度学习_数据集 深度学习项目的数据集相关方法库,目前包含:
* downloadExampleXlsxFile() 示例excel文件下载
* xlsxToJsonArr() 从excel文件读取并返回若干(数组格式的)JSON对象
* jsonToArray() 将JSON对象转为数组对象(递归)
* splitDatasetArr() 拆分数据集数组为训练集和测试集数组
* 无序化
* dataAoaToTensor2d() 将AOA化的数据集数组处理为特征及标签的二维张量
* tensorNormalize() 张量归一化
*/
* @库导入
*/
import * as tf from "@tensorflow/tfjs"
import * as XLSX from "xlsx"
import { downloadFile } from "./app-utils.js"
* @downloadExampleXlsxFile 下载示例excel文件
* @function
*/
export function downloadExampleXlsxFile() { try {
const exampleAoaData = [
["特征1", "特征2", "特征3", "标签1", "标签2"],
[10, 200, 30, 5, 20],
[35, 300, 40, 10, 40],
[24, 100, 20, 2, 30],
]
const sheet = XLSX.utils.aoa_to_sheet(exampleAoaData)
const workbook = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(workbook, sheet, "数据集")
const workbookArrBufObj = XLSX.write(workbook, { type: "buffer" })
downloadFile(workbookArrBufObj, "数据集.xlsx")
} catch (error) {
console.error("downloadExampleXlsxFile()报错: ", error)
}}
* @xlsxToJsonArr 从excel文件读取并返回若干(数组格式的)JSON对象
* @function async
* @param { File } xlsxFile excel文件。
* @param { String[] } [sheetNames] 表格名数组,若未填则默认读取第一个表格。
* @returns { JSON[] } 表格中的数据,以JSON对象数组的形式返回。
*/
export async function xlsxFileToJson(xlsxFile, sheetNames) { try {
const xlsxArrBuf = await xlsxFile.arrayBuffer()
const workbook = XLSX.read(xlsxArrBuf, { type: "buffer" })
if (!sheetNames) {
const dataJson = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]])
return [dataJson]
} else {
const dataJsonArr = []
for (let key in sheetNames) {
dataJsonArr.push(XLSX.utils.sheet_to_json(workbook.Sheets[sheetNames[key]]))
}
return dataJsonArr
}
} catch (error) {
console.error("downloadExampleXlsxFile()报错: ", error)
}}
* @jsonToArray 将JSON对象转为数组对象(递归)
* @function
* @param { JSON | JSON[] } jsonDataset 数据集JSON对象,它是个对象数组
* @returns { Array } 数据集对象
*/
export function jsonToArray(jsonDataset) { try {
const arrayDataset = []
if (typeof jsonDataset === "object") {
for (let key in jsonDataset) {
if (typeof jsonDataset[key] === "object") {
arrayDataset.push(jsonToArray(jsonDataset[key]))
} else {
arrayDataset.push(jsonDataset[key])
}
}
} else {
arrayDataset.push(jsonDataset)
}
return arrayDataset
} catch (error) {
console.error("jsonToArray()报错:", error)
}}
* @splitDatasetArr 拆分数据集数组为训练集和测试集数组
* @function
* @param { JSON[] | Array[] } rawDatasetArr 原始数据集。
* @param { Number } splitDuration 拆分间隔,必须大于1。
* @param { Boolean } [isUniShuffle] 拆分间隔内是否打散。
* @returns {{
* trainDatasetArr: JSON[] | Array[],
* testDatasetArr: JSON[] | Array[],
* }} 包含训练集和测试集的JSON对象数组
*/
export function splitDataset(rawDatasetArr, splitDuration, isUniShuffle) { try {
const trainDatasetArr = []
const testDatasetArr = []
const tempDatasetArr = []
for (let i = 0; i < rawDatasetArr.length; i++) {
tempDatasetArr.push(rawDatasetArr[i])
if ((i + 1) % splitDuration === 0) {
if (isUniShuffle) {
tf.util.shuffle(tempDatasetArr)
}
testDatasetArr.push(tempDatasetArr.pop())
trainDatasetArr.concat(tempDatasetArr)
tempDatasetArr.length = 0
}
}
return {
trainDatasetArr: trainDatasetArr,
testDatasetArr: testDatasetArr
}
} catch (error) {
console.error("dataArrToTensor2d()报错: ", error)
}}
* @无序化
* 使用Fisher-Yates算法对数据进行无序化处理
* 仅处理外层
* ```js
* tf.util.shuffle(array)
* ```
*/
* @dataAoaToTensor2d 将AOA化的数据集数组处理为特征及标签的二维张量
* @function
* @param { Array[] } dataAoa AOA化的数据集对象数组
* @param { Number } [indexRank] 数据集标签的数量
* @returns {{
* featureTensor: tf.Tensor2D,
* labelTensor: tf.Tensor2D
* }} 特征张量,标签张量
*/
export function dataAoaToTensor2d(dataAoa, indexRank) { try {
return tf.tidy(() => {
const dataTensor = tf.tensor2d(dataAoa, [dataAoa.length, dataAoa[0].length])
if ((!indexRank) || (indexRank === 0)) {
return {
featureTensor: dataTensor,
labelTensor: null,
}
} else {
const [featureArray, labelArray] = tf.split(
dataTensor,
[dataTensor.shape[1] - indexRank, indexRank],
1
)
return {
featureTensor: featureArray,
labelTensor: labelArray,
}
}
})
} catch (error) {
console.error("dataAoaToTensor2d()报错: ", error)
}}
* @tensorNormalize 张量归一化
* @function
* 沿着某一个轴,对张量进行归一化处理
* @note 只有全局归一化、特征轴归一化(轴为0)时,tensorMax和tensorMin才是有意义的
* 特征轴归一化:对某特征,求所有样本在该特征的最大值、最小值,然后归一化
* @param { tf.Tensor } tensor 张量
* @param { number } [axis] - 轴。对张量的第几个轴进行归一化
* @returns {{
* normalization: tf.Tensor<tf.Rank>,
* tensorMax: tf.Tensor<tf.Rank>,
* tensorMin: tf.Tensor<tf.Rank>
* axis: number
* }} 归一化的张量,最大张量,最小张量,轴
* @note 对于一般的二维张量而言,有2个轴axis:0轴为样本轴,1轴为特征轴
* @note 对于一般的三维张量而言,有3个轴axis:0轴为样本轴,1轴为特征组轴,2为组内各特征轴
*/
export function tensorNormalize(tensor, axis) { try {
return tf.tidy(() => {
const tensorMax = tf.max(tensor, axis)
const tensorMin = tf.min(tensor, axis)
if ((!axis) || (axis === 0)) {
const normalization = tensor.sub(tensorMin).div(tensorMax.sub(tensorMin))
return {
normalization: normalization,
tensorMax: tensorMax,
tensorMin: tensorMin,
axis: null
}
} else {
const tileArray = []
for (let i = 0; i < tensor.rank; i++) {
if (i === axis) {
tileArray.push(tensor.shape[i])
} else {
tileArray.push(1)
}
}
const tensorMaxTemp = tensorMax.expandDims(axis).tile(tileArray)
const tensorMinTemp = tensorMin.expandDims(axis).tile(tileArray)
const normalization = tensor.sub(tensorMinTemp)
.div(tensorMaxTemp.sub(tensorMinTemp))
return {
normalization: normalization,
tensorMax: null,
tensorMin: null,
axis: axis
}
}
})
} catch (error) {
console.error("tensorNormalize()报错: ", error)
}}