数据预处理中如何跳过连续分隔符?
问题:处理含不规则空格的ASCII数据集时出现NaN值及加载失败问题
背景
我正在清理一个存在不规则空格的ASCII数据集,示例如下:
dataset = [1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 2 1 1 1 1 1 1 1]
当前代码可以运行,但因为分隔符设为' ',会把单个空格识别为列分隔,导致提取的features出现大量NaN值:
features = [ nan nan nan nan 2 2 nan nan nan 1 nan nan nan nan 3 nan]
现有代码
import pandas as pd import torch from torch.utils.data import Dataset, DataLoader, random_split import numpy as np import os class SDataset(Dataset): def __init__(self, directory, delimiter=' '): self.data = [] self.labels = [] self.delimiter = delimiter # 遍历目录下所有文件 for filename in os.listdir(directory): if filename.endswith('.f16'): file_path = os.path.join(directory, filename) try: # 加载ASCII数据 df = pd.read_csv(file_path, delimiter=self.delimiter, header=None, engine='python') # 确保列数足够 if df.shape[1] >= 21: # 提取特征和标签 features = df.iloc[:, [12, 13]].values labels = df.iloc[:, 6].values self.data.append(features) self.labels.append(labels) else: print(f"文件 {filename} 列数不足。") except Exception as e: print(f"加载文件 {filename} 出错: {e}") if not self.data: raise ValueError("未找到有效数据。") # 堆叠特征 self.data = np.vstack(self.data) # 拼接标签 self.labels = np.concatenate(self.labels) def __len__(self): return len(self.labels) def __getitem__(self, idx): features = torch.tensor(self.data[idx], dtype=torch.float32) label = torch.tensor(self.labels[idx], dtype=torch.float32) return features, label # 加载目录下的.f16文件数据集 dataset_directory = "C:/.../.../.../.../..." dataset = SDataset(dataset_directory, delimiter=' ') # 定义拆分比例 train_size = int(0.7 * len(dataset)) # 70% 用于训练 test_size = len(dataset) - train_size # 剩余用于测试 # 拆分数据集 train_dataset, test_dataset = random_split(dataset, [train_size, test_size]) # 创建DataLoader train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True) test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False) # 训练循环 for batch_idx, (features, labels) in enumerate(train_loader): print(f"训练批次 {batch_idx+1}") print("特征:", features) print("标签:", labels) # 测试循环 for batch_idx, (features, labels) in enumerate(test_loader): print(f"测试批次 {batch_idx+1}") print("特征:", features) print("标签:", labels)
尝试的解决方法及报错
我尝试添加.strip()方法来移除空格,修改后的代码片段如下:
try: # 加载ASCII数据 df = pd.read_csv(file_path, delimiter=self.delimiter, header=None, engine='python') # 确保列数足够 if df.shape[1] >= 21: # 提取特征和标签 df = df.strip() features = df.iloc[:, [12, 13]].values labels = df.iloc[:, 6].values self.data.append(features) self.labels.append(labels) else: print(f"文件 {filename} 列数不足。")
但运行后出现以下错误:
Traceback (most recent call last): File "c:---.py", line 51, in <module> dataset = SDataset(dataset_directory, delimiter=' ') ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:---.py", line 34, in __init__ raise ValueError("No valid data found. Ensure files contain the correct number of columns.") ValueError: No valid data found. Ensure files contain the correct number of columns.
解决方案
问题出在两个核心点:
- 单个空格作为分隔符时,
pd.read_csv会将连续空格拆分为多个分隔符,生成大量空列,最终导致NaN值。 df.strip()是错误用法——DataFrame对象没有该方法,这会直接抛出异常,导致所有文件加载失败,触发No valid data found错误。
正确处理方式:
方法一:使用正则表达式作为分隔符
将分隔符设置为匹配任意数量的空白字符(空格、制表符等),即delimiter=r'\s+',这样pd.read_csv会自动将连续多个空格视为单个分隔符,不会生成空列。
修改读取数据的代码:
df = pd.read_csv(file_path, delimiter=r'\s+', header=None, engine='python')
注:必须指定engine='python',默认的c引擎不支持正则表达式分隔符。
方法二:先清理文件内容再加载
如果正则分隔符不生效,可以先读取文件内容,将每行的连续空格替换为单个空格,再用StringIO加载为DataFrame:
import io with open(file_path, 'r') as f: content = f.read() # 替换连续空格为单个空格,同时过滤空行 cleaned_content = '\n'.join([' '.join(line.split()) for line in content.splitlines() if line.strip()]) df = pd.read_csv(io.StringIO(cleaned_content), delimiter=' ', header=None)
移除错误的df.strip()调用
直接删除df = df.strip()这一行。若需要清理单元格内的空格,可使用df.apply(lambda x: x.str.strip() if x.dtype == 'object' else x),但在本场景下,使用正则分隔符后无需额外清理。
修改后的SDataset类初始化关键代码:
try: # 使用正则分隔符处理连续空格 df = pd.read_csv(file_path, delimiter=r'\s+', header=None, engine='python') # 确保列数足够 if df.shape[1] >= 21: # 提取特征和标签 features = df.iloc[:, [12, 13]].values labels = df.iloc[:, 6].values self.data.append(features) self.labels.append(labels) else: print(f"文件 {filename} 列数不足。") except Exception as e: print(f"加载文件 {filename} 出错: {e}")
这样就能正确加载数据,避免NaN值和加载失败的问题。
内容的提问来源于stack exchange,提问作者Daedalus
相关产品推荐
相关产品推荐

