新服务器运行django站点

远程登录服务器

1
2
3
4
sudo ssh root@user_name
#删除 原来的ssh密钥命令
ssh-keygen -f "/home/shimmer/.ssh/known_hosts" -R "117.72.9.46"

延长服务器ssh超时自动断开时间,此处为30分钟

1
2
3
4
5
#默认情况下,SSH 配置文件位于 /etc/ssh/sshd_config。
ClientAliveInterval 1800
ClientAliveCountMax 3
#设置完成后,保存文件并重新启动 SSH 服务器:
sudo service ssh restart

建议安装FTP软件代替scp命令,本处使用FileZilla

首先更新服务器的软件

1
2
3
#用户为root用户
apt update
apt upgrade

升级python版本,安装pip

1
2
apt install python3
apt install python3-pip

我的服务器上,上一步的环境没解决好,有问题,pip不能切换,使用conda创建虚拟环境

  1. 下载 Miniconda 安装脚本:

    在终端中执行以下命令,从 Miniconda 的官方网站下载适用于你的操作系统的安装脚本。你可以选择适用于 Python 3.x 的版本。

    1
    wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
  2. 运行安装脚本:

    在终端中执行以下命令,运行下载的安装脚本(请注意,文件名可能会因下载的版本而有所不同):

    1
    bash Miniconda3-latest-Linux-x86_64.sh
  3. 按照安装向导完成安装:

    按照安装向导的提示进行安装。ctrl + c跳过解释,通常情况下,选择默认选项即可。

  4. 启动一个新的终端窗口:

    安装完成后,你需要启动一个新的终端窗口,以使新的 Conda 环境变量生效。

  5. 测试 Conda 安装:

    在终端中运行以下命令,检查 Conda 是否正确安装:

    1
    conda --version

    如果显示了 Conda 的版本信息,则表示安装成功。

现在,你可以使用 Conda 创建虚拟环境、安装软件包等。使用以下命令来创建一个名为 “myenv” 的虚拟环境:

1
conda create -n myenv python=3.8

然后激活这个环境:

1
conda activate myenv

在激活的环境中,你可以使用 Conda 安装所需的软件包,管理依赖项等。当你完成项目后,可以使用以下命令退出虚拟环境:

1
conda deactivate

安装requirements.txt库

1
2
3
pip install -r requirements.txt
#注意安装mysqlclient时需要先安装mysqlclient的开发库
apt-get install libmysqlclient-dev

上传并解压文件(推荐上传压缩包替代文件夹),

1
unzip MyBlog.zip

pip换国内源

1
2
3
4
5
6
mkdir ~/.pip
nano ~/.pip/pip.conf
--------------------------
#pip.conf文件输入以下内容,换为清华源
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple

安装数据库,此处为MySql

1
apt install mysql-server

为mysql root用户设置密码

  1. 登录到 MySQL 服务器: 打开终端并使用以下命令登录到 MySQL 服务器。你将需要输入安装过程中设置的 MySQL root 用户密码。

    1
    mysql -u root -p

    如果成功登录,你将进入 MySQL 命令行界面。

  2. 设置 root 用户密码: 在 MySQL 命令行中,使用以下命令来设置 root 用户的密码。将 new_password 替换为你想要设置的实际密码。

    1
    ALTER USER 'root'@'localhost' IDENTIFIED WITH 'mysql_native_password' BY 'new_password';

    替换 'new_password' 为你要设置的实际密码。

  3. 刷新权限: 在设置密码后,需要刷新权限以确保更改生效。

    1
    FLUSH PRIVILEGES;
  4. 退出 MySQL 命令行: 输入以下命令退出 MySQL 命令行界面。

    1
    exit

    运行django程序

  • mysql建立相应的数据库

  • 使用迁移命令建立相应的表

    1
    2
    python3 manage.py makemigrations
    python3 manage.py migrate

    开启防火墙

1
2
3
4
#在配置nginx前,开启防火墙,不然下次可能无法通过ssh访问服务器
apt install ufw
ufw enable
ufw allow 22/tcp

安装nginx

1
apt install nginx

配置nginx文件

1
nano /etc/nginx/sites-available/default
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server {
charset utf-8;
listen 80;
server_name 117.72.9.46.;

location /static {
alias /MyBlog/static;
}

location /media {
alias /MyBlog/media;
}

location / {
proxy_set_header Host $host;
proxy_pass http://unix:/tmp/117.72.9.46.socket;
}
}


1
service nginx reload

apt换源

  1. 备份当前sources.list文件:
1
cp /etc/apt/sources.list /etc/apt/sources.list.bak
  1. 编辑sources.list文件:
1
nano /etc/apt/sources.list
  1. 注释掉原有的源,加入新的软件源:
1
2
3
4
deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse

收集静态文件

1
2
# 静态文件收集目录
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
1
python3 manage.py collectstatic

运行gunicorn

1
gunicorn --bind unix:/tmp/117.72.9.46.socket MyBlog.wsgi:application

gunicorn –bind unix:/tmp/117.72.9.46.socket –log-file /logfile.log MyBlog.wsgi:application

使用nginx获取真实ip

1
2
3
4
5
6
7
8
9
10
11
12
#如果你使用了Nginx作为反向代理服务器,并且在Nginx配置中有一些代理相关的设置,那么在Django中通过#self.request.META.get('REMOTE_ADDR')获取到的IP地址可能会不准确,甚至为空。这是因为Nginx会将用户的真实IP地址放在特定的#HTTP头中,而不是直接传递给Django。

#在这种情况下,你可以通过访问特定的HTTP头来获取用户的真实IP地址。默认情况下,Nginx将用户的真实IP地址存储在X-Real-IP头中。以下##是如何在Django中获取用户真实IP地址的示例代码:

user_ip = self.request.META.get('HTTP_X_REAL_IP') # 获取真实IP地址
if user_ip:
url = f"http://ip-api.com/json/{user_ip}?lang=zh-CN"
response = requests.get(url)
data = response.json()
print("国家:", data['country'])
location_info = data['country']


当然你也可以不安装nginx、gunicorn等服务,直接部署项目

  1. 开启防火墙,配置服务器防火墙规则:

确保服务器的防火墙允许来自外部网络的连接到达你选择的Django运行端口

1
2
3
4
5
6
#查看防火墙状态
ufw status
#开启django运行的端口
ufw allow 8000/tcp
#重新加载防火墙规则
ufw reload

2.启动Django应用:

1
2
#切记运行接口是(0.0.0.0),而不仅仅是本地接口127.0.0.1
python manage.py runserver 0.0.0.0:8000

3.访问django程序

1
浏览器访问    公网IP:8000
  

python GIL

CPython 中的 GIL:影响与应对方法

Python 官方文档


global interpreter lock:
The mechanism used by the CPython interpreter to assure that only one thread executes Python bytecode at a time. This simplifies the CPython implementation by making the object model (including critical built-in types such as dict) implicitly safe against concurrent access. Locking the entire interpreter makes it easier for the interpreter to be multi-threaded, at the expense of much of the parallelism afforded by multi-processor machines.

However, some extension modules, either standard or third-party, are designed so as to release the GIL when doing computationally intensive tasks such as compression or hashing. Also, the GIL is always released when doing I/O.

Past efforts to create a “free-threaded” interpreter (one which locks shared data at a much finer granularity) have not been successful because performance suffered in the common single-processor case. It is believed that overcoming this performance issue would make the implementation much more complicated and therefore costlier to maintain.


全局解释程序锁:
全局解释程序锁(GIL)是 CPython 解释器的一个特性,确保一次只有一个线程可以执行 Python 字节码。GIL 的存在简化了 CPython 的实现,通过隐式地为对象模型提供并发访问安全性,甚至包括关键的内置类型,如字典。虽然全局解释程序锁会限制多线程环境中并行执行的能力,但通过将同步复杂性集中到解释器级别,它使得解释器更容易支持多线程。然而,这也导致多核处理器提供的并行性大部分被消耗。
不过,一些扩展模块(无论是标准的还是第三方的)被设计为在执行计算密集型任务(如压缩或散列)时会释放 GIL。此外,在执行 I/O 操作时,GIL 总是会被释放。
过去创建“自由线程”解释器(以更细的粒度锁定共享数据的解释器)的努力没有成功,因为在常见的单处理器情况下性能受到影响。据信,克服该性能问题将使实现复杂得多,并且因此维护成本更高。


不同 Python 解释器的特点及 GIL 影响

Python 生态系统中有多种 Python 解释器实现,每个实现都有其独特的特点:

  • CPython:作为 Python 的标准解释器,使用 C 语言开发,对 Python 语言特性的支持最全面,广泛被使用。
  • Jython:基于 Java 开发,能够将 Python 代码编译为 Java 字节码,运行在 JVM 上,且可以调用 Java 库。
  • IronPython:使用 C# 开发,运行在 .NET 平台上,可以调用 C# 库和 .NET 框架。
  • PyPy:使用 Python 开发,通过 JIT 技术提高执行效率,与 CPython 兼容性较好。
  • Cython:并非独立的解释器,而是一种能够将 Python 扩展为可编译成 C 语言的语法扩展,可以生成 C 语言代码以提高效率,需要编译后才能在 CPython 中使用。
  • 还有其他实现如 Stackless Python、MicroPython 等。
  • CPython 作为使用 C 语言开发的标准解释器,存在全局解释器锁(GIL)的问题,从而导致多线程无法充分利用多核 CPU。

  • Jython 和 IronPython:由于基于 Java 和 .NET 运行时,不存在 GIL 问题,可以在多核 CPU 上充分发挥优势。

  • PyPy:虽然 PyPy 也有 GIL,但其使用 JIT 编译技术,部分优化了 GIL 带来的问题。

  • Cython:Cython 本身并非独立的解释器,但它可以通过编译成 C 语言的扩展来提高 Python 解释器的效率,不受 GIL 影响。


为什么 CPython 中存在 GIL?

CPython 中存在全局解释器锁(GIL)的主要原因是其历史和设计初衷。

历史背景: Python 最初在单核 CPU 时代诞生,其设计初衷并未考虑多线程并发执行的场景。在此背景下,设计师并没有着重解决多线程竞争问题。

引用计数内存管理机制: CPython 主要使用引用计数内存管理机制。然而,这种机制并不是线程安全的。具体而言,引用计数机制在多线程环境中容易出现问题,多个线程同时对对象引用计数进行增减操作可能引发竞争条件和线程安全问题。

为了避免这些问题,CPython 在执行 Python 字节码时引入了 GIL。这个机制确保同一时刻只有一个线程可以执行 Python 字节码,从而简化了内存管理。然而,这也限制了在多核 CPU 下实现真正的并发执行。

尽管 GIL 在某些情况下降低了多线程编程的便利性,但它在某些方面也有好处,例如在 I/O 密集型任务中释放 GIL,允许其他线程执行。

CPython 使用 C 扩展库: CPython 广泛使用 C 语言扩展库来提升性能。在多线程环境下,C 扩展库需要自己实现线程同步,这可能增加复杂性和错误的可能性。

降低 GIL 影响的方法:

降低 GIL 影响的策略包括但不限于以下方法:

  1. 利用多进程充分利用多核 CPU,从而避免 GIL 的限制。
  2. 使用异步编程来优化 I/O 密集型应用的并发性。
  3. 使用 C 扩展库或 Cython 优化计算密集型代码的执行效率。
  4. 利用 multiprocessing 模块提供的进程池实现多进程并发。
  5. 考虑使用无 GIL 的解释器,如 Jython、IronPython。
  6. 使用并行计算框架如 Dask、Joblib 支持并行计算。
  7. 优化算法和数据结构以减少竞争锁的使用。
  8. 分离计算密集型代码和 I/O 操作,充分利用 GIL 的释放。
  9. 对于 I/O 密集型任务,使用多线程优化而非计算密集型任务。
  10. 合理设置线程数量,避免过多线程竞争。
  11. 使用原生线程或 asyncio 等作为并发手段。
  12. 在适当的情况下使用共享内存和消息传递,减少锁的竞争。
  

小白的nginx指南

Nginx 是一个高性能的开源web和反向代理服务器,也可以用作电子邮件(IMAP/POP3)代理服务器。它的主要特点包括占用资源少、并发性高、可扩展性强以及对高负载环境的稳定性。

  1. 高性能

    • 事件驱动:Nginx 使用事件驱动架构,能够高效地处理大量并发连接,而不会消耗过多的内存或CPU资源。
    • 非阻塞:Nginx 是非阻塞式的,允许它同时处理多个请求,而不会等待一个请求完成后再处理下一个。
  2. 低资源消耗

    • 内存效率:Nginx 的内存占用非常低,适合在有限的硬件资源上运行。
    • CPU效率:由于事件驱动和非阻塞特性,Nginx 使用 CPU 的效率非常高,即使在高负载下也能保持稳定。
  3. 高并发性

    • Nginx 可以同时处理成千上万个并发连接,这对于高流量和高并发的网站非常重要。
  4. 反向代理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    反向代理服务器(Reverse Proxy Server)是一种位于网络服务器和客户端之间的中间服务器,是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。与正向代理服务器不同,反向代理服务器的作用是隐藏真实的后端服务器,使客户端不直接与后端服务器通信。客户端是不知道真正的目标服务器是谁的,甚至不知道自己访问的是一个代理。  

    正向代理服务器(Forward Proxy Server)是一种位于客户端和目标服务器之间的中间服务器,其主要作用是代表客户端向目标服务器发送请求,并将获得的内容返回给客户端。客户端通过正向代理服务器来访问互联网上的资源,而不是直接连接目标服务器。正向代理服务器在客户端和目标服务器之间充当了中介的角色,隐藏了客户端的真实IP地址和身份。
    应用场景:
    访问受限资源:正向代理服务器可以用于绕过网络访问限制。例如,如果某些网站被屏蔽或受到地理位置限制,用户可以通过连接到位于允许访问的国家/地区的正向代理服务器来访问这些资源。

    保护客户端隐私:正向代理服务器可以隐藏客户端的真实IP地址,增强了用户的隐私和匿名性。

    内容过滤和安全性:正向代理服务器可以用于过滤恶意流量、病毒、广告和有害内容,提高安全性。

    提高性能:正向代理服务器可以缓存常用资源,减少对目标服务器的请求,从而提高性能。

    VPN服务:正向代理服务器通常用于构建虚拟私人网络(VPN)。用户可以通过连接到VPN服务器来获得安全的、匿名的互联网访问,并访问受限资源。

    企业内部网络:在企业内部,正向代理服务器通常用于管理内部网络的访问控制和安全性,允许员工安全地访问互联网资源。

    正向代理与反向代理的区别
    简单来讲:
    正向代理需要在客户端做配置,服务器不需要做任何配置。
    反向代理需要在服务器做配置,客户端不需要做任何配置。
  • Nginx 可以作为反向代理服务器,将客户端的请求转发到后端服务器,实现负载平衡和高可用性。这对于分散负载和提供冗余非常有用。
  1. 负载均衡

    • Nginx 可以分发请求到多个后端服务器,确保它们平均分担负载,提高系统的性能和可用性。这对于处理大量流量的网站非常重要。
  2. 静态文件服务

    • Nginx 能够快速地提供静态文件(如HTML、CSS、JavaScript和图像),这减轻了后端服务器的负载,提高了网站的响应速度。
  3. 反向代理缓存

    • Nginx 可以缓存一些静态或动态内容,以减少对后端服务器的请求,提高性能。这对于频繁请求相同内容的网站非常有用。

以下是在Ubuntu上管理Nginx的一些常用命令:

  1. 启动Nginx
    1
    sudo systemctl start nginx
  2. 停止Nginx
    1
    sudo systemctl stop nginx
  3. 重启Nginx
    1
    sudo systemctl restart nginx
  4. 重新加载Nginx配置(不中断已经处理的连接):
    1
    sudo systemctl reload nginx
  5. 检查Nginx配置文件的语法是否正确
    1
    sudo nginx -t
  6. 查看Nginx的状态
    1
    sudo systemctl status nginx
  7. 启用Nginx开机自启动
    1
    sudo systemctl enable nginx
  8. 禁用Nginx开机自启动
    1
    sudo systemctl disable nginx
  9. 查看Nginx版本号
    1
    nginx -v
  10. 打开Nginx的主配置文件(默认是/etc/nginx/nginx.conf):
    1
    sudo nano /etc/nginx/nginx.conf
  11. 查看Nginx配置文件所在目录
    1
    nginx -V
  12. 查看Nginx正在监听的端口和虚拟主机配置
    1
    sudo nginx -T
  

Python迭代器与生成器

Python 迭代器和生成器

Python 中的迭代器和生成器是用于处理可迭代对象的强大工具。它们有一些共同点,但也有一些重要的区别。

迭代器(Iterators)

  • 迭代器是可迭代对象的一个子集。
  • 它是一个可以记住遍历位置的对象。
  • 迭代器需要实现 __iter__()__next__() 方法。
  • 使用 iter() 方法可以将列表、元组、集合、字符串等可迭代对象转换为迭代器。
  • 通过调用 next() 方法逐个访问元素。
  • 不能通过索引来访问生成器的元素。
  • 当没有更多元素可迭代时,next() 方法会引发 StopIteration 异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建一个可迭代对象(列表)
my_list = [1, 2, 3, 4, 5]

# 使用iter()方法将可迭代对象转换为迭代器
my_iterator = iter(my_list)

# 使用next()方法逐个访问迭代器的元素
try:
while True:
element = next(my_iterator)
print(element)
except StopIteration:
pass

在这个示例中,将列表my_list转换为迭代器my_iterator,然后使用next()方法逐个访问迭代器的元素。当没有更多的元素可迭代时,next()方法会引发StopIteration异常,我们通过异常处理来结束循环。

生成器(Generators)

  • 生成器是一种特殊的迭代器。
  • 使用 yield 关键字替代 return 返回值,将函数变成生成器对象。
  • 生成器不会一次性生成所有值,而是按需生成每个值,这可以节省内存。
  • 生成器只能被迭代一次,一旦耗尽,需要重新创建或重新初始化才能再次迭代。
  • 不能通过索引来访问生成器的元素。

生成器是生成元素的,迭代器是访问集合元素的一种方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建一个生成器函数
def my_generator():
yield 1
yield 2
yield 3

# 使用生成器函数创建生成器对象
gen = my_generator()

# 迭代生成器并按需生成值
for value in gen:
print(value)

# 尝试再次迭代,会发现生成器已经耗尽
for value in gen:
print(value) # 不会打印任何内容,因为生成器已经耗尽

迭代器用于按需访问集合元素,而生成器用于按需生成元素

  

Python 下划线

  • 单个前导下划线:

    用于表示该变量是模块内部使用的,作为约定,告诉其他开发者这不是公共接口的一部分,不建议直接访问

    1
    2
    3
    4
    5
    6
    class MyClass:
    def __init__(self):
    self.public_variable = 42
    self._protected_variable = 'protected data'
    obj = MyClass()
    print(obj._protected_variable) # 输出: protected data
  • 单个末尾下划线

    避免与Python关键字或者内置函数名命名冲突时,可以使用单个末尾下划线来重命名变量,如class_可以避免与class冲突

    class_ = 'test'
    print(class_)  # 输出: test
    ------------------------------
    class= 'test'
        File "<stdin>", line 1
          class= 'test'
             ^
    SyntaxError: invalid syntax
  • 双前导下划线

    名称修饰,保护父类属性的访问,防止子类属性覆盖父类属性,访问方法obj._类名__属性名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class Parent:
    def __init__(self):
    self.__x = 10 # 使用双前导下划线命名属性

    class Child(Parent):
    def __init__(self):
    super().__init__()
    self.__x = 20 # 子类定义相同名称的属性

    parent = Parent()
    child = Child()

    print(parent.__dict__) # 输出 {'_Parent__x': 10}
    print(child.__dict__) # 输出 {'_Parent__x': 10, '_Child__x': 20}

    print(parent._Parent__x) # 输出 10
    print(child._Child__x) # 输出 20

  • 双前导和双末尾下划线

    用于标识特殊方法(魔术方法),如 __init__(构造方法)、__str__(字符串表示方法)。

    预定义的特殊名称,如,__name__ 是一个包含当前模块名称的特殊变量。__file__ 包含当前模块的文件路径。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class MyClass:
    def __init__(self):
    self.__count__ = 0

    def __str__(self):
    return f"MyClass instance with count: {self.__count__}"
    if __name__ =='__main__': # 预定义的特殊名称
    obj = MyClass()
    obj.__count__ = 5 # 使用末尾下划线的特殊变量
    print(obj) # 输出 "MyClass instance with count: 5"

  • 单个下划线:

    用来表示无关紧要的变量

    1
    2
    for _ in range(5):
    print('test')

    在交互式解释器中,_指向最后一次执行的表达式结果

    1
    2
    3
    4+8
    7+9
    _ # 输出16
  

关键词提取算法

关键词是揭示文档核心主题的最小语义单元,对于理解文本内容至关重要。关键词自动抽取技术致力于自动识别和提取这些具有高度意义和代表性的词汇或短语,实现了自动化的关键词识别过程。在文本挖掘领域,这一技术被称为关键词抽取(Keyword Extraction),而在信息检索领域,它通常被称作自动标引(Automatic Indexing)。关键词提取作为文献检索、自动摘要、文本分类、推荐系统等多个领域的关键任务,为这些应用提供了基础性的支持。

在传统的中文文本处理领域,目前主要采用以下三种算法进行关键词提取:

  • TF/IDF算法:评估词汇在文档中的重要性与其在语料库中的常见程度的反比。
  • TextRank算法:一种基于图的排序算法,通过文档内部的词汇相互作用来确定关键词的重要性。
  • LDA算法:一种主题模型,它假设文档是从隐含主题的混合中生成的,通过这种方式抽取具有代表性的关键词。

TF/IDF算法

预处理:首先,需要对文档进行分词,将文本分解为单个词汇,并去除那些常见但对主题贡献不大的词汇,比如“的、吗、首先、然后”等停用词。这是为了减少噪音,确保算法专注于那些具有实际意义的词汇。

词频(TF)计算:接下来统计每个词在文章中出现的频率,即该词出现次数除以文档的总词数。这个比例反映了词在文档中的重要性,但不能反映词汇的独特性或在整个语料库中的分布情况。

逆文档频率(IDF)计算:逆文档频率用来衡量词汇的罕见程度,通过对语料库中包含该词文档的数量取倒数并进行对数变换来计算,公式为 IDF = log(语料库的文档总数 / 包含该词的文档数 + 1)。这样做是为了提升那些在少数文档中出现但给出大量信息的词的重要性。

计算TFIDF值:最后将每个词的TF值乘以其IDF值得到TF/IDF值。这个值越高,词在文档中的重要性越大。

TextRank算法

TextRank算法是一个基于图的排名算法,广泛应用于关键词提取和文本摘要任务中。其核心思想是利用文本内部词语之间的共现关系来评估每个词语的重要性。在这个过程中,每个词语被视为图中的一个节点,而词语之间的共现关系则形成节点间的连接边。

预处理阶段

首先,对文档进行预处理,包括分词和去除停用词。分词是将文本分解为单独的词汇单元,而去除停用词(如“的”、“吗”、“然后”等)旨在消除那些虽频繁出现但对理解文档主题贡献较小的词汇。这一步骤帮助减少图中的节点数量,确保算法能更有效地聚焦于那些具有实际意义的词汇。

构建图

接下来,构建一个图,其中的节点代表文档中的词语或短语,边代表它们之间的共现关系。这里的“共现”指的是两个或多个词汇在文本中一定窗口大小范围内同时出现的情况,而边的权重通常反映了共现的频次。通过这种方式,图形象地表示了文本中词语的相互关联和相对重要性。

在构建图的过程中,统计共现情况是关键步骤之一。这一步骤通常遵循以下流程:

  1. 窗口大小:首先,确定一个“窗口大小”,即在文本中同时考虑的连续词汇的数量。这个大小可以根据任务和文本的特点调整。较小的窗口强调更紧密的词语关系,而较大的窗口可以捕捉更广泛的上下文关系。
  2. 遍历文本:然后,遍历处理后的文本(已分词且去除了停用词),在每个窗口内记录所有词汇对的共现。例如,如果窗口大小为4,那么窗口中的每个词都与其他三个词形成共现关系。
  3. 构建图:对于每个共现关系,如果图中还不存在这两个词语对应的节点,则创建这些节点;如果这两个节点之间还没有边,则添加一条边,并将边的权重设为1。如果这两个节点之间已经有一条边,则将该边的权重增加1。

迭代计算与权重确定

通过类似PageRank算法的迭代计算过程,每个节点(词或短语)的权重根据其邻接节点的重要性进行动态调整,直至整个系统达到平衡(收敛)。这个过程模拟了一个网络中的“推荐”机制,即一个词的重要性部分由与之相关的其他词的重要性决定。

关键词与摘要的提取

最终,根据节点的权重对它们进行排序,权重越高的词语被认为在文档中的重要性越大。通过选择排名靠前的词语,我们可以确定文档的关键词或生成文本摘要。

类比说明

可以将TextRank算法比作社交网络中的人际关系网。在这个网络中,每个人(节点)通过与其他人的互动(边)建立起连接。一个人的影响力(节点权重)不仅取决于他们直接认识的人数,还受到他们朋友的社交地位影响。这个类比有助于理解TextRank如何通过分析词语间的相互作用来评估它们的重要性,进而抽取关键信息。

LDA算法

LDA(潜在狄利克雷分配,Latent Dirichlet Allocation)是一种常用于文本分析的主题模型,通过分析文档中词语的分布来推断出潜在的主题结构。LDA理想的文档不应过于短暂,以避免词汇过于稀疏,影响主题发现的质量。

初始化

选择K个你希望从文档中发现的主题数量,每个文档被认为是这些主题的一个混合体,其中每个主题被定义为词汇的概率分布。通过狄利克雷分布为每个主题随机生成一个词的概率分布。

随机分配

对于文档中的每个词,随机分配一个主题,作为该词的初始主题标签,然后开始吉布斯采样,不断更新文档中每个词的主题分配,在每次迭代中,算法会为文档中的每个词重新评估其属于各个主题的条件概率。

  1. 对每个文档中的每个词
    • 临时移除该词的当前主题分配。
    • 根据当前模型的状态,计算该词被分配到每个主题的条件概率。这一步利用了以下公式,其中包含两个因素:
      • 文档中其他词的当前主题分配。
      • 全部文档中,当前主题下其他词的分配。
  2. 条件概率公式
    • 具体地,每个词w被分配到主题k的条件概率是基于:
      • $p(topic_k∣document_d)$ 主题k在文档d中的分布。
      • $p(word_w∣topic_k)$:词w在主题k中的分布。
  3. 更新主题分配
    • 根据计算出的条件概率,为该词选择一个新的主题,并更新模型状态。
  4. 迭代直至收敛
    • 这个过程重复执行,直到每个词的主题分配变化不大,模型达到了稳定状态。

收敛

重复迭代过程,直到每个词的主题分配稳定下来,这时算法结束。最终,我们得到每个文档的主题分布,以及每个主题的词分布。从每个主题的词分布中选出N个概率最高的词作为关键词。

  

:D 一言句子获取中...