拆分DataFrame的score列并解决类型转换问题以用于模型训练
问题描述
尝试将DataFrame的score列拆分为fullTimeHome、fullTimeAway等列用于模型训练,但类型转换语句if let scoreColumn = gameTrainingData["score"] as? Column<Dictionary<String, Optional<Any>>>始终执行失败——尽管该列显示类型确实是Column<Dictionary<String, Optional<Any>>>。未找到内置拆分函数,当前代码如下:
// Extract relevant information from the 'score' column if let scoreColumn = gameTrainingData["score"] as? Column<Dictionary<String, Optional<Any>>> { let winnerColumn = scoreColumn.map { ($0!["winner"] as? String) ?? "UNKNOWN" } let fullTimeHomeColumn = scoreColumn.map { ($0!["fullTime"] as? [String: Int])?["home"] ?? -1 } let fullTimeAwayColumn = scoreColumn.map { ($0!["fullTime"] as? [String: Int])?["away"] ?? -1 } // Add these as new columns to the DataFrame gameTrainingData.append(column: Column(name: "winner", contents: winnerColumn)) gameTrainingData.append(column: Column(name: "fullTimeHome", contents: fullTimeHomeColumn)) gameTrainingData.append(column: Column(name: "fullTimeAway", contents: fullTimeAwayColumn)) } // Define feature columns based on the extracted data let featureColumns = [ "homeTeam", "awayTeam", "fullTimeHome", "fullTimeAway", "referees" ] // Model Setup let parameters = MLRandomForestClassifier.ModelParameters( validation: .split(strategy: .automatic), maxIterations: 100, randomSeed: 38 ) let model = try MLRandomForestClassifier( trainingData: gameTrainingData, targetColumn: "winner", // Assuming you're predicting the winner featureColumns: featureColumns, parameters: parameters )
补充说明
示例输入:
"score": { duration = REGULAR; fullTime = { away = 0; home = 2; }; halfTime = { away = 0; home = 0; }; winner = "HOME_TEAM"; }
score列展示:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ score ┃ ┃ <Dictionary<String, Optional<Any>>> ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ ["halfTime": Optional({ away = 0; home = … │ │ ["halfTime": Optional({ away = 2; home = … │ │ ["halfTime": Optional({ away = 1; home = … │ │ ...(共23条更多数据) ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛
目标是拆分出fullTimeHome和fullTimeAway列,用于训练模型预测比赛最终比分。
解决方案
1. 类型转换失败的核心原因
Create ML中Column的泛型类型实际存储格式可能和显示的Dictionary<String, Optional<Any>>存在差异,比如底层是MLDictionaryFeatureValue而非原生Swift字典,直接强转会失败。
2. 正确的列拆分代码
替换原类型转换逻辑,改用逐行读取数据的方式提取字段:
// 先确认score列存在 guard let scoreColumn = gameTrainingData.column("score") else { fatalError("score列不存在") } // 初始化存储新列数据的数组 var winnerValues: [String] = [] var fullTimeHomeValues: [Int] = [] var fullTimeAwayValues: [Int] = [] // 遍历每行数据处理 for rowIndex in 0..<gameTrainingData.rows.count { // 逐行获取score列的原始值并转为字典 guard let scoreDict = scoreColumn.value(at: rowIndex) as? [String: Any] else { // 处理异常数据,填充默认值 winnerValues.append("UNKNOWN") fullTimeHomeValues.append(-1) fullTimeAwayValues.append(-1) continue } // 提取winner字段 let winner = scoreDict["winner"] as? String ?? "UNKNOWN" winnerValues.append(winner) // 提取fullTime中的home和away比分 let fullTimeDict = scoreDict["fullTime"] as? [String: Int] ?? [:] let homeScore = fullTimeDict["home"] ?? -1 let awayScore = fullTimeDict["away"] ?? -1 fullTimeHomeValues.append(homeScore) fullTimeAwayValues.append(awayScore) } // 将数组转为Column并添加到DataFrame gameTrainingData.append(column: Column(name: "winner", contents: winnerValues)) gameTrainingData.append(column: Column(name: "fullTimeHome", contents: fullTimeHomeValues)) gameTrainingData.append(column: Column(name: "fullTimeAway", contents: fullTimeAwayValues)) // 后续模型训练代码保持不变 let featureColumns = [ "homeTeam", "awayTeam", "fullTimeHome", "fullTimeAway", "referees" ] let parameters = MLRandomForestClassifier.ModelParameters( validation: .split(strategy: .automatic), maxIterations: 100, randomSeed: 38 ) let model = try MLRandomForestClassifier( trainingData: gameTrainingData, targetColumn: "winner", featureColumns: featureColumns, parameters: parameters )
3. 关键注意事项
- 避免直接强转
Column泛型类型,使用value(at:)逐行读取后转字典,兼容性更强。 - 添加异常处理逻辑,防止单条数据格式错误导致流程中断。
- 新列数据类型需匹配Create ML要求(字符串用
[String]、整数用[Int]),确保模型训练能正常识别。
内容的提问来源于stack exchange,提问作者JonGrimes20
相关产品推荐
相关产品推荐

