如何从多个2000万行制表符分隔文件各采样2万行合并为Pandas DataFrame
嘿,这个需求我太熟悉了——直接加载2000万条记录的文件绝对会把内存撑爆,必须用高效的逐文件抽样策略才行。下面给你一套完整的实现方案,分步骤来:
核心思路
我们的目标是不加载整个文件,只抽取每个文件中的2万条随机记录,最后合并成一个DataFrame。主要有两种可靠的实现方式,你可以根据自己的内存情况选择:
方法一:先算总行数,跳过不需要的行
这种方法适合文件行数能快速计算的场景,效率很高:
步骤1:导入必要的库
import pandas as pd import os import random
步骤2:编写单个文件的抽样函数
这个函数会先统计文件的总行数,然后随机生成要跳过的行号,只读取我们需要的2万条:
def sample_large_tsv(file_path, sample_size=20000): # 统计文件总行数(减去表头行) with open(file_path, 'r', encoding='utf-8') as f: total_data_rows = sum(1 for _ in f) - 1 # 表头占1行,剩下的是数据行 # 生成需要跳过的行号:总行数 - 抽样数 = 要跳过的行数 # 注意:read_csv的skiprows是跳过的行索引(从0开始,0是表头),所以数据行是1到total_data_rows skip_indices = random.sample(range(1, total_data_rows + 1), total_data_rows - sample_size) # 读取文件,只保留抽样行 sampled_df = pd.read_csv( file_path, sep='\t', skiprows=skip_indices, low_memory=False # 关闭内存优化,避免大文件的类型推断警告 ) return sampled_df
步骤3:遍历文件夹并合并结果
# 替换成你的文件夹路径 target_folder = "/your/folder/path/with/tsv/files" sampled_dfs = [] # 遍历所有tsv文件 for file_name in os.listdir(target_folder): if file_name.lower().endswith(".tsv"): full_path = os.path.join(target_folder, file_name) print(f"正在处理文件: {file_name}") # 调用抽样函数 df = sample_large_tsv(full_path) sampled_dfs.append(df) # 合并所有抽样数据 final_combined_df = pd.concat(sampled_dfs, ignore_index=True) # 验证结果 print(f"合并完成!总记录数: {len(final_combined_df)}")
方法二:分块读取抽样(更适合超大型文件)
如果你的内存特别紧张,或者文件行数统计很慢,可以用分块读取的方式,每次读一部分数据并抽样,直到凑够2万条:
def sample_tsv_by_chunks(file_path, sample_size=20000, chunk_size=100000): sampled_chunks = [] collected = 0 # 分块读取文件 for chunk in pd.read_csv( file_path, sep='\t', chunksize=chunk_size, low_memory=False ): if collected >= sample_size: break # 计算当前块需要抽多少条 need = sample_size - collected # 从当前块中随机抽样 chunk_sample = chunk.sample(n=min(need, len(chunk)), random_state=42) sampled_chunks.append(chunk_sample) collected += len(chunk_sample) return pd.concat(sampled_chunks, ignore_index=True)
使用的时候只需要把步骤3里的sample_large_tsv换成这个函数就行。
关键注意事项
- 可复现性:如果需要每次抽样结果一致,给
random.sample或者chunk.sample加上random_state参数(比如random_state=42)。 - 内存优化:可以给
read_csv指定dtype参数,比如dtype={"user_id": "int32", "category": "category"},大幅减少内存占用。 - 编码问题:如果文件不是UTF-8编码,记得修改
encoding参数(比如encoding="gbk")。 - 表头一致性:确保所有文件的表头完全相同,否则合并时会出现列不匹配的问题。如果表头不一致,先统一表头再抽样。
内容的提问来源于stack exchange,提问作者modLmakur
相关产品推荐
相关产品推荐

