You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

针对大规模乌尔都语新闻数据集:如何快速遍历pandas DataFrame指定列并完成NLTK分词以构建n-gram语言模型?

优化乌尔都语新闻语料分词与N-gram模型的性能与逻辑

一、核心性能优化:替换低效的For循环分词

你的核心问题是用纯Python循环遍历11万行数据分词,速度极慢。这里有几个层级的优化方案,从简单到进阶:

1. 用Pandas向量化操作替代循环

Pandas的apply方法内部做了底层优化,比手动range循环高效得多。可以直接对"News Text"列批量分词,再通过itertools.chain高效展平为一维tokens列表:

import pandas as pd
import nltk
from itertools import chain

# 读取并预处理数据
dataframe = pd.read_excel("urdu-news-dataset-1M.xlsx").drop(["Index"], axis=1)

# 批量分词:先转字符串避免空值报错,再对每行分词,最后展平结果
tokens = list(chain.from_iterable(
    dataframe["News Text"].astype(str).apply(nltk.word_tokenize)
))

itertools.chain.from_iterable比循环里的tokens+=更高效,它避免了列表重复扩容带来的性能损耗。

2. 并行加速分词(进阶)

如果数据量特别大,可以利用多核CPU并行处理分词任务。swifter库会自动判断最优的执行方式(向量化/并行),用起来非常省心:

import swifter

# 用swifter加速分词操作
token_series = dataframe["News Text"].astype(str).swifter.apply(nltk.word_tokenize)
tokens = list(chain.from_iterable(token_series))

安装swifter:pip install swifter

3. 换用乌尔都语专用分词器(可选)

NLTK的word_tokenize对乌尔都语的支持不算最优,你可以试试urduhack库的专用分词器,它针对乌尔都语的语法和字符做了优化,准确率和速度都会更好:

from urduhack import tokenization

# 乌尔都语专用分词函数
def urdu_tokenize(text):
    return tokenization.word_tokenize(text)

tokens = list(chain.from_iterable(
    dataframe["News Text"].astype(str).apply(urdu_tokenize)
))

安装urduhack:pip install urduhack(部分环境可能需要额外配置依赖)


二、修正N-gram模型的逻辑错误

你的示例输出出现了字符连续拼接的问题,这是因为代码里的预处理循环逻辑完全错误:把单个词拆成了字符处理。下面是修正后的完整逻辑:

修正后的完整代码

import pandas as pd
import nltk
from itertools import chain
from nltk.probability import FreqDist
from collections import defaultdict, Counter
import random

# ---------------------- 数据读取与分词优化 ----------------------
dataframe = pd.read_excel("urdu-news-dataset-1M.xlsx").drop(["Index"], axis=1)

# 批量分词并展平
tokens = list(chain.from_iterable(
    dataframe["News Text"].astype(str).apply(nltk.word_tokenize)
))

# ---------------------- 预处理:转小写、过滤标点 ----------------------
# 加入乌尔都语常用标点,可根据需求扩展
punctuations = {'.', '!', '?', ',', '،', '۔', ':', ';'}
processed_tokens = [
    token.lower() for token in tokens 
    if token not in punctuations and token.strip() != ""
]

# ---------------------- 生成N-gram ----------------------
unigram = processed_tokens
bigram = list(nltk.ngrams(processed_tokens, 2, pad_left=True, pad_right=True))
trigram = list(nltk.ngrams(processed_tokens, 3, pad_left=True, pad_right=True))
quadgram = list(nltk.ngrams(processed_tokens, 4, pad_left=True, pad_right=True))
quingram = list(nltk.ngrams(processed_tokens, 5, pad_left=True, pad_right=True))

# ---------------------- 计算频率与构建模型 ----------------------
frequency_bigram = FreqDist(bigram)
frequency_trigram = FreqDist(trigram)
frequency_quadgram = FreqDist(quadgram)
frequency_quingram = FreqDist(quingram)

bigram_model = defaultdict(Counter)
trigram_model = defaultdict(Counter)
quadgram_model = defaultdict(Counter)
quingram_model = defaultdict(Counter)

for i, j in frequency_bigram:
    if i is not None and j is not None:
        bigram_model[i][j] += frequency_bigram[(i,j)]

for i, j, k in frequency_trigram:
    if i is not None and j is not None and k is not None:
        trigram_model[(i,j)][k] += frequency_trigram[(i,j,k)]

for i, j, k, l in frequency_quadgram:
    if i is not None and j is not None and k is not None and l is not None:
        quadgram_model[(i,j,k)][l] += frequency_quadgram[(i,j,k,l)]

for i, j, k, l, m in quingram:
    if i is not None and j is not None and k is not None and l is not None and m is not None:
        quingram_model[(i,j,k,l)][m] += frequency_quingram[(i,j,k,l,m)]

# ---------------------- 文本生成函数 ----------------------
def predict_word(count):
    return random.choice(list(count.elements()))

# 注意输入应为完整的乌尔都语词,而非单个字符
input_words = ("ق", "ب") 
sentence = " ".join(input_words) # 用词间空格分隔,避免字符拼接

print("初始输入:", sentence)
print("生成过程:")
for _ in range(200):
    try:
        suffix = predict_word(trigram_model[input_words])
        sentence += " " + suffix
        print(sentence)
        input_words = (input_words[1], suffix)
    except KeyError:
        # 无匹配N-gram时随机选词继续
        suffix = random.choice(processed_tokens)
        sentence += " " + suffix
        input_words = (input_words[1], suffix)

print("\n最终生成的文章:")
print(sentence)

三、额外性能优化建议

  1. 分块处理大文件:如果Excel文件过大,可分块读取处理,避免内存溢出:
# 分块读取,每块10000行
chunk_iter = pd.read_excel("urdu-news-dataset-1M.xlsx", chunksize=10000)
tokens = []
for chunk in chunk_iter:
    chunk = chunk.drop(["Index"], axis=1)
    tokens.extend(chain.from_iterable(chunk["News Text"].astype(str).apply(nltk.word_tokenize)))
  1. 缓存分词结果:如果需要多次运行模型,可把分词结果保存为pickle文件,避免重复分词:
import pickle

# 保存分词结果
with open("urdu_tokens.pkl", "wb") as f:
    pickle.dump(processed_tokens, f)

# 读取缓存的分词结果
with open("urdu_tokens.pkl", "rb") as f:
    processed_tokens = pickle.load(f)
  1. 直接构建N-gram模型:如果不需要保存所有N-gram列表,可直接遍历分词结果构建模型,节省内存:
# 直接构建trigram模型,无需先生成trigram列表
trigram_model = defaultdict(Counter)
for i in range(len(processed_tokens)-2):
    trigram_key = (processed_tokens[i], processed_tokens[i+1])
    trigram_model[trigram_key][processed_tokens[i+2]] += 1

内容的提问来源于stack exchange,提问作者Huzaifa Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 13:02:36