Python 实战 | 使用 Python 调用 DeepSeek API 处理表格数据

一、前言

有时候,会遇到一些单纯使用 Python 很难解决的问题。例如 从一批给定的企业名单(表格)中,根据企业的经营范围,找出涉农企业并标记“农业及相关产业标签”,例如农林牧渔业、食用农林牧渔产品加工与制造…… 这就是一个偏主观的任务,过去我们尝尝使用正则表达式匹配关键词的方式去处理,但是这种方法算不上完美。比方说,农产品的细分种类那么多,用关键词进行匹配,难免出现遗漏。况且经营范围还会出现一些逆向的表示(例如:不含苹果汁生产),使得处理结果与实际结果偏差更大。

但是大模型的出现和成熟让这种需求的处理变得更加轻松和可靠了。大模型就像是一个学识丰富且具备独立思考能力,又可以连续工作的机器人,如果使用 Python 调用大模型来解决这类问题,必然节省不少人力。本期笔者就向大家分享一个调用大模型解决上述问题的实操案例。

二、创建 DeepSeek API

以当下最火爆的 DeepSeek 为例,要调用大模型,需要先注册账号并创建 API key。

(1)注册 DeepSeek 账号

(2)实名认证

(3)充值

(4)创建 API key

图片

图片

图片

创建好的 key 需要立即复制 key,后续无法重新复制。如果忘记复制,删除创建的 key,然后重新创建即可。

三、编写提示词

使用 Python 调用大模型批量处理数据,本质上就是就是连续不断地问答(注意不是连续对话,连续对话每一次对话都需要加载上文,耗费的 Toke 数量较大),我们抛出问题,大模型给出答案。所以需要提前准备好能让 DeepSeek 给出正确答案的提示词。

提示词的编写还需要考虑大模型的特性,例如在 DeepSeek 官方网站和手机 APP 中使用 DeepSeek 大模型时,可以上传图片进行文字识别,也可以上传表格进行简单的数据处理,但是调用 API 时这些操作都不能实现。即提示词必须是纯文本,那么我们应该如何让大模型处理表格数据呢?我们可以把表格内容转换为 Python 中的字典格式即可,就像下面这样。

图片

图片

图片

这一步可以通过 Python 实现。同时,我们也可以限制 DeepSeek 回答内容的格式,使其返回可以被简单解析成表格的 JSON 格式(与 python 字典非常相似),通过阅读 DeepSeek API 接口文档,可以知道应该怎么做。详细做法见下图。

图片

综合以上信息,笔者的提示词如下。

图片

四、Token 计算与费用问题

图片

DeepSeek 每轮对话能接受的 Token 有限,也就是说我们不能一次性让它帮我们处理所有数据。从官方接口文档来看,推理模型R1 与通用模型V3 的上下文长度,都是 64K(实际为65792),最大输出长度也完全一样,都是 8K(实际为 8192)。我们每次传给 API 的提示词和数据的内容总和,加起来不能超过上述限制,否则 API 会立即报错,同时还需要考虑输出内容的长度限制,如果是一些少输入多输出的数据处理场景,还需要根据这一限制进一步减少输入的 Token 数量,也就是交由 API 处理的数据量。那么如何估算 Token 大小呢,DeepSeek 官方给出了估算的公式,如下图所示。

图片

至于费用问题,DeepSeek 的收费标准并不高,以推理模型 R1 来看,每一百万 Tokens 输入,(缓存命中情况下)仅收费 1 元,如果是优惠时段,还能享受 2.5 折价格,不过需要注意,输出内容部分的收费标准是输入内容的 4 倍,估算成本时需要考虑这一点。

五、案例代码(全流程)

1.拆分数据

笔者要处理的数据有近十万条,也就是从约十万家企业中找到涉农企业并标记对应的农业产业标签。由于不能一次性将所有数据传入 API,所以需要分批传入,也就是一次性传入不超过 Token 数量限制的数据条数,这样的话就需要提前估算每一行数据的 Token,确保每次传入 Token 不超标,同时也要考虑输出内容的 Token 限制。

💡

每次输入的 Token 并不是说越接近限额,性价比就越高。这其中有很多因素,首先,API 是以 Token 数额计费的,而不是调用次数;其次,一次性输入过多,会让 AI 的注意力无法集中,即便提示词中已经说明不允许遗漏数据,但实际处理时遗漏现象还是难免出现;再者,每次输入的数据量越多,AI 思考的时间也会越久;最后,由于 Token 的估算有误差问题,必须要保守一些。所以建议在输出 Token 不超标的情况下,每次输入的 Token 没必要直逼 64K 的限额,大约 20K - 30K 即可。

所以这里笔者先根据字符数量估算了每一行数据的 Token,相关代码如下。

import pandas as pd# 读取数据DATA= pd.read_csv('./原始数据/企业数据.csv', dtype=str).fillna('')# 清洗数据,剔除或替换特殊字符,避免影响后续步骤DATA= DATA.applymap(lambda x: x.replace('`', '‘').replace("'", '‘').replace('"', '“')\                       .replace('【', '(').replace('】', ')').replace('\n', '').replace('\r', '')\                        .replace('\t', ''))# 估算 Tokens 并形成一个字段DATA['Tokens'] = DATA.apply(lambda r: int(len(''.join(list(r.values)))*0.6), axis=1)DATA.head(5)

图片

随后根据估算的 Tokens,将全部数据拆分为若干个子数据,每个子数据都只包含可以被 API 一次性处理的数据量。笔者为了避免 AI 处理数据时出现遗漏,每次传入的数据量经过严格限制,不仅 Token 不能超过 20000,一次输入的数据量也被限制在了 50 以内。拆分数据的代码和拆分后的数据如下图所示。

def Get_index_Limit_Tokens(df, max_tokens=20000, max_qynum=50):    '''    输入一个数据 df,根据前面生成的 Tokens 字段,获取合适数量的    数据行数,需要满足两个条件,一是这些数据行对应的 Tokens    不超过参数 max_tokens 的值,二是数据行数不超过设定的最大值    max_qynum,两个条件同时满足。返回值则是选取的数据行的索引值列表    '''    # 确保传入的数据 df 的行索引不存在重复    index_list = list(df.index)    add_tokens = 0    target_index = []    qynum = 0    for ind in index_list:        qynum += 1        add_tokens += df['Tokens'][ind]        if add_tokens > max_tokens or qynum > max_qynum:            break        else:            target_index.append(ind)    if not target_index:        # 说明这一行的文本 Token 已经超过设置的值,那么只返回一行数据的索引即可        # 后续如果 Token 超标,也方便及时处理        Special_index = [index_list][0]        return Special_index    return target_index
# 初始化拆分后子数据的编号file_id = 0while not DATA.empty:    file_id += 1    # 获取子数据的索引    target_index = Get_index_Limit_Tokens(DATA, max_tokens=20000, max_qynum=50)    # 根据索引获取数据    df_one = DATA.loc[target_index, :]    # 保存获取的数据,存入一个提前创建的文件夹中    df_one.to_csv(f'./提前拆分的数据/{file_id}.csv', index=False)    # 将获取的数据从全部数据集中删除    DATA = DATA.drop(target_index)

图片

2.循环调用 DeepSeek API

数据提前拆分后就可以开始循环调用 API 来处理数据了。关于 API 的选用问题,是选择推理模型 R1 还是通用模型 V3,可以参考这篇文章:《AI 视界 | 推理模型和通用模型的区别究竟是什么?》 ,对于本文这种简单的判断问题,通用模型 V3 模型足以胜任,且思考时间更短,标准时段下的价格更低。如果希望只在优惠时段时才调用 API 那么可以编写 Python 函数,让循环只在规定时段内才会运行。

图片

至于如何调用 API,DeepSeek 官方给出了调用示范,我们只需按照步骤进行测试即可。

图片

接下来根据官方的演示代码稍加修改后进行循环调用即可,注意调用前需要先安装第三方库 openai。

import pandas as pdimport os,  time, globfrom openai import OpenAIclient = OpenAI(api_key='sk-bf9c867698e048a5844e3403acecf810', base_url="https://api.deepseek.com")# 获取拆分后的全部文件的路径files_paths = glob.glob('./提前拆分的数据/*.csv')# 根据文件序号排序,防止混乱files_paths.sort(key=lambda x: int(os.path.basename(x).split('.')[0]))DATA_paths = [path.replace('\\', '/') for path in files_paths]def is_time_in_range():    """    判断当前时间是否在 00:31 - 8:29 之间。    :return: 如果当前时间在范围内,返回 True;否则返回 False。    """    # 获取当前时间的小时和分钟    current_time = time.localtime()    current_hour = current_time.tm_hour    current_minute = current_time.tm_min
    # 将时间转换为分钟数进行比较    start_time_minutes = 0 * 60 + 30  # 00:31 转换为分钟数    end_time_minutes = 8 * 60 + 29    # 08:29 转换为分钟数    current_time_minutes = current_hour * 60 + current_minute  # 当前时间转换为分钟数    # 判断当前时间是否在范围内    if start_time_minutes <= current_time_minutes < end_time_minutes:        return True    else:        return False## 将多行数据合成一个字典,如果字典的值为空,则去除def Row_2_Dict(df:pd.DataFrame):    '''    将表格 df 转为字典格式的纯文本内容    '''    Target_dict = {}    # 刷新索引    df = df.reset_index(drop=True)    index_list = list(df.index)    for ind in index_list:        row_dict = df.loc[ind, :]        entname = row_dict.pop('企业名称')        del row_dict['Tokens']        row_dict = {k:v for k,v in row_dict.items() if str(v).strip() and k not in ('Tokens')}        # 将清洗后的字典存入 Target_dict        Target_dict[entname] = row_dict    return str(Target_dict)
# 提示词.txt 文件内存储的是提前编写好的命令提示词,里面不包含任何企业相关信息with open('./提示词.txt', 'r', encoding='utf-8') as TSC:    提示词 = TSC.read().strip()# 用于保存调用报错的文件Error_files = []for datapath in DATA_paths:    start = time.time()    # 等待优惠时段,如果可以接受开销增加,那么可以不用等待    while not is_time_in_range():        # 如果不在规定时段内,等待一分钟后重新进入循环        print(f'\r正在等待优惠时段', end='')        time.sleep(60)        continue    print(f'正在处理文件:{os.path.basename(datapath)}')
    df = pd.read_csv(datapath, dtype=str).fillna('')    ## 先获取企业信息    Company_Info = Row_2_Dict(df)    try:        # 使用 tyr-except 增加一定的容错,如果一次调用报错,不至于让循环彻底停止        messages = [{"role": "system", "content": 提示词},                    {"role": "user", "content": Company_Info}]        response = client.chat.completions.create(            # model="deepseek-reasoner",             model="deepseek-chat",            max_tokens=8100,            # response_format={'type': 'json_object'},            messages=messages        )        # 思考链文本,使用 R1 模型时才会有        # reasoning_content = response.choices[0].message.reasoning_content        # 获取返回的文本        content = response.choices[0].message.content        # 计算本次调用花费的秒数        # 保存刚刚返回的文本结果,保存在存放拆分后 csv 的文件夹中        with open(datapath.replace('.csv', '.txt'), 'w', encoding='utf-8') as f:            f.write(content)    except Exception as e:        # 如果调用时报错,记录报错的文件        Error_files.append(datapath)        print('返回报错了,稍微等一会儿……')        time.sleep(60)    usetimes = time.time() - start    print(f'本次调用完成, 用时: {usetimes} 秒')

保存后的返回结果如下图所示。

图片

3.解析返回结果,重新形成表格

# 获取报错的 txt 文件的路径TXT_files = glob.glob('./提前拆分的数据/*.txt')TXT_files.sort(key=lambda x: int(os.path.basename(x).split('.')[0]))# 逐一解析为表格def json_to_table(D, source='-'):    '''    将 API 返回的 json 文本解析为表格    '''    if len(D) == 0:        return pd.DataFrame(columns=['企业ID', '企业名称', '产业标签', '判断依据', '来源'])    table_values_list = []    for d in D:        table_values_list.append([d['企业ID'], d['企业名称'],d['产业标签'], d['判断依据'], source])    df = pd.DataFrame(table_values_list, columns=['企业ID', '企业名称', '产业标签', '判断依据', '来源'])    return df# 存放所有解析结果的列表dflist = []for txt in TXT_files:    with open(txt, 'r', encoding='utf-8') as f:        TEXT_JS = f.read().strip()    TEXT_JS = re.sub('`|json|\s+', '', TEXT_JS)    TEXT_JS = re.sub('^.{,10}(\[)', r'\1', TEXT_JS)    try:        JS = eval(TEXT_JS)        df = json_to_table(JS, txt)        dflist.append(df)    except:        print(f'文件 {txt} 无法被解析为表格')
# 合并所有解析结果并排序DATA_RESULT = pd.concat(dflist)DATA_RESULT['企业ID'] = DATA_RESULT['企业ID'].apply(int)DATA_RESULT = DATA_RESULT.sort_values(['企业ID']).reset_index(drop=True)# 保存为 excel 文件,如果结果太大,建议保存为 csv 文件DATA_RESULT.to_excel('./处理结果.xlsx', index=False)

图片

六、关于调用限速问题

这是一个很现实的问题,如果这个流程用来处理大量的数据,肯定希望调用速度越快越好。DeepSeek 官方文档明确说明:

图片

但是经过笔者实测发现,这里所说的不限速,并非完全不限速,同一个账号,无论创建了多少 key,同一时间都只能有一段进行中的对话。也就是说只有等一次调用完成了,才能进行下一次调用。

七、总结

本文向大家分享了一个如何使用 Python 调用 DeepSeek API 解决实际问题的案例,并向大家提供了详细的代码。值得一说的是,让大家更方便地理解代码,笔者简化了实际流程,去除了不少容错机制,大家在使用时,还请根据实际情况再做调整。最后希望这次分享对大家有所帮助。

### 调用 DeepSeek 功能的背景 DeepSeek 是一种先进的大语言模型技术栈,通常用于自然语言处理(NLP)、文本生成和其他机器学习任务。为了通过 Python 调用其接口或功能,开发者可以通过官方 API 或 SDK 实现交互[^1]。 以下是实现这一目标的具体方式: --- #### 安装依赖库 要调用 DeepSeek 的功能,首先需要安装必要的 Python 库。如果 DeepSeek 提供了一个专用的 Python SDK,则可以直接使用 pip 进行安装。例如: ```bash pip install deepseek-client ``` 如果没有专门的 SDK,可能需要借助 `requests` 或其他 HTTP 工具来发送 RESTful 请求。 --- #### 使用 RESTful 接口访问 DeepSeek 功能 假设 DeepSeek 支持 RESTful 风格的 RPC 协议,那么可以按照以下方式进行调用[^3]: 1. **构建请求 URL 和参数** 假设 DeepSeek 的服务部署在一个特定的服务器上,并提供了文档说明如何构造请求路径和数据结构。例如,URL 可能类似于: ``` https://api.deepseek.com/v1/generate_text ``` 2. **编写 Python 代码** 下面是一个简单的例子,展示如何通过 POST 方法向 DeepSeek 发送请求并获取响应: ```python import requests url = "https://api.deepseek.com/v1/generate_text" headers = { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY" # 替换为实际的API密钥 } payload = { "prompt": "Write a short story about a robot who dreams.", "max_tokens": 100, "temperature": 0.7 } response = requests.post(url, json=payload, headers=headers) if response.status_code == 200: result = response.json() print(result["text"]) # 输出生成的文本 else: print(f"Error: {response.status_code}, {response.text}") ``` 上述代码片段展示了如何设置请求头、传递 JSON 数据以及解析返回的结果。 --- #### 利用 Pandas 处理 DeepSeek 返回的数据 如果 DeepSeek 的输出是以表格形式呈现的大规模数据集,可以利用 pandas 来进一步分析这些数据。例如: ```python import pandas as pd # 将 DeepSeek 返回的 JSON 结果转换为 DataFrame data = [ {"id": 1, "content": "This is generated text."}, {"id": 2, "content": "Another piece of content."} ] df = pd.DataFrame(data) print(df.head()) ``` 这使得后续数据分析更加便捷高效。 --- #### 数据可视化增强洞察力 对于某些场景下,除了原始数据外还需要直观理解模式与趋势,此时可引入 Matplotlib 或 Seaborn 等工具完成绘图工作[^2]。比如绘制词频统计直方图: ```python import matplotlib.pyplot as plt word_counts = df['content'].str.split().apply(len) plt.hist(word_counts, bins=20) plt.title('Word Count Distribution') plt.xlabel('Number of Words') plt.ylabel('Frequency') plt.show() ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值