如何测试nltk资源是否已安装在运行我代码的机器上?

34 投票
3 回答
18246 浏览
提问于 2025-04-18 06:48

我刚开始我的第一个NLTK项目,对如何正确设置有点困惑。我需要一些资源,比如Punkt分词器和最大熵词性标注器。我自己是通过图形界面 nltk.download() 下载的这些资源。为了我的合作伙伴,我当然希望这些东西能自动下载。我在文档中没有找到相关的代码示例。

我是不是应该把 nltk.data.load('tokenizers/punkt/english.pickle') 这样的代码放到我的程序里?这样每次运行脚本时会不会都下载这些资源?我需要给用户(也就是我的共同开发者)反馈正在下载什么,以及为什么要花这么长时间吗?肯定有工具可以完成这个工作,对吧?:)

//编辑以澄清我的问题:
我该如何测试一个NLTK资源(比如Punkt分词器)是否已经安装在运行我代码的机器上,如果没有安装该如何进行安装?

3 个回答

2

我想分享一下我的看法,虽然有点晚了。

nltk有两个功能:download和downloader。

download()这个功能已经包含了检查包是否下载和是否是最新的逻辑:

from pathlib import Path
from nltk import download as nltk_download
from typing import List, Any
from nltk.downloader import Downloader
import logging

def download_nltk_data(
        list_of_resources: List[str],
        download_dir: Path,
) -> None:
    for resource in list_of_resources:
        nltk_download(
            info_or_id=resource,
            download_dir=download_dir,
            quiet=True, # Change this if you wanna suppress the message
        )

download_nltk_data(
    list_of_resources=[
        'stopwords',
        'punkt',
    ],
    download_dir=Path('./data/nltk/'),
)

输出:

[nltk_data] Downloading package stopwords to data\nltk...
[nltk_data]   Package stopwords is already up-to-date!
[nltk_data] Downloading package punkt to data\nltk...
[nltk_data]   Package punkt is already up-to-date!

如果你想要隐藏这些信息,只需要把quiet=True改一下就行。

如果你想对包有更细致的控制,可以使用Downloader类来扩展功能:

def check_package_exists(
    package_id: Any,
    download_dir: Path,
) -> bool:
    downloader = Downloader(download_dir=str(download_dir))
    return downloader.is_installed(package_id)

def download_nltk_data(
    list_of_resources: List[str],
    download_dir: Path,
) -> None:
    download_dir.mkdir(parents=True, exist_ok=True)
    downloader = Downloader(download_dir=str(download_dir))
    for resource in list_of_resources:
        if not check_package_exists(resource, download_dir):
            logging.debug(f'Downloading {resource} to {download_dir}')
            downloader.download(info_or_id=resource, quiet=True)
        else:
            logging.debug(f'{resource} already exists in {download_dir}')


download_nltk_data(
    list_of_resources=[
        'stopwords',
        'punkt',
    ],
    download_dir=Path('./data/nltk/'),
)

输出:

stopwords already exists in data\nltk
punkt already exists in data\nltk

或者类似的东西。

4

在Somnath的评论之后,我来分享一个使用try-except的解决方法示例。在这个例子中,我们要查找一个默认情况下不在nltk数据中的comtrans模块。

from nltk.corpus import comtrans
from nltk import download

try:
    words = comtrans.words('alignment-en-fr.txt')
except LookupError:
    print('resource not found. Downloading now...')
    download('comtrans')
    words = comtrans.words('alignment-en-fr.txt')
47

你可以使用 nltk.data.find() 这个函数,具体可以参考这个链接:https://github.com/nltk/nltk/blob/develop/nltk/data.py

>>> import nltk
>>> nltk.data.find('tokenizers/punkt.zip')
ZipFilePathPointer(u'/home/alvas/nltk_data/tokenizers/punkt.zip', u'')

当资源不可用时,你会看到这样的错误信息:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/nltk-3.0a3-py2.7.egg/nltk/data.py", line 615, in find
    raise LookupError(resource_not_found)
LookupError: 
**********************************************************************
  Resource u'punkt.zip' not found.  Please use the NLTK Downloader
  to obtain the resource:  >>> nltk.download()
  Searched in:
    - '/home/alvas/nltk_data'
    - '/usr/share/nltk_data'
    - '/usr/local/share/nltk_data'
    - '/usr/lib/nltk_data'
    - '/usr/local/lib/nltk_data'
**********************************************************************

你可能想要这样做,以确保你的合作伙伴也有这个包:

>>> try:
...     nltk.data.find('tokenizers/punkt')
... except LookupError:
...     nltk.download('punkt')
... 
[nltk_data] Downloading package punkt to /home/alvas/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
True

撰写回答