如何将特殊格式CSV解析为Map<String, List<Double>>构建词向量空间
Java 解析空格分隔的词向量CSV并构建字典
看起来你遇到的核心问题是正确拆分每行中的键和后续的57维数值,直接按空格拆分容易踩坑(比如多个连续空格、制表符混着用的情况),下面给你一套可靠的实现方案:
核心思路
假设你的CSV每行格式是:[无空格的键] [double值1] [double值2] ... [double值57],我们可以:
- 逐行读取文件内容
- 用任意空白字符作为分隔符拆分每行(避免多个空格/制表符的干扰)
- 取第一个元素作为键,剩余的57个元素转换为double数组作为值
- 将键值对存入
Map<String, double[]>(也就是你说的字典)
完整实现代码
方式一:使用Java 8+流式API(简洁高效)
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; public class WordVectorParser { public static void main(String[] args) { String csvPath = "你的词向量文件路径.csv"; Map<String, double[]> wordVectorMap = new HashMap<>(); try { Files.lines(Paths.get(csvPath)) .filter(line -> !line.isBlank()) // 跳过空行 .forEach(line -> { String[] parts = line.split("\\s+"); // 按任意空白字符拆分 if (parts.length != 58) { // 验证元素数量:1个键 + 57个值 System.err.println("无效行,元素数量不符:" + line); return; } String key = parts[0]; double[] vector = new double[57]; for (int i = 0; i < 57; i++) { try { vector[i] = Double.parseDouble(parts[i + 1]); } catch (NumberFormatException e) { System.err.println("数值转换失败,行:" + line + ",位置:" + (i+1)); return; } } wordVectorMap.put(key, vector); }); // 测试输出:打印第一个键的向量 wordVectorMap.forEach((key, vec) -> { System.out.println("键:" + key); System.out.print("向量:"); for (double d : vec) { System.out.print(d + " "); } System.out.println(); // 只打印第一个就退出,避免输出太多 return; }); } catch (IOException e) { System.err.println("读取文件失败:" + e.getMessage()); } } }
方式二:传统BufferedReader方式(兼容性更好)
如果你的项目还在使用Java 8以下版本,可以用这种方式:
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class WordVectorParser { public static void main(String[] args) { String csvPath = "你的词向量文件路径.csv"; Map<String, double[]> wordVectorMap = new HashMap<>(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(csvPath)); String line; while ((line = reader.readLine()) != null) { line = line.trim(); if (line.isBlank()) continue; String[] parts = line.split("\\s+"); if (parts.length != 58) { System.err.println("无效行,元素数量不符:" + line); continue; } String key = parts[0]; double[] vector = new double[57]; boolean isValid = true; for (int i = 0; i < 57; i++) { try { vector[i] = Double.parseDouble(parts[i + 1]); } catch (NumberFormatException e) { System.err.println("数值转换失败,行:" + line + ",位置:" + (i+1)); isValid = false; break; } } if (isValid) { wordVectorMap.put(key, vector); } } // 测试输出 if (!wordVectorMap.isEmpty()) { Map.Entry<String, double[]> firstEntry = wordVectorMap.entrySet().iterator().next(); System.out.println("第一个键:" + firstEntry.getKey()); System.out.print("向量:"); for (double d : firstEntry.getValue()) { System.out.print(d + " "); } } } catch (IOException e) { System.err.println("读取文件失败:" + e.getMessage()); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
注意事项与扩展
- 如果键包含空格怎么办?
如果你的键是带空格的(比如"hello world" 1.23 4.56 ...),直接按空格拆分就会出错。这种情况建议用专业的CSV解析库,比如OpenCSV,它可以处理带引号的字段。示例代码大概是:// 需要先引入OpenCSV依赖 CSVReader reader = new CSVReader(new FileReader(csvPath), ' '); // 指定空格为分隔符 String[] nextLine; while ((nextLine = reader.readNext()) != null) { // 这里nextLine[0]就是带空格的键(如果用引号括起来的话) } - 性能优化
如果你的词向量文件非常大,建议用LinkedHashMap保持顺序,或者预先估算Map的容量(比如new HashMap<>(预计单词数量))来减少扩容开销。 - 异常处理
代码里已经加入了基本的异常处理,你可以根据实际需求调整(比如把无效行记录到日志文件,而不是只打印到控制台)。
内容的提问来源于stack exchange,提问作者azyeboo
相关产品推荐
相关产品推荐

