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

欺诈文本分类检测(十五)——数据校正与增强

1. 引言

基于前文构建训练/测试集构建的数据集,已经进行了多轮训练。但一直有一个数据层面的隐患在于,我们在给正向数据集所打的标签,并不是那么的准确。前面打标签的基本做法是:

  • 从正向数据集中分割出的对话,都打的是正向标签
  • 从反向数据集中分割出的对话,都打的是负向标签

后一类问题不大,但前一类其实是存在一些问题的,具体为:一个完整案例中带有欺诈时,并不见得从中分割出的子对话也带有欺诈。例如:

{"input": "李华: 您好,这里是电商平台的客服中心,请问您是张先生吗?\n张伟: 是的,我是张伟,请问有什么事吗?", "label": true, "fraud_speaker": "李华"}
{"input": "李华: 张先生,您最近在我平台上购买了一些商品对吧?我们这边检测到您的商品可能存在质量问题,为了保障您的权益,现在需要进行理赔退款。\n张伟: 哦,真的吗?那该怎么操作呢?", "label": true, "fraud_speaker": "李华"}
{"input": "李华: 我们需要您提供您的订单号和一些个人信息,以便我们核实您的身份并快速处理您的退款。\n张伟: 好的,我的订单号是1234567890,需要哪些个人信息?", "label": true, "fraud_speaker": "李华"}
{"input": "李华: 需要您的姓名、身份证号码以及银行卡号。请您放心,我们会严格保密您的信息。", "label": true, "fraud_speaker": "李华"}
{"input": "张伟: 我的姓名是张伟,身份证号码是123456789012345678,银行卡号是622202020202020202", "label": true, "fraud_speaker": "李华"}
{"input": "李华: 非常感谢您的配合。为了确保信用卡或银行卡安全,我们还需要您提供收到的验证码。\n张伟: 验证码是123456", "label": true, "fraud_speaker": "李华"}

上面这个拆分后的对话集,第一条是正常的对话,并没有经济欺诈; 第三条如果不考虑上下文,仅仅提供订单号,也构不成欺诈; 但是,我们按照所属对话集进行分类时,都打的欺诈标签(label=true)。

那怎么知道一个子对话中是否带有欺诈呢?能想到的只有两种办法:

  1. 人工阅读每个子对话,手动打标签。
  2. 让能力强的大模型,来分析对话内容,自动打上标签后,再让小模型去学习。

为了低成本快速落地,我们优先选择了第二种,等自动化手段用完后,如果还需要进一步提高,再考虑人工介入。

选择第二种还有一个好处是:可以让能力强的模型在打标签的同时,给出分析原因reason,这样就为reason的训练提供了素材。

2. 基础定义

先复用前面已经定义过的一些工具函数:

  • load_jsonl: 加载数据集
  • get_files: 获取一个目录下的文件列表
  • remove_markdown_boundary: 去掉markdown中的分隔符,gpt生成的json中,有时会带有markdown分隔符’```'。
  • print_json: 以结构化的形式打印数据
import os
import re
import json
from tqdm import *def load_jsonl(path):with open(path, 'r') as file:data = [json.loads(line) for line in file]return datadef get_files(directory, extension='.jsonl', excludes=[]):files = [f for f in os.listdir(directory) if f.endswith(extension) and f not in excludes]return filesdef remove_markdown_boundary(text):return re.sub(r'^```json\n(.*)\n```$', r'\1', text.strip(), flags=re.DOTALL)def print_json(obj):print(json.dumps(obj, indent=4, ensure_ascii=False))

查看待处理文件列表,这里我们只处理正向数据集,也就是带欺诈的数据集。

meeting_开头的数据集都属于反面数据集,为了尽可能降低成本,已经确定是非欺诈的数据就不再给GPT去检测了。

input_dir = "../dataset/fraud/jsonl_dialogs"
output_dir = "../dataset/fraud/jsonl_gpt"
exclude_files = ['meeting_label_false_train_100.jsonl', 'meeting_label_false_train_300.jsonl', 'meeting_label_false_train_500.jsonl']input_files = get_files(input_dir,  excludes = exclude_files)
input_files
['网络赌博诈骗(200)_train_100.jsonl','投资诈骗(200)_train_100.jsonl','微商代理诈骗(200)_train_100.jsonl',
……'网络贷款诈骗(162)_train_100.jsonl']

以第一个文件为例,查看原始数据格式。


dataset = load_jsonl(os.path.join(input_dir, input_files[0]))
dataset[10]
{'input': '大刚: 我真的没有办法了。我输了所有的钱,现在我的生意都没有了。\n小海: 你这样做太过分了!我要报警!\n大刚: 对不起,我真的对不起你。我愿意偿还你的损失,只是现在我已经身无分文,无能为力了。','label': True,'fraud_speaker': '大刚','instruction': '\n下面是一段对话文本, 请分析对话内容是否有诈骗风险,以json格式输出你的判断结果(is_fraud: true/false)。\n'}

3. 测试gpt能力

这一部分主要有两个目的:

  1. 调试提示词,测试模型的数据校正能力是否能达到预期;
  2. 对比gpt-4o-mini和gpt-4o两个模型的能力;
3.1 模型访问配置

使用Agently框架配置4o-mini模型调用实例。

选用Agently框架来访问GPT的原因在于:它不仅对常用的模型统一了使用方式,而且对提示词的编写作了高层次的抽象,大大简化了提示词的组织和编写难度。详细参考:https://www.agently.cn/licenses/zh-CN.html

import os
import Agently
agent_factory_mini = Agently.AgentFactory(is_debug=False)agent_factory_mini\.set_settings("current_model", "AzureOpenAI")\.set_settings("model.AzureOpenAI.auth", {"api_key": os.environ["OPENAI_API_KEY"],"api_version": "2024-05-01-preview","azure_endpoint": "https://openaiquanshi.openai.azure.com/openai/deployments/meeting-gpt4o-mini/chat/completions?api-version=2024-05-01-preview",})\.set_settings("model.OpenAI.options", { "model": "gpt-4o-mini" })
# Test
agent_mini = agent_factory_mini.create_agent()
print(f"agent_mini test: {agent_mini.instruct('你是谁?').start()}")
agent_mini test: 我是一个人工智能助手,旨在回答你的问题和提供帮助。如果你有任何问题或需要信息,请随时问我!

使用Agently框架配置gpt-4o模型调用实例。

import os
import Agently
agent_factory_4o = Agently.AgentFactory(is_debug=False)# Other settings are the same as chat mode above
agent_factory_4o\.set_settings("current_model", "AzureOpenAI")\.set_settings("model.AzureOpenAI.auth", {"api_key": os.environ["OPENAI_API_KEY"],"api_version": "2024-05-01-preview","azure_endpoint": "https://openaiquanshi.openai.azure.com/openai/deployments/meeting-gpt4o/chat/completions?api-version=2024-05-01-preview",})\.set_settings("model.OpenAI.options", { "model": "gpt-4o" })# Test
agent_4o = agent_factory_4o.create_agent()
print(f"agent_4o test: {agent_4o.instruct('你是谁?').start()}")
    agent_4o test: 我是一个由OpenAI开发的人工智能助手,可以回答问题、提供信息和协助解决各种任务。有什么需要我帮忙的吗?
3.2 提示词定义

定义进行欺诈文本分类的提示词,输入一段对话,尝试输出三项信息:

  1. 分析文本中是否存在欺诈
  2. 找出欺诈者姓名
  3. 给出分析原因
# 你是一个分析诈骗案例的专家,你的任务是分析{input}中的对话内容是否存在经济诈骗(is_fraud:<bool>),如果存在经济诈骗,请找出正在进行诈骗行为的发言者姓名(fraud_speaker:<str>),并给出你的分析理由(reason:<str>),最后以json格式输出。
prompt_template = '''
role: 你是一个分析诈骗案例的专家,你的任务是分析对话内容中是否存在经济诈骗。
input: ${input}
instruct:task: - 1. 分析{input}中的对话内容是否存在经济诈骗,并给出你的分析理由。- 2. 如果存在经济诈骗,请找出正在进行诈骗行为的发言者姓名。output language: ${language}
output:result:is_fraud:$type: boolean$desc: 关于{input}中是否存在明确的经济诈骗(true/false)。fraud_speaker:$type: str$desc: 仅当{is_fraud}=true 时找出的诈骗者姓名,如果未提及诈骗者姓名,请输出""。reason:$type: str$desc: 仅当{is_fraud}=true 时给出的理由。
'''

在上面这个提示词中,我们有几项细节要求:

  1. 如果未提及诈骗者姓名,请输出"":当诈骗者姓名未明确提及时,模型输出的结果是比较随意的,例如“相关的人”、“未提到”等,这会增加我们结果评测时的难度。明确要求模型输出空串则可以提高fraud_speaker字段值的一致性。
  2. 仅当{is_fraud}=true 时给出的理由。:这是为了与反向数据集保持一致,反向数据集没有走gpt检测也就没有给reason字段赋值,这条要求可以让所有反向数据集的reason字段都保持为空。
3.3 对比测试

定义预测函数,输入一段文本,输出分析结果。由于模型输出结果的不确定性,需要处理可能出现的json格式异常。

def predict(agent, text):response = agent.load_yaml_prompt(yaml = prompt_template,variables={"input": text,"language": 'chinese',}).start()# 如果遇到markdown格式的json,则尝试用上面封装的remove_markdown_boundary来二次处理.if isinstance(response, str):try:response = json.loads(remove_markdown_boundary(response))except json.JSONDecodeError:return {}# 确保response是一个字典return response.get('result', {}) if isinstance(response, dict) else {}

下面摘取了4个对话案例,其中:

  • 第一条虽然发言人是“欺诈者1”,但实际上是公安机关的反欺诈宣传。
  • 第二条带有欺诈内容,并且有具体的欺诈者姓名;
  • 第三条和第四条均是被骗者与民警的对话,未提及具体的欺诈者姓名;

我们通过这4个对话案例,来测试gpt-4o和gpt-4o-mini两个模型在欺诈文本分类上的表现。

inputs = ["欺诈者1: 如何举报非法传销举报非法传销行为时,应当尽可能了解掌握传销活动的详细线索,包括上课的具体地点、时间,传销头目、骨干和参与人员的住宿地点,非法传销活动的公司名称,其具体运作方式及书证、物证等,以便执法机关更加及时、准确、有效地打击传销行为。根据《禁止传销条例》第9条、第26条的规定,利用互联网等媒体发布含有传销信息的,以及为传销活动提供经营场所、培训场所、货源、保管、仓储等便利条件的,也是违法行为,也要受到查处。拨打:公安局110、市场监督管理局12315\n欺诈者1: 以上关于防范非法传销的知识点大家一定要记牢\n欺诈者1: 不信暴富神话 远离非法传销陷阱",'张华: 你好,我是某短视频平台上的投资理财导师张华,很高兴认识你。今天我们主要讲解一些基础的投资理财知识。\n闫某: 你好,张老师。我最近对投资理财很感兴趣,希望能够学习一些实用的知识。\n张华: 非常好,投资理财确实是一个非常好的方向,可以让你的财务更加自由。我们的课程会从基础到高级,系统地带你了解投资的各个方面。\n闫某: 听起来不错,那我需要怎么开始呢?\n张华: 你可以先购买我们的基础课程,只需要500元,就能获得全面的学习资料和视频教程。\n闫某: 好的,我会去购买课程。\n张华: 课程购买成功后,我们会有专人联系你,并给你提供一个专业的炒股软件,帮助你实操。这个软件是经过我们平台认证的,非常安全和可靠。','赖某: 我已经提交了很多个人资料,可是一直没有收到审批结果。可能是需要一些时间吧。\n民警: 赖某先生,我必须告诉你,你被骗了。这个项目是假的,没有任何国家扶贫项目可以通过网上投资获得高收益的。\n赖某: 什么!我怎么可能被骗?平台的人明明给了我那么多保证,我以为自己是个幸运儿。\n民警: 诈骗分子往往利用人们的贪欲和侥幸心理来进行欺骗,他们给你无限美好的承诺,让你以为自己是特殊的,然后骗走你的钱财。现实生活中诈骗无处不在,不要轻易相信一夜暴富的诱惑,只有脚踏实地,勤劳才能致富。','赖某: 民警同志,请问我可以办理营业执照吗?\n民警: 你为什么要办营业执照?有什么打算?\n赖某: 我看到了一则广告,说可以在网上办理营业执照,而且还有国家秘密扶贫项目。听起来很有吸引力。\n民警: 这个广告是在哪个平台上看到的?你是如何联系到相关平台的人员的?\n赖某: 我是在抖音短视频平台看到的广告,然后我搜了很多资料,在网上联系到了相关平台的人员。\n民警: 他们是怎么说服你的?你对他们的承诺有多大信心?\n赖某: 他们告诉我有个国家扶贫项目,只需要低投入就可以获得高收益,而且还说可以通过投资平台成为合伙人,享受分红。我对他们的承诺非常有信心。\n民警: 你提交个人资料后等了多久没有收到审批结果?',
]
for i, item in enumerate(inputs):print(f"data {i} predict result: ")print_json(predict(agent_mini, item))print_json(predict(agent_4o, item))
    data 0 predict result: {"is_fraud": false,"fraud_speaker": "","reason": "对话内容主要是在讨论如何举报和防范非法传销,没有涉及任何直接的经济诈骗行为或可疑的财务交易。"}{"is_fraud": false,"fraud_speaker": "","reason": ""}data 1 predict result: {"is_fraud": true,"fraud_speaker": "张华","reason": "张华以投资理财导师的身份推销收费课程,并承诺提供炒股软件,这种行为可疑且存在经济诈骗的风险。通常,正规投资理财课程不应通过隐性收费及不明软件诱导用户,因此此对话中存在诈骗嫌疑。"}{"is_fraud": true,"fraud_speaker": "张华","reason": "张华以'投资理财导师'的名义推荐用户购买课程并声称可以提供经过平台认证的炒股软件,但未提供详细信息,不具透明性,可能意图诱骗用户进行不明投资。"}data 2 predict result: {"is_fraud": true,"fraud_speaker": "平台的人","reason": "对话中提到的项目显然是一个骗局,民警明确指出该项目是假的,没有合法的扶贫项目会通过网上投资获得高收益。赖某被误导相信这个项目能带来高收益,说明存在利用人们的贪欲进行的经济诈骗行为。"}{"is_fraud": true,"fraud_speaker": "","reason": "赖某被指出受到了虚假的国家扶贫项目的诱骗,并且提交了个人资料但未收到预期结果,符合典型的投资诈骗特征。"}data 3 predict result: {"is_fraud": true,"fraud_speaker": "相关平台的人员","reason": "赖某所提到的国家秘密扶贫项目和低投入高收益的承诺具有欺骗性,这通常是典型的经济诈骗特征,尤其是在没有合法依据的情况下进行投资项目宣传和合伙人招募。"}{"is_fraud": true,"fraud_speaker": "","reason": "在对话内容中,赖某提到通过抖音短视频平台看到了一则广告,称可以通过低投入获得高收益,还涉及国家秘密扶贫项目,并且还可以成为投资平台的合伙人享受分红。这些信息极有可能是诈骗手段,利用高回报诱骗人投资,实际情况中这类项目通常为诈骗骗局。"}

从上面这个测试结果可以看到:

  • 数据1-反向案例:两个模型预测的标签分类一致,但mini未遵循指令额外输出了原因,而4o则按照指令保持原因为空。
  • 数据2-正向案例:两个模型输出一致
  • 数据3和数据4-正向案例:两个模型输出的标签一致,但对于fraud_speaker字段,mini未遵循指令输出了平台的人相关平台的人, 而4o则按照指令在未明确提及诈骗者姓名时输出为空。

通过上面这个结果分析,gpt-4o模型在遵循指令方面的能力要比4o-mini要强,为了确保数据集的质量,我们选择gpt-4o模型来进行接下来的数据分析和处理。

4. 生成预测结果

4.1 预测方法定义

定义方法来循环检测数据集中是否有欺诈行为,得到GPT对每条数据预测生成的标签、欺诈者、原因三个信息,其中有几个代码细节说明如下。

  • 当数据格式出现异常缺失字段时,将pred_label置为None,以便能区分出异常数据进行单独处理。
  • 得到结果后直接以json格式写入文件,保持一行一条数据。
  • progress_queue是一个队列,用于上报整体进度。
def run_predict(agent, dialogset, output_path, progress_queue=None):with open(output_path, 'a') as f:for i, item in enumerate(dialogset):dialog_input = item['input']prediction = predict(agent, dialog_input)item['pred_label'] = prediction.get('is_fraud', None)item['pred_speaker'] = prediction.get('fraud_speaker', '')item['reason'] = prediction.get('reason')f.write(json.dumps(item, ensure_ascii=False) + '\n')progress_queue.put(1) if progress_queue else None
4.2 主循环定义

测试数据集分割,用于多线程并行预测。

max_workers = 10
data_chunks = [list(dataset[i::max_workers]) for i in range(max_workers)]
len(dataset), len(data_chunks), len(data_chunks[0])
    (1190, 10, 119)

上面这个示例中,我们将1190条的数据集分隔为10份,第份119条数据。

定义主循环,使用ThreadPoolExecutor来调度多个线程,并行完成一个数据集中所有数据的标签预测。

  • 按文件分割数据集,每个分割后的子数据集作为一个单独的任务运行。
  • 用tqdm组件来定义进度条对象,其中total_count则表示总进度值,即总数据条数,子线程中每处理一条数据,就会更新一个进度值。
  • 定义progress_queue来收集子线程中的进度信息,收集到的数值更新到进度条pbar。
  • max_workers参数可以用来限制并发的线程数,此参数的取值取决于我们每分钟会消耗的token数以及GPT的限流阀值。
  • limit表示总共处理多少条数据,默认-1表示处理所有数据。
import queue
from concurrent.futures import ThreadPoolExecutor, ALL_COMPLETED
from queue import Queuedef run_predict_all(agent_factory, input_files, output_dir, max_workers=10, limit=-1):per_file_limit = limit//len(input_files) if limit >= len(input_files) else -1 data_chunks = [load_jsonl(f)[:per_file_limit] for f in input_files]output_files = [os.path.join(output_dir, os.path.basename(f)) for f in input_files]total_count = sum(len(chunk) for chunk in data_chunks)print(f"chunks: {len(data_chunks)}, total_count: {total_count}")pbar = tqdm(total=total_count, desc="total progress")# 创建一个队列来传递进度信息progress_queue = Queue()with ThreadPoolExecutor(max_workers=max_workers) as executor:futures = [executor.submit(run_predict, agent_factory.create_agent(), chunk, output_files[i], progress_queue) for i, chunk in enumerate(data_chunks)]# 在主线程中轮询队列来更新进度条while any(not f.done() for f in futures):try:# 尝试从队列中获取进度信息progress = progress_queue.get(timeout=10) # 使用get_nowait避免阻塞pbar.update(progress)except queue.Empty:print("No item available within the timeout period.")# 进度条使用完后,需要关闭。pbar.close()

注:使用多线程时需要注意的一点是,Agent实例并非多线程安全,所以每个任务都要单独创建一个Agent对象,否则会报一些状态错误。

4.3 运行预测

定义输出目录,开始运行。

output_dir = "../dataset/fraud/gpt_test"
exclude_files = ['meeting_label_false_train_100.jsonl', 'meeting_label_false_train_300.jsonl', 'meeting_label_false_train_500.jsonl']
files = get_files(input_dir, excludes=exclude_files)
input_files = [os.path.join(input_dir, f) for f in files]
run_predict_all(agent_factory_4o, input_files, output_dir, limit=-1)
    chunks: 36, total_count: 36total progress:   0%|          | 0/36 [00:00<?, ?it/s]total progress: 100%|██████████| 36/36 [00:49<00:00,  1.37s/it]

运行完后,在输出目录下就生成了与源文件同名的数据文件。

!ls -l ../dataset/fraud/jsonl_gpt
    total 49544-rw-r--r--  1 a200007  staff  1047047 Aug 21 01:14 “杀猪盘” 诈骗(200)_train_100.jsonl-rw-r--r--  1 a200007  staff   654512 Aug 21 01:46 “杀猪盘” 诈骗(200)_train_300.jsonl-rw-r--r--  1 a200007  staff   768424 Sep 14 16:18 “杀猪盘” 诈骗(200)_train_500.jsonl-rw-r--r--  1 a200007  staff   685348 Aug 21 00:47 二手交易诈骗(200)_train_100.jsonl-rw-r--r--  1 a200007  staff   456925 Aug 21 01:38 二手交易诈骗(200)_train_300.jsonl-rw-r--r--  1 a200007  staff   589504 Sep 14 16:18 二手交易诈骗(200)_train_500.jsonl-rw-r--r--  1 a200007  staff   444965 Aug 21 00:11 传销诈骗(140)_train_100.jsonl-rw-r--r--  1 a200007  staff   298311 Aug 21 01:31 传销诈骗(140)_train_300.jsonl-rw-r--r--  1 a200007  staff   437844 Sep 14 16:18 传销诈骗(140)_train_500.jsonl-rw-r--r--  1 a200007  staff   749744 Aug 21 00:52 兼职刷单诈骗(140)_train_100.jsonl-rw-r--r--  1 a200007  staff   437196 Aug 21 01:37 兼职刷单诈骗(140)_train_300.jsonl-rw-r--r--  1 a200007  staff   550339 Sep 14 16:18 兼职刷单诈骗(140)_train_500.jsonl-rw-r--r--  1 a200007  staff   810073 Sep 14 16:17 冒充客服诈骗(200)_train_100.jsonl-rw-r--r--  1 a200007  staff   567405 Aug 21 01:42 冒充客服诈骗(200)_train_300.jsonl-rw-r--r--  1 a200007  staff   506205 Sep 14 16:01 冒充客服诈骗(200)_train_500.jsonl-rw-r--r--  1 a200007  staff   895945 Sep 14 16:17 微商代理诈骗(200)_train_100.jsonl-rw-r--r--  1 a200007  staff   719013 Sep 14 16:18 微商代理诈骗(200)_train_300.jsonl-rw-r--r--  1 a200007  staff   496998 Aug 21 02:12 微商代理诈骗(200)_train_500.jsonl-rw-r--r--  1 a200007  staff  1027820 Sep 14 16:18 投资诈骗(200)_train_100.jsonl-rw-r--r--  1 a200007  staff   734102 Sep 14 16:18 投资诈骗(200)_train_300.jsonl-rw-r--r--  1 a200007  staff   504747 Aug 21 02:12 投资诈骗(200)_train_500.jsonl-rw-r--r--  1 a200007  staff   448207 Sep 14 16:18 短信诈骗(200)_train_100.jsonl-rw-r--r--  1 a200007  staff   569006 Sep 14 16:18 短信诈骗(200)_train_300.jsonl-rw-r--r--  1 a200007  staff   375027 Aug 21 02:17 短信诈骗(200)_train_500.jsonl-rw-r--r--  1 a200007  staff   787791 Aug 21 00:54 网络贷款诈骗(162)_train_100.jsonl-rw-r--r--  1 a200007  staff   609205 Sep 14 16:18 网络贷款诈骗(162)_train_300.jsonl-rw-r--r--  1 a200007  staff   591751 Sep 14 16:18 网络贷款诈骗(162)_train_500.jsonl-rw-r--r--  1 a200007  staff   873538 Sep 14 16:18 网络赌博诈骗(200)_train_100.jsonl-rw-r--r--  1 a200007  staff   623467 Sep 14 16:18 网络赌博诈骗(200)_train_300.jsonl-rw-r--r--  1 a200007  staff   425876 Aug 21 02:10 网络赌博诈骗(200)_train_500.jsonl-rw-r--r--  1 a200007  staff  1143246 Sep 14 16:18 虚假购物诈骗(200)_train_100.jsonl-rw-r--r--  1 a200007  staff   816140 Sep 14 16:18 虚假购物诈骗(200)_train_300.jsonl-rw-r--r--  1 a200007  staff   580752 Aug 21 02:14 虚假购物诈骗(200)_train_500.jsonl-rw-r--r--  1 a200007  staff   983876 Sep 14 16:18 虚拟货币诈骗(200)_train_100.jsonl-rw-r--r--  1 a200007  staff   704278 Sep 14 16:18 虚拟货币诈骗(200)_train_300.jsonl-rw-r--r--  1 a200007  staff   636393 Sep 14 16:18 虚拟货币诈骗(200)_train_500.jsonl

预览结果:

gpt_dataset = load_jsonl(os.path.join("../dataset/fraud/jsonl_gpt", files[0]))
gpt_dataset[0]
    {'input': '王丽: 您有6580积分即将到期,请立即登录积分商城兑换商品。\n王女士: 看起来是移动积分提醒,我赶紧看看能换什么。\n王丽: 点击这个链接可以进入积分商城,使用积分兑换各类商品。\n王女士: 这个夜光石英男表看起来还不错,用889积分和199元换购吧。\n王丽: 感谢您的兑换,商品将在一周内送达。\n王女士: 一周后,手表收到了,但质量很差啊。联系客服却没有人回应。\n赖洁: 您有6000积分即将到期,立即登录商城兑换商品吧,还有馈赠的爱奇艺会员哦。\n赖先生: 哦,又是积分兑换的信息,我用积分加200多元买一款手表吧。\n赖洁: 感谢您的购买,商品和爱奇艺会员会很快到账。','label': True,'fraud_speaker': '王丽','instruction': '\n下面是一段对话文本, 请分析对话内容是否有诈骗风险,以json格式输出你的判断结果(is_fraud: true/false)。\n','pred_label': True,'pred_speaker': '王丽','reason': '王丽通过积分兑换商品的方式,引导受害者支付现金购买商品,但所收到商品质量很差,且无法联系到客服,符合经济诈骗的特征。'}

可以看到,每条数据多了pred_label、pred_speaker、reason三个字段,是GPT生成的预测结果。

运行过程中可能会碰到超出限流阀值的情况,错误如下所示:

{'error': {'code': '429', 'message': 'Requests to the ChatCompletions_Create Operation under Azure OpenAI API version 2024-05-01-preview have exceeded token rate limit of your current OpenAI S0 pricing tier. Please retry after 2 seconds.

解法:出现这种情况可以尝试调低并行的worker数量,通过降低并行任务数来规避Token限流错误。

5. 数据校正

由于GPT的预测结果带有不确定性,因此上一步我们只是将GPT预测结果先保存起来,接下来会对GPT生成的结果质量进行分析,再决定是否能使用这些数据。

5.1 分析GPT的预测结果

定义几个方法:

  • load_jsonl_files: 用于加载一个目录下的所有数据集,支持extension参数按指定后缀过滤文件。
  • find_diff_data: 统计源数据集中与GPT预测标签不一致的数据条数。
  • find_failed_data: 找出所有GPT预测时出现异常的数据,例如:超时、触发限流、json格式非法等错误引起的部分数据预测失败。
def load_jsonl_files(directory, extension='.jsonl'):dataset = []for filename in os.listdir(directory):if filename.endswith(extension):file_path = os.path.join(directory, filename)with open(file_path, 'r', encoding='utf-8') as file:data = [json.loads(line) for line in file]dataset.extend(data)return datasetdef find_diff_data(dataset):label_diff_set = [item for item in dataset if item['label'] != item['pred_label'] and item['pred_label'] != None]speaker_diff_set = [item for item in dataset if item['label'] == item['pred_label'] and item['label'] == True and item['fraud_speaker'] != item['pred_speaker']]return label_diff_set, speaker_diff_setdef find_failed_data(dataset):label_none_set = [item for item in dataset if item['pred_label'] == None]return label_none_set
input_path_1 = "../dataset/fraud/jsonl_gpt"

查看GPT预测失败的数据条数。

label_none_set = find_failed_data(load_jsonl_files(input_path_1))
len(label_none_set), label_none_set[:2]
    (154,[{'input': '张华: 你好,我是张华,我是一家公司的高级投资顾问。我听说您对投资有兴趣,我想和您讨论一些机会。\n李明: 嗨,张华,请问你是如何得知我对投资感兴趣的?\n张华: 我们公司有涉及到投资方面的数据库,我们会根据用户的信息进行筛选,您的资料正好符合我们的目标客户。\n李明: 哦,这样啊。那你有什么具体的投资机会可以介绍给我吗?\n张华: 当然有了。我们现在有一个非常有潜力的项目,投资回报率非常高。如果你有兴趣,我可以详细介绍给你。\n李明: 听起来不错,请给我详细介绍一下吧。\n张华: 这个项目是关于地产投资的,我们可以帮助您投资一块地皮。这个地皮所在的地段非常好,未来发展潜力非常大。\n李明: 那具体是怎么投资的呢?','label': True,'fraud_speaker': '张华','instruction': '\n下面是一段对话文本, 请分析对话内容是否有诈骗风险,以json格式输出你的判断结果(is_fraud: true/false)。\n','pred_label': None,'pred_speaker': '','reason': None},{'input': '小明: 你好,我是中国医保局的工作人员,我需要核实一下您的个人信息。\n小红: 您好,有什么需要核实的吗?\n小明: 根据我们的系统显示,您名下的医保已停用,请进******申换电子版使用。\n小红: 真的吗?为什么会停用呢?\n小明: 我们发现您的医保卡存在安全隐患,为了保护您的个人信息,我们需要帮您更换为电子版。\n小红: 这么麻烦吗?我可以直接去办理吗?\n小明: 不可以,为了您的安全,我们只能通过短信链接帮您进行办理。\n小红: 嗯,好吧。那我点击链接后该怎么操作?\n小明: 点击链接后,您将进入我们的官方网页,按照网页上的提示填写身份证号、银行卡号、银行卡密码、预留手机号、验证码等信息。','label': True,'fraud_speaker': '小明','instruction': '\n下面是一段对话文本, 请分析对话内容是否有诈骗风险,以json格式输出你的判断结果(is_fraud: true/false)。\n','pred_label': None,'pred_speaker': '','reason': None}])

可以看到,有154条数据预测失败。

找出100长度的数据集中标签不一致的数据。

label_diff_set, speaker_diff_set = find_diff_data(load_jsonl_files(input_path_1, 'train_100.jsonl'))
len(label_diff_set), len(speaker_diff_set)
    (4404, 1423)

找出300长度的数据集中标签不一致的数据。

label_diff_set, speaker_diff_set = find_diff_data(load_jsonl_files(input_path_1, 'train_300.jsonl'))
len(label_diff_set), len(speaker_diff_set)
    (674, 623)

找出500长度的数据集中标签不一致的数据。

label_diff_set, speaker_diff_set = find_diff_data(load_jsonl_files(input_path_1, 'train_500.jsonl'))
len(label_diff_set), len(speaker_diff_set)
    (325, 485)

可以看到,标签不一致的数据加起来有5403条,并且对话长度越短,不一致的数据条数越多,随着上下文变长,不一致的数据条数在减少。

预览不一致的数据:

label_diff_set
[{'input': '葛亮: 哎呀,我最后再试一次。\n李明: 好,让我看一下……对不起,我的手机突然没电了。稍后再联系你。\n葛亮: 有什么问题吗?怎么联系不上你了?','label': True,'fraud_speaker': '李明','instruction': '\n下面是一段对话文本, 请分析对话内容是否有诈骗风险,以json格式输出你的判断结果(is_fraud: true/false)。\n','pred_label': False,'pred_speaker': '','reason': ''},{'input': '小张: 我联系“林妹妹”要求退款,但她说蜂蜜已经灌装了,不能退,只能给我发货。\n小张: 几天后,我收到快递,发现45瓶蜂蜜没有任何标签,是劣质蜂蜜,于是我报了警。','label': False,'fraud_speaker': '','instruction': '\n下面是一段对话文本, 请分析对话内容是否有诈骗风险,以json格式输出你的判断结果(is_fraud: true/false)。\n','pred_label': True,'pred_speaker': '林妹妹','reason': '小张联系了出售蜂蜜的“林妹妹”要求退款,但被拒绝并被发了劣质蜂蜜。劣质商品没有任何标签,且买家已经报警,表明了存在经济诈骗行为。“林妹妹”是发货者,涉嫌诈骗。'}]
5.2 校正不一致数据

不一致的数据主要有三类:

  1. 标签不一致
  2. 标签一致,但诈骗者姓名不一致
  3. GPT预测失败的数据

我们先按照条件分别筛选出来。

import pandas as pddf = pd.DataFrame(load_jsonl_files(input_path_1))
consistant_data = df[df['label'] == df['pred_label']]
inconsistant_data = df[(df['label'] != df['pred_label']) & (df['pred_label'].notna()) ]
label_none_data = df[df['pred_label'].isna()]

其中:

  • consistant_data:是标签一致的数据,包括了标签一致但speaker不一致的场景。
  • inconsistant_data:标签不一致的数据,子条件df['pred_label'].notna()是为了过滤掉预测失败的数据。
  • label_none_data:标签为None即GPT预测失败的数据。

标签不一致的数据处理

从前面数据的分析结果来看,标签不一致的数据量有5400多条。我们取了一些不一致的数据样本进行详细查看,发现GPT-4o的预测结果绝大部分都是正确的,所以这里的数据校正采用了比较简单的处理方式:不一致的数据均以GPT预测的结果为准,包括label和fraud_speaker,处理后的结果保存到一个单独的文件inconsistant_data.jsonl中。

inconsistant_data['label'] = inconsistant_data['pred_label']
inconsistant_data['fraud_speaker'] = inconsistant_data['pred_speaker']
inconsistant_data = inconsistant_data[inconsistant_data['input'] != ""]
inconsistant_data.to_json(f"{temp_dir}/inconsistant_data.jsonl", orient="records", lines=True, force_ascii=False)

注:运行过程中发现,原始数据中,有极个别的input是空的,所以这里有处理数据时额外使用条件inconsistant_data['input'] != ""将这类异常数据过滤掉。

标签一致的处理处理
标签一致的数据集中,可能有speaker不一致的情况,这里我们统一以GPT预测的speaker为准,用pred_speaker字段值覆盖掉原始的fraud_speaker。
处理后的数据保存到新的文件consistant_data.jsonl中。

temp_dir= "../dataset/fraud/temp"
consistant_data = consistant_data[consistant_data['input'] != ""]
consistant_data['fraud_speaker'] = consistant_data['pred_speaker']
consistant_data.to_json(f"{temp_dir}/consistant_data.jsonl", orient="records", lines=True, force_ascii=False)

预测失败的数据处理
对于GPT预测失败的数据,只需要重新走一次预测,并把结果保存到一个单独的文件label_none_data.jsonl中。

run_check(agent_4o, label_none_data.to_dict(orient="records"), f"{temp_dir}/label_none_data.jsonl")

经过上面的处理后,我们得到了以下三个经过标签校正的数据集文件:

  • label_none_data.jsonl
  • consistant_data.jsonl
  • inconsistant_data.jsonl

除此之外,还有前面未经GPT处理的反向数据集文件:

  • meeting_label_false_train_100.jsonl
  • meeting_label_false_train_300.jsonl
  • meeting_label_false_train_500.jsonl

上面6个文件就是所有数据集。

可以复用前文构建训练/测试集中的make_train_eval_test函数来切分出新的训练、验证、测试集,具体可以参考前文介绍,这里就不再示例。

小结:本文引入了GPT的能力来对数据集中的标签进行校正,并同时让GPT预测出了对话中的诈骗者姓名和分析理由。用这些数据集来训练模型,将有助于提高模型在实际场景中的预测准确率,同时我们也有了预测诈骗者姓名和分析理由所需要的数据集。

参考阅读

  • 欺诈文本分类检测(四):构建训练/测试集
  • 欺诈文本分类检测(二):生成正向数据集
  • 欺诈文本分类检测(三):生成反向数据集

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 分布式消息中间件kafka
  • 计算机毕业设计 美发管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 记一次docker打包部署历程
  • NoSql数据库Redis知识点
  • Python的串口通信库
  • 【学习笔记】手写Tomcat 四
  • 文件操作(3)
  • Python套接字
  • 植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
  • 一些线上常用排查问题的命令
  • 深度学习之概率论预备知识点(3)
  • CVE-2024-46103
  • 深度学习02-pytorch-08-自动微分模块
  • Qt/C++开发经验
  • vue2使用npm引入依赖(例如axios),报错Module parse failed: Unexpected token解决方案
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • [译]前端离线指南(上)
  • [译]如何构建服务器端web组件,为何要构建?
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • 03Go 类型总结
  •  D - 粉碎叛乱F - 其他起义
  • Docker 笔记(2):Dockerfile
  • ES6简单总结(搭配简单的讲解和小案例)
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Python十分钟制作属于你自己的个性logo
  • react-native 安卓真机环境搭建
  • SQLServer之创建显式事务
  • 工程优化暨babel升级小记
  • 关于Flux,Vuex,Redux的思考
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 讲清楚之javascript作用域
  • 人脸识别最新开发经验demo
  • 我的zsh配置, 2019最新方案
  • 赢得Docker挑战最佳实践
  • MyCAT水平分库
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • #QT项目实战(天气预报)
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (06)金属布线——为半导体注入生命的连接
  • (20)docke容器
  • (6) 深入探索Python-Pandas库的核心数据结构:DataFrame全面解析
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (二)Kafka离线安装 - Zookeeper下载及安装
  • (三)docker:Dockerfile构建容器运行jar包
  • (三)elasticsearch 源码之启动流程分析
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .naturalWidth 和naturalHeight属性,
  • .NET Core 通过 Ef Core 操作 Mysql