当前位置: 首页 > news >正文

用Python处理IEMOCAP情感标签:从原始TXT文件到可用的数据集(附完整代码)

用Python处理IEMOCAP情感标签:从原始TXT文件到可用的数据集(附完整代码)

第一次接触IEMOCAP数据集的研究者,往往会被其复杂的目录结构和分散的标注文件搞得晕头转向。这个包含12小时音频的多模态情感数据库,虽然质量极高,但原始数据就像一座迷宫——标注信息分散在多个Session文件夹的TXT文件中,情感标签使用缩写表示,还有各种需要特殊处理的异常情况。本文将带你用Python一步步解开这个谜团,把零散的标注信息转化为结构清晰的DataFrame,为后续的模型训练铺平道路。

1. IEMOCAP数据集结构解析

IEMOCAP数据集由5个会话(Session)组成,每个会话包含两位说话者(F/M)的即兴对话(impro)和剧本对话(script)。情感标注信息存储在EmoEvaluation文件夹的TXT文件中,而对应的音频片段则位于sentences/wav目录下。

典型的文件结构如下:

IEMOCAP/ ├── Session1/ │ ├── dialog/ │ │ ├── EmoEvaluation/ │ │ │ ├── Ses01F_impro01.txt │ │ │ └── ... │ ├── sentences/ │ │ ├── wav/ │ │ │ ├── Ses01F_impro01/ │ │ │ │ ├── Ses01F_impro01_F000.wav │ │ │ │ └── ... ├── Session2/ └── ...

每个TXT标注文件包含多行记录,格式示例:

[3.5000 - 4.5000] Ses01F_impro01_F000 neu [0.0, 0.0, 0.0, 0.0, 0.0]

其中各字段含义为:

  • 时间区间
  • 音频片段ID
  • 情感标签(缩写)
  • 其他评估数据(可忽略)

2. 构建自动化处理流程

2.1 递归查找所有标注文件

首先需要找到所有Session中的TXT标注文件。这里使用os.walk递归搜索:

import os import pandas as pd def find_all_txt_files(root_dir): """递归查找所有EmoEvaluation目录下的TXT文件""" txt_files = [] for session in [f"Session{i}" for i in range(1, 6)]: eval_dir = os.path.join(root_dir, session, "dialog", "EmoEvaluation") if not os.path.exists(eval_dir): continue for root, _, files in os.walk(eval_dir): for file in files: if file.endswith('.txt'): txt_files.append(os.path.join(root, file)) return txt_files

2.2 解析单个TXT文件内容

每个TXT文件包含多行标注记录,我们需要提取音频片段ID和对应的情感标签:

def parse_txt_file(txt_path): """解析单个TXT文件,返回(音频ID, 情感标签)列表""" records = [] with open(txt_path, 'r', encoding='utf-8') as f: for line in f: if line.startswith('['): # 有效数据行 parts = line.strip().split('\t') if len(parts) >= 3: audio_id = parts[1] emotion = parts[2] records.append((audio_id, emotion)) return records

2.3 构建完整音频路径

原始标注只包含片段ID,我们需要构建完整的音频文件路径:

def build_audio_path(audio_id, root_dir): """根据音频ID构建完整的wav文件路径""" session = f"Session{audio_id[3]}" # 从ID中提取Session号 base_name = audio_id.split('_')[0] + '_' + audio_id.split('_')[1] return os.path.join( root_dir, session, "sentences", "wav", base_name, f"{audio_id}.wav" )

3. 情感标签标准化处理

IEMOCAP包含9种基础情感标签,但研究中常用的是4类简化版本。我们需要实现两种映射方案:

3.1 九类情感映射

原始标签到数字编码的完整映射:

EMOTION_9_MAP = { 'ang': 0, # 愤怒 'hap': 1, # 快乐 'exc': 2, # 兴奋 'sad': 3, # 悲伤 'fru': 4, # 沮丧 'fea': 5, # 恐惧 'sur': 6, # 惊讶 'neu': 7, # 中性 'oth': 8, # 其他 'dis': 8, # 厌恶(归为其他) 'xxx': 8 # 未知(归为其他) }

3.2 四类情感映射

更常用的简化版本,将相似情感合并:

EMOTION_4_MAP = { 'ang': 0, # 愤怒 'hap': 1, # 快乐(包含exc) 'exc': 1, # 兴奋→快乐 'sad': 2, # 悲伤 'neu': 3, # 中性 # 其他情感设为None将被过滤 }

3.3 标签转换函数

实现灵活的标签转换函数,支持两种映射方案:

def convert_emotion_label(label, mode='4class'): """转换情感标签为数字编码""" if mode == '4class': mapping = EMOTION_4_MAP else: mapping = EMOTION_9_MAP return mapping.get(label, None) # 未知标签返回None

4. 构建结构化数据集

将所有组件整合,生成最终的DataFrame:

def build_iemocap_dataframe(root_dir, emotion_mode='4class'): """构建IEMOCAP数据集DataFrame""" all_records = [] # 查找并解析所有TXT文件 txt_files = find_all_txt_files(root_dir) for txt_file in txt_files: records = parse_txt_file(txt_file) for audio_id, emotion in records: # 转换情感标签 label = convert_emotion_label(emotion, emotion_mode) if label is None: # 过滤不支持的情感 continue # 构建完整音频路径 audio_path = build_audio_path(audio_id, root_dir) # 添加到结果集 all_records.append({ 'audio_id': audio_id, 'audio_path': audio_path, 'emotion': emotion, 'label': label }) return pd.DataFrame(all_records)

使用示例:

df = build_iemocap_dataframe('/path/to/IEMOCAP', emotion_mode='4class') print(f"数据集大小: {len(df)}") print(df.head())

5. 异常处理与实用技巧

5.1 常见问题解决方案

  1. 路径问题

    • Windows路径使用反斜杠,建议使用os.path.join构建路径
    • 确保数据集路径正确,各Session文件夹完整
  2. 版本兼容性

    • 推荐使用pandas 1.0+版本
    • 如果遇到编码问题,尝试指定encoding='utf-8'
  3. 缺失文件处理

    if not os.path.exists(audio_path): print(f"警告: 音频文件不存在 {audio_path}") continue

5.2 性能优化建议

对于大型处理任务:

  • 使用多进程加速文件解析:
    from multiprocessing import Pool with Pool(4) as p: # 使用4个进程 records = p.map(parse_txt_file, txt_files)
  • 将最终DataFrame保存为Parquet格式,节省空间并提高后续加载速度:
    df.to_parquet('iemocap_labels.parquet')

5.3 数据增强思路

获得基础数据集后,可以考虑:

  • 添加说话者性别信息(从文件名提取F/M)
  • 合并文本转录(如果有)
  • 添加音频时长信息(使用librosa获取)
import librosa def get_audio_duration(path): try: return librosa.get_duration(filename=path) except: return 0.0 df['duration'] = df['audio_path'].apply(get_audio_duration)

6. 完整代码整合

以下是整合所有功能的完整脚本:

import os import pandas as pd from multiprocessing import Pool import librosa # 常量定义 EMOTION_9_MAP = {...} # 如前文定义 EMOTION_4_MAP = {...} # 如前文定义 class IEMOCAPProcessor: def __init__(self, root_dir, emotion_mode='4class'): self.root_dir = root_dir self.emotion_mode = emotion_mode def process(self): txt_files = self.find_all_txt_files() with Pool(4) as p: records = p.map(self.process_single_file, txt_files) flat_records = [item for sublist in records for item in sublist] df = pd.DataFrame(flat_records) # 添加音频时长 df['duration'] = df['audio_path'].apply( lambda x: librosa.get_duration(filename=x) if os.path.exists(x) else 0.0 ) return df def find_all_txt_files(self): """查找所有TXT标注文件""" txt_files = [] for session in [f"Session{i}" for i in range(1, 6)]: eval_dir = os.path.join(self.root_dir, session, "dialog", "EmoEvaluation") if os.path.exists(eval_dir): for root, _, files in os.walk(eval_dir): for file in files: if file.endswith('.txt'): txt_files.append(os.path.join(root, file)) return txt_files def process_single_file(self, txt_path): """处理单个TXT文件""" records = [] with open(txt_path, 'r', encoding='utf-8') as f: for line in f: if line.startswith('['): parts = line.strip().split('\t') if len(parts) >= 3: audio_id = parts[1] emotion = parts[2] label = self.convert_emotion_label(emotion) if label is not None: audio_path = self.build_audio_path(audio_id) if os.path.exists(audio_path): records.append({ 'audio_id': audio_id, 'audio_path': audio_path, 'emotion': emotion, 'label': label }) return records def convert_emotion_label(self, label): """转换情感标签""" mapping = EMOTION_4_MAP if self.emotion_mode == '4class' else EMOTION_9_MAP return mapping.get(label, None) def build_audio_path(self, audio_id): """构建音频文件路径""" session = f"Session{audio_id[3]}" base_name = audio_id.split('_')[0] + '_' + audio_id.split('_')[1] return os.path.join( self.root_dir, session, "sentences", "wav", base_name, f"{audio_id}.wav" ) # 使用示例 if __name__ == '__main__': processor = IEMOCAPProcessor('/path/to/IEMOCAP', emotion_mode='4class') df = processor.process() df.to_csv('iemocap_4class.csv', index=False) print("数据集处理完成,保存为iemocap_4class.csv")

这个脚本采用了面向对象的设计,将主要功能封装在IEMOCAPProcessor类中,支持:

  • 多进程加速处理
  • 两种情感分类模式
  • 自动验证音频文件存在性
  • 添加音频时长信息
  • 结果导出为CSV

7. 后续应用建议

获得结构化数据集后,可以方便地用于各种深度学习框架。例如PyTorch数据加载示例:

from torch.utils.data import Dataset import torchaudio class IEMOCAPDataset(Dataset): def __init__(self, csv_path, transform=None): self.df = pd.read_csv(csv_path) self.transform = transform def __len__(self): return len(self.df) def __getitem__(self, idx): row = self.df.iloc[idx] waveform, sr = torchaudio.load(row['audio_path']) if self.transform: waveform = self.transform(waveform) return waveform, row['label']

对于实际项目,还需要考虑:

  • 音频预处理(降噪、归一化)
  • 特征提取(MFCC、Mel频谱等)
  • 数据平衡(某些情感样本可能较少)
  • 数据分割(训练/验证/测试集)
http://www.jsqmd.com/news/683196/

相关文章:

  • 告别龟速诊断:手把手教你用DoIP和以太网线,把车辆刷写速度提升300倍
  • 2026康复医院设计哪家好?专业设计机构选择参考 - 品牌排行榜
  • 2025最权威的AI写作方案推荐榜单
  • 2026口碑最佳100吋电视横评:5款企业实力单品精准解析 - 十大品牌榜
  • 深入剖析Java Stream中Collectors.toMap的Duplicate key陷阱与实战规避策略
  • 互联网大厂 Java 求职面试实录:从 Spring Boot 到微服务探讨
  • WindowResizer终极指南:如何强制调整Windows窗口大小,突破软件限制
  • 性价比高的防晒霜推荐!Leeyo防晒霜真的是我怕晒黑人的天菜~ - 全网最美
  • 从MATLAB仿真到硬件在环:LFM线性调频信号在FMCW雷达设计中的实战指南
  • Aurora 8b/10b回环测试上板避坑指南:从单板自环到双板光口互联的完整流程
  • 别再死记硬背API了!用Agora RTC SDK手把手教你从零搭建一个1v1视频通话Demo(Web版)
  • SAP MIRO批量发票校验后,应付科目行项目金额怎么按暂估比例拆分?一个FMRESERV增强实例
  • 别再死磕3D扫描了!用Python+ResNet101从单张照片生成你的3D人脸模型(附完整代码)
  • 不止于仿真:深入Xilinx Ultrascale SelectIO,剖析IDDRE1/ODDRE1在真实LVDS项目中的配置与调试
  • 互联网大厂 Java 求职者面试:构建微服务与数据库架构
  • Figma中文插件:5分钟实现专业级界面汉化
  • 当UFS命令卡住时:深入Task Management UPIU,看Abort Task与Logical Unit Reset如何工作
  • 021、智能体框架实战:用LangChain构建第一个Agent
  • 从Metasploitable2靶场实战出发:一次完整的Telnet漏洞利用与权限提升复盘
  • 终极指南:5分钟掌握fre:ac免费音频转换器的完整使用技巧
  • Linux RT 调度器的 migrate_task_rq:RT 任务的跨 CPU 迁移
  • 别再只调参了!深入理解PyTorch CNN中Conv2d的stride和padding计算(以CIFAR-10为例)
  • 互联网大厂 Java 求职者面试:技术要点与幽默答辩
  • LangGraph构建AI代理:动态路由与状态管理实践
  • 轻量级大模型量化不是“除以127”就完事!:嵌入式C中int8_t张量对齐、饱和截断、零点偏移的6处隐蔽陷阱
  • 终极指南:3分钟掌握NCM格式解密,释放你的网易云音乐自由
  • Linux内核调度器如何利用MPIDR_EL1寄存器优化多核性能(以Arm64为例)
  • 用Qt 5.14.2 + EMQX搭建本地物联网消息测试环境:从客户端到服务器一条龙配置
  • League Akari:英雄联盟玩家的终极本地化工具箱,全面解决游戏效率与数据安全难题 [特殊字符]
  • ComfyUI-Impact-Pack V8架构深度解析:5大创新如何重塑AI图像处理工作流