Golang中Gota DataFrame读取CSV/JSON差异及Excel转DataFrame问询
问题说明
- 用Golang的Gota库时,
dataframe.ReadJSON()和dataframe.ReadCSV()读取同一份数据生成的DataFrame存在差异,目前能看到的是列顺序颠倒,不排除还有其他未知差异 - 项目要求JSON转出来的DataFrame必须和CSV版本完全一致
- 当前工作流程:
- 判断文件是xlsx还是csv
- 用对应方式转成DataFrame
- 把DataFrame传给
processDF()函数处理
- 用到的库:
xlsxreader、gota/dataframe、excel2json
解决方法
一、对齐JSON与CSV生成的DataFrame
核心问题:列顺序不统一
JSON的键是无序的,dataframe.ReadJSON()会按字典序排列列;而CSV是按文件里的顺序读取列。要让两者对齐,只需要:
- 先读CSV拿到标准列顺序
- 读JSON生成DataFrame后,按这个标准顺序重新排列列
其他潜在差异处理
- 数据类型:JSON的数值可能被解析成float,CSV可能推断为int,可以通过
dataframe.ReadOption强制统一类型 - 空值处理:用
dataframe.WithNaN()之类的选项,确保JSON和CSV的空值解析逻辑一致
二、直接把Excel转成Gota DataFrame(绕开JSON中转)
如果不想折腾JSON和CSV的差异,直接用xlsxreader读取Excel内容,手动构建DataFrame就行,步骤如下:
- 用
xlsxreader打开Excel,读取目标工作表 - 读取表头作为列名
- 逐行读取单元格数据,转成Gota支持的
series.Series - 用列名和对应的Series构建DataFrame
代码示例
1. 让JSON生成的DataFrame对齐CSV的列顺序
package main import ( "os" "github.com/go-gota/gota/dataframe" ) // 获取CSV的列顺序,作为标准参考 func getCSVColumnOrder(csvPath string) []string { f, err := os.Open(csvPath) if err != nil { panic(err) } defer f.Close() csvDF := dataframe.ReadCSV(f) return csvDF.Names() } // 读取JSON并按指定列顺序重新排列 func jsonToAlignedDF(jsonPath string, columnOrder []string) dataframe.DataFrame { f, err := os.Open(jsonPath) if err != nil { panic(err) } defer f.Close() jsonDF := dataframe.ReadJSON(f) // 按CSV的列顺序重新选择列 return jsonDF.Select(columnOrder) } func main() { csvPath := "data.csv" jsonPath := "data.json" colOrder := getCSVColumnOrder(csvPath) alignedDF := jsonToAlignedDF(jsonPath, colOrder) processDF(alignedDF) } func processDF(df dataframe.DataFrame) { // 这里写你的DataFrame处理逻辑 }
2. 直接读取Excel生成Gota DataFrame
package main import ( "fmt" "github.com/go-gota/gota/dataframe" "github.com/go-gota/gota/series" "github.com/tealeg/xlsx" ) // 把Excel文件转成Gota DataFrame,sheetIndex是工作表下标(从0开始) func excelToDF(excelPath string, sheetIndex int) (dataframe.DataFrame, error) { xlFile, err := xlsx.OpenFile(excelPath) if err != nil { return dataframe.DataFrame{}, err } if sheetIndex >= len(xlFile.Sheets) { return dataframe.DataFrame{}, fmt.Errorf("指定的工作表下标超出范围") } sheet := xlFile.Sheets[sheetIndex] // 读取表头作为列名 var colNames []string headerRow := sheet.Rows[0] for _, cell := range headerRow.Cells { colNames = append(colNames, cell.String()) } // 按列收集数据,准备构建Series colData := make([][]interface{}, len(colNames)) for rowIdx := 1; rowIdx < len(sheet.Rows); rowIdx++ { row := sheet.Rows[rowIdx] for cellIdx, cell := range row.Cells { if cellIdx >= len(colNames) { continue // 跳过超出表头列数的单元格 } // 这里默认转成字符串,你可以根据实际需求处理成int/float等类型 colData[cellIdx] = append(colData[cellIdx], cell.String()) } } // 构建Series数组 var seriesList []series.Series for idx, name := range colNames { s := series.String(colData[idx], series.Name(name)) seriesList = append(seriesList, s) } // 生成最终的DataFrame return dataframe.New(seriesList...), nil } func main() { excelPath := "data.xlsx" df, err := excelToDF(excelPath, 0) // 读取第一个工作表 if err != nil { panic(err) } processDF(df) } func processDF(df dataframe.DataFrame) { // 这里写你的DataFrame处理逻辑 }
内容的提问来源于stack exchange,提问作者Ethan Leonard
相关产品推荐
相关产品推荐

