You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优雅高效地从文本文件读取数值并构建numpy数组字典?

优化文本数据集解析为字典的实现方案

首先,你的核心思路没问题,但现有代码存在几个小语法问题(比如变量名带空格、with语句缺少open()、取正则匹配结果时未索引到具体元素),而且可以通过状态管理简化逻辑、利用numpy的批量加载提升效率,让代码更易读且高效。下面分享几种优化方案:

先看你的原始问题与代码

我有一个如下结构的文本文件(开头有意留空):

  • 一些无关文本行
  • Data set # 1
    Time Data1 Data2
    [s] [kg/m2] [C]
1.0 2.45 465.5E-5
2.0 3.76 876.6E-6
...
// 表格末尾到下一行之间有空行
// Data set # 2
...
...

我希望创建一个字典,键为数据集编号(如'1'),值为对应后续的浮点矩阵。目前我使用以下代码实现:
```python
results = []
num_of points = []  # 语法错误:变量名不能包含空格
dict_results = {}
regex_pattern = r'-?\ *[0-9]+\.?[0-9]*(?:[Ee]\ *-?\ *[0-9]+)?' # 匹配所有数值
with ('file.txt') as f:  # 语法错误:缺少open()函数
    for line in f:
        test_line = re.findall (regex_pattern, line)
        if len(test_line) == 1: # 判断是否是数据集编号行
            if not num_of points: # 处理第一个数据集
                current point = int (test_line)  # 语法错误+逻辑错误:变量名空格,且test_line是列表需取[0]
                num_of_points.append(current_point)
            else:
                # 将数据存入字典
                results_array = np.array(results , dtype= float)
                dict_results.update({num_of_points[-1] : results_array})
                # 重置结果列表
                results = []
                # 更新数据集编号
                current_point = int(test_line)
                num_of_points.append(current_point)
        elif len(test_line) == 3: # 判断是否是数据行
            results.append(test_line)
```
该代码似乎可以正常运行,但我想知道是否存在更优雅且高效的实现方式。非常感谢!

方案1:简化状态管理,用生成器拆分数据集

这个方案把解析逻辑拆分为生成器函数,代码模块化,逻辑清晰,适合大多数场景:

import re
import numpy as np

def parse_data_sets(file_path):
    # 预编译正则,提升匹配效率
    regex_dataset = re.compile(r'Data set # (\d+)')
    regex_data_line = re.compile(
        r'(-?\s*\d+\.?\d*(?:[Ee]\s*-?\s*\d+)?)\s+'
        r'(-?\s*\d+\.?\d*(?:[Ee]\s*-?\s*\d+)?)\s+'
        r'(-?\s*\d+\.?\d*(?:[Ee]\s*-?\s*\d+)?)'
    )
    
    current_dataset = None
    current_data = []
    
    with open(file_path, 'r') as f:
        for line in f:
            line = line.strip()
            if not line:
                continue  # 跳过空行
            
            # 匹配数据集编号行
            dataset_match = regex_dataset.match(line)
            if dataset_match:
                # 保存上一个数据集(如果存在)
                if current_dataset is not None:
                    yield current_dataset, np.array(current_data, dtype=np.float64)
                    current_data = []
                current_dataset = dataset_match.group(1)
                continue
            
            # 匹配数据行(必须有三个数值)
            data_match = regex_data_line.match(line)
            if data_match and current_dataset is not None:
                # 提取并转换为浮点数
                values = [float(val.strip()) for val in data_match.groups()]
                current_data.append(values)
        
        # 处理文件末尾的最后一个数据集
        if current_dataset is not None and current_data:
            yield current_dataset, np.array(current_data, dtype=np.float64)

# 生成最终字典
dict_results = dict(parse_data_sets('file.txt'))

优化亮点:

  • 用生成器函数分离解析逻辑与字典构建,代码更易维护
  • 预编译正则表达式,避免循环中重复编译,提升匹配速度
  • 显式跳过空行与无关文本,减少无效判断
  • 修复了原代码中的所有语法与逻辑错误

方案2:用numpy批量加载,提升大文件处理效率

如果你的数据集很大,用numpy的genfromtxt批量读取数据,比逐行解析效率高很多:

import numpy as np
import re

def parse_data_sets_fast(file_path):
    dict_results = {}
    regex_dataset = re.compile(r'Data set # (\d+)')
    
    with open(file_path, 'r') as f:
        while True:
            line = f.readline()
            if not line:
                break  # 文件读取完毕
            
            line = line.strip()
            dataset_match = regex_dataset.match(line)
            if dataset_match:
                dataset_id = dataset_match.group(1)
                # 跳过表头、分隔线,定位到第一个数据行
                while True:
                    skip_line = f.readline()
                    if not skip_line:
                        break
                    # 尝试转换第一个值,判断是否是数据行
                    try:
                        float(skip_line.strip().split()[0])
                        # 把文件指针移回该行开头
                        f.seek(f.tell() - len(skip_line))
                        break
                    except (ValueError, IndexError):
                        continue
                
                # 批量加载数据,自动跳过注释行(//开头)
                data = np.genfromtxt(f, dtype=np.float64, comments='//', invalid_raise=False)
                # 过滤无效的NaN行,保证数据干净
                data = data[~np.isnan(data).any(axis=1)]
                if len(data) > 0:
                    dict_results[dataset_id] = data
    
    return dict_results

dict_results = parse_data_sets_fast('file.txt')

优化亮点:

  • 利用numpy的底层优化,批量读取数据,大幅提升大文件处理速度
  • 用文件指针精准定位数据起始位置,跳过无关内容
  • 自动识别并跳过//开头的注释行
  • 过滤无效行,确保存储的矩阵都是有效数值

方案3:极简版(适合结构固定的小文件)

如果你的文件结构非常固定,一次性读取整个文件再解析,代码会非常简洁:

import re
import numpy as np

with open('file.txt', 'r') as f:
    content = f.read()

# 匹配所有数据集:编号 + 后续的所有内容(直到下一个数据集或文件结束)
dataset_pattern = re.compile(r'Data set # (\d+).*?\n(.*?)(?=\nData set #|\Z)', re.DOTALL)
dict_results = {}

for match in dataset_pattern.finditer(content):
    dataset_id = match.group(1)
    data_lines = match.group(2).strip().split('\n')
    # 过滤非数据行,转换为浮点数矩阵
    data = []
    for line in data_lines:
        line = line.strip()
        # 跳过空行、注释、表头、分隔线
        if not line or line.startswith('//') or '[' in line or '~' in line:
            continue
        try:
            values = list(map(float, line.split()))
            if len(values) == 3:
                data.append(values)
        except ValueError:
            continue
    if data:
        dict_results[dataset_id] = np.array(data, dtype=np.float64)

优化亮点:

  • 一次性读取文件,减少IO操作次数
  • 用re.DOTALL模式匹配多行内容,一次性提取整个数据集
  • 代码极简,适合结构固定的小文件快速解析

内容的提问来源于stack exchange,提问作者PathFinder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 16:07:31