202506

wget 使用代理

wget -qO- -e use_proxy=yes -e http_proxy=http://127.0.0.1:9080 ifconfig.me/all.json | jq
wget --debug -e use_proxy=yes -e http_proxy=http://127.0.0.1:9080

新建 .net 项目

dotnet new winforms -o WawaEditor
cd .\WawaEditor\
dotnet run

如何设计一个文本编辑器可以打开和编辑超大文本文件

好的,这是一个非常经典且有深度的问题。设计一个能够用较小内存打开、编辑超大文本文件(例如几个 GB 到几十 GB)的文本编辑器,其核心思想是**“分而治之”“虚拟化”**。绝对不能将整个文件一次性读入内存。

下面我将从基本思路到高级数据结构,为你梳理几个关键的设计思路。

核心挑战与错误思路

  • 核心挑战:一个 10GB 的文件远远超出了典型应用程序的内存分配能力,也超出了单个字符串或对象所能容纳的极限。
  • 错误思路:调用 File.ReadAllText()File.ReadAllLines()。这会尝试将整个文件加载到内存中,导致内存溢出(OutOfMemoryException)和程序崩溃。

思路一:文件索引 + 虚拟化视图 (最核心、最实用的方法)

这个思路将“数据模型”与“UI展现”完全分离,是所有高性能大文件编辑器的基础。

1. 建立行索引(Pre-indexing)

在打开文件时,并不读取文件内容,而是快速扫描一遍文件,建立一个行位置索引

  • 做法
    1. 打开一个文件的只读流 (FileStream)。
    2. 创建一个列表,例如 List<long>,用于存储每一行在文件中的起始位置(字节偏移量)。
    3. 从头到尾读取文件流(可以按一个较大的缓冲区,如 64KB,来提高效率),但不保存内容。
    4. 每当检测到一个换行符 (\n),就将紧随其后的字节的偏移量(stream.Position)记录到索引列表中。
  • 结果:你会得到一个相对很小的索引。例如,一个 10GB 的文件有 1 亿行,每行起始位置用一个 long (8字节) 存储,索引本身大约只需要 100,000,000 * 8 bytes ≈ 800 MB 的内存。这虽然也不小,但相比 10GB 已经是可以管理的了。

2. 实现虚拟化 UI(UI Virtualization)

UI 控件(无论是 WinForms 的 TextBox 还是自定义绘制的面板)永远只加载和渲染当前屏幕上可见的几十行文本。

  • 做法
    1. UI 控件维护一个“总行数”的属性,这个值就等于前面建立的行索引的长度。这让滚动条可以正确地表现出文件的总大小。
    2. 当用户滚动滚动条时,根据滚动条的位置计算出当前应该显示的起始行号(例如 line 1,000,000)。
    3. 程序使用行索引,找到第 1,000,000 行在文件中的字节偏移量。
    4. 使用 FileStream.Seek() 方法将文件指针直接移动到该位置。
    5. 从该位置开始,只读取屏幕上需要显示的几十行数据到内存缓冲区中,然后将其渲染到屏幕上。

3. 实现数据缓存(Data Caching)

为了让滚动体验更流畅,不应该只加载屏幕可见的行。

  • 做法:可以维护一个内存中的“窗口”或“缓冲区”,比如总是加载当前可视区域前后各 1000 行的数据。当用户滚动时,只要目标行在缓存中,就不需要进行磁盘 I/O,只有当滚动到缓存区域之外时,才去磁盘读取并更新缓存。

思路二:处理编辑操作 (最复杂的部分)

查看是只读操作,而编辑会改变文件内容和结构,这要复杂得多。

1. 保持源文件只读,使用变更日志(Change Log)

直接修改磁盘上的大文件是非常低效的,因为插入或删除一个字符都可能导致后续所有字节的移动。

  • 做法
    1. 在整个编辑会话中,始终保持原始的超大文件为只读状态
    2. 在内存中创建一个“变更日志”或“事务日志”。这个日志可以是一个字典,例如 Dictionary<int, string>,其中 Key 是行号,Value 是被修改后的新行内容。
    3. 对于修改操作:当用户修改第 N 行时,将新的行内容存入变更日志。
    4. 对于删除操作:在变更日志中标记第 N 行已被删除。
    5. 对于插入操作:在变更日志中记录在第 N 行之后插入了哪些新行。
  • 渲染逻辑:当需要显示第 N 行时,程序首先检查变更日志。
    • 如果日志中有第 N 行的修改/插入记录,则显示日志中的内容。
    • 如果日志中没有,则通过行索引从原始文件中读取并显示。

2. 文件保存策略

  • 另存为 (Save As):这是最简单的保存方式。程序创建一个新文件,然后从头到尾遍历所有行(根据原始索引和变更日志),将最终的内容逐行写入新文件。
  • 保存 (Save):安全的做法是先执行“另存为”到一个临时文件。如果临时文件写入成功,则删除原始文件,并将临时文件重命名为原始文件名。这能保证即使在保存过程中断电或程序崩溃,原始文件也不会损坏。

思路三:使用高级数据结构(优化编辑性能)

当插入和删除操作非常频繁时,简单地维护一个变更日志会变得复杂且低效。这时可以引入专门为文本编辑设计的数据结构。这些结构将文件内容切分成小块,使得中间的修改不会影响到整个数据。

1. Rope (绳索)

  • 概念:Rope 是一种二叉树结构,它的叶子节点是小的文本块(字符串),而中间节点则表示将它的子节点连接起来。
  • 优点
    • 快速编辑:在文本中间插入或删除内容,通常只需要修改树的几个节点,而不需要像数组一样移动大量内存。
    • 内存高效:多个 Rope 可以共享未被修改的子树节点,非常适合实现“撤销/重做”(Undo/Redo)功能。
  • 实现:将大文件切分成许多小的 Rope 叶子节点(例如每 64KB 一个),然后构建一棵 Rope 树来表示整个文件。所有编辑操作都在这棵树上进行。

2. Gap Buffer (间隙缓冲区)

  • 概念:这是一个在内存中维护的、包含一个“间隙”(Gap)的字符数组。光标所在的位置就是间隙所在的位置。
  • 优点
    • 打字速度极快:用户在光标处输入字符,只是简单地在间隙中填入字符并移动间隙的边界,非常高效。
    • 非常适合用户通常在同一位置进行连续编辑的场景。
  • 缺点:当光标大幅度跳跃时,需要移动整个间隙,这会涉及大量的内存复制,性能会下降。

总结与架构设计

一个强大的大文件文本编辑器通常是上述思路的结合体。

简化架构图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
+--------------------------------+
| UI Layer | <-- 用户交互 (滚动, 输入)
| (Virtualized Text Control) |
+--------------------------------+
^
| (请求数据 / 发送编辑命令)
v
+--------------------------------+
| Editor Logic / Buffer | <-- 核心逻辑层
| Manager |
+--------------------------------+
| |
(读取/修改) | | (查找/修改)
v v
+---------------+ +-----------------+
| Data Model | | Change Log | <-- 内存中的数据结构
| (Rope/Gap/etc)| | (记录修改/删/增)|
+---------------+ +-----------------+
|
(按需读取) |
v
+--------------------------------+
| Original Large File on Disk | <-- 磁盘上的原始文件 (只读)
| (Accessed via FileStream) |
+--------------------------------+

总结一下关键点:

  1. 绝不一次性加载:这是第一原则。
  2. 建立索引:为快速定位行提供基础。
  3. UI虚拟化:只渲染屏幕上可见的内容。
  4. 编辑与数据分离:使用变更日志或高级数据结构来处理修改,不直接碰触原始数据。
  5. 安全保存:通过“另存为”+“重命名”的策略保证文件安全。

AI

  1. 初学者的生成式人工智能:
  • 生成式人工智能和语言模型的介绍
  • 探索和比较不同的语言模型
  • 负责任地使用生成式人工智能
  • 理解提示工程的基础知识

https://microsoft.github.io/generative-ai-for-beginners/

  1. 微软 - 初学者的人工智能:

探索这24个有趣课程:

  • 符号式人工智能
  • 神经网络
  • 计算机视觉
  • 自然语言处理
  • 和更多

通过动手实战项目、互动测验和实际实验,加强你的学习。

https://microsoft.github.io/AI-For-Beginners/

  1. 生成式人工智能:周到在线搜索的进化
  • 在线搜索信息的进化

  • 改变我们搜索和共享信息的方式

你将掌握的技能:

  • 生成式人工智能
  • 先进的搜索引擎技术

https://www.linkedin.com/learning/generative-ai-the-evolution-of-thoughtful-online-search/harness-the-power-of-prompt-engineering

Markdown PPT

为开发者打造的演示文稿工具
https://cn.sli.dev/

pyenv

curl https://pyenv.run | bash

pyenv install 3.7.10
pyenv virtualenv 3.7.10 gector 
pyenv activate gector 

pip install --upgrade pip setuptools wheel
pip install jsonnet==0.17.0
pip install -r requirements.txt --prefer-binary


pyenv versions
pyenv uninstall <version>
pyenv virtualenvs

setuptools wheel 这两个是干啥的,python没有自带吗?

工具 作用
setuptools 用于 打包和构建 Python 包(生成 .egg / .tar.gz
wheel 用于 构建和安装 .whl 文件(一种更快的包格式)
  • 几乎所有 pip 安装的包都依赖 setuptools 来“打包”它们自己
  • wheel 是 Python 官方推荐的现代包格式(.whl 文件)
    • 安装快(无需编译),跨平台可用(只要匹配 Python/OS 架构)
    • 使用 pip install --only-binary :all: some_package
  • Python 安装时自带了 pip,通常会预装一个老版本的 setuptools 和 wheel
    • 有些系统精简安装会没有 wheel
    • 很多编译失败问题都是因为这俩太旧或缺失
    • 建议每次建新环境后运行 pip install --upgrade pip setuptools wheel

unshre

unshare 是 Linux 下一个非常强大的命令行工具,用于 创建新的命名空间(namespace)并在其中运行命令。这使你可以在某些隔离的环境下执行程序,比如隔离网络、挂载点、PID 等,类似于容器的某些功能。

工具/系统调用 作用
unshare 创建新的命名空间(如 mount、PID、network、user 等),用于隔离进程资源视图。
chroot 更改当前进程的“根目录”,限制进程访问其他目录,是一种文件系统层面的隔离手段
pivot_root 把新的挂载点作为根文件系统,原根变成子目录,是更强的 rootfs 替换方式,常用于 init 或容器。

实现了一个隔离的运行环境

unshare --mount --uts --ipc --net --pid --fork bash
mount --bind /myroot /myroot
chroot /myroot /bin/bash

好的!下面我将为你提供一个完整的 Bash 脚本,它使用 unshare + chroot 构建一个类容器(轻量沙箱)环境,你可以在里面运行独立命令,和宿主系统隔离。


🧱 脚本目标

  • 创建新的命名空间(mount、PID、UTS、IPC、net)
  • 使用 unshare 隔离这些命名空间
  • 使用 chroot 切换到一个你准备好的根文件系统(比如一个最小的 BusyBox 或 Debian 系统目录)
  • 自动挂载 /proc 和其他必要目录
  • 模拟容器效果

🧾 脚本内容:sandbox.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/bin/bash

set -e

# 1. 指定你准备的 rootfs 路径(提前准备 busybox、debian 根目录等)
ROOTFS=/sandbox/rootfs

# 2. 检查 root 权限
if [ "$EUID" -ne 0 ]; then
echo "请用 root 运行这个脚本"
exit 1
fi

# 3. 必须的目录结构
mkdir -p $ROOTFS/{proc,sys,dev,tmp}

# 4. 创建沙箱:新命名空间 + chroot + /proc 挂载
unshare --mount --uts --ipc --net --pid --fork bash <<EOF
# 挂载 /proc
mount -t proc proc $ROOTFS/proc

# 可选:挂载 dev
mount --bind /dev $ROOTFS/dev
mount --bind /sys $ROOTFS/sys

# 设置主机名
hostname sandbox

# 切换 rootfs
cd $ROOTFS
chroot . /bin/bash

# 退出时卸载
umount $ROOTFS/proc
umount $ROOTFS/dev
umount $ROOTFS/sys
EOF

精简

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
set -e
ROOTFS=/sandbox/rootfs
mkdir -p $ROOTFS/{proc,sys,dev,tmp}
unshare --mount --uts --ipc --net --pid --fork bash -c "
mount -t proc proc $ROOTFS/proc
mount --bind /dev $ROOTFS/dev
mount --bind /sys $ROOTFS/sys
hostname sandbox
exec chroot $ROOTFS /bin/sh
"

📦 如何准备 $ROOTFS

方法一:用 busybox 最小系统

1
2
3
4
5
6
7
mkdir -p /sandbox/rootfs
cd /sandbox/rootfs
cp /bin/busybox ./bin/
# 创建符号链接
for cmd in sh ls mount umount echo cat; do
ln -s /bin/busybox ./bin/$cmd
done

方法二:用 Debian 制作 rootfs(推荐)

1
debootstrap --arch=amd64 stable /sandbox/rootfs http://deb.debian.org/debian/

🧪 使用方式

1
2
sudo chmod +x sandbox.sh
sudo ./sandbox.sh

你会进入一个完全隔离的 bash,你在里面看不到宿主的进程、网络、主机名,甚至可以模拟 root(如果使用 --user)。


🚀 进阶(添加用户命名空间)

想用非 root 用户运行(模拟 root 权限):

1
unshare --user --mount --uts --ipc --net --pid --fork --map-root-user bash

需要额外做 UID/GID 映射,这可以再扩展支持。


如果你告诉我你想基于什么系统(busybox、Debian、Ubuntu)或你的使用场景(如运行 Node、Python、curl、网络实验、进程沙箱),我可以为你生成更详细、更高级的容器脚本。是否继续?

太好了,恭喜你成功运行了沙箱环境!👏
现在你想把宿主机上的 tree 命令“提供”给沙箱使用 —— 也就是 把它连同依赖复制进沙箱 rootfs,这样在 chroot 后可以运行 tree


✅ 步骤概览

要让沙箱内能用 tree 命令,你需要:

  1. 找出 tree 可执行文件的位置;
  2. 找出它依赖的共享库(.so 文件);
  3. 把这些文件复制到沙箱的 rootfs 中对应的位置;
  4. 在沙箱内运行验证。

🛠️ 操作步骤(以 Ubuntu 为例)

🔍 1. 查找 tree 路径

1
which tree

输出示例:

1
/usr/bin/tree

🔍 2. 查看依赖库

1
ldd /usr/bin/tree

输出示例:

1
2
3
linux-vdso.so.1 =>  (0x00007ffce45f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f158ae00000)
/lib64/ld-linux-x86-64.so.2 (0x00007f158b200000)

📦 3. 创建目标路径并复制文件

假设你的 $ROOTFS=/sandbox/rootfs

1
2
3
4
5
6
# 可执行文件
cp /usr/bin/tree $ROOTFS/usr/bin/

# 共享库
cp /lib/x86_64-linux-gnu/libc.so.6 $ROOTFS/lib/x86_64-linux-gnu/
cp /lib64/ld-linux-x86-64.so.2 $ROOTFS/lib64/

注意:libc.so.6ld-linux 的路径和平台有关,请以你的系统为准。


⛑️ 4. 如目录不存在,先创建它:

1
2
3
mkdir -p $ROOTFS/usr/bin
mkdir -p $ROOTFS/lib/x86_64-linux-gnu
mkdir -p $ROOTFS/lib64

✅ 5. 进入沙箱验证

进入你之前配置好的沙箱:

1
sudo ./sandbox.sh

然后在沙箱中运行:

1
tree

你应该能看到正常输出。


🧠 小提示:写个通用复制函数

你可以写个函数批量复制任何命令和其依赖,比如:

1
2
3
4
5
6
7
8
9
10
11
12
copy_command_to_rootfs() {
CMD=$1
DEST=$2
BIN=$(which $CMD)

echo "Copying $CMD from $BIN"
cp --parents "$BIN" "$DEST"

for LIB in $(ldd $BIN | awk '{print $3}' | grep -v '^$'); do
cp --parents "$LIB" "$DEST"
done
}

使用方式:

1
2
3
copy_command_to_rootfs tree /sandbox/rootfs
copy_command_to_rootfs ls /sandbox/rootfs
copy_command_to_rootfs ps /sandbox/rootfs

✅ 总结

步骤 命令
查找命令位置 which tree
查找依赖 ldd /usr/bin/tree
复制文件 cp 可执行文件和依赖库
进入沙箱 sudo ./sandbox.sh
运行验证 tree

这是一个非常好的问题,说明你在深入理解 Linux 沙箱或容器底层原理。
我们之所以在沙箱(chroot + unshare)环境中挂载 /proc/dev/sys,是为了让沙箱内的程序能够正常运行、获取系统信息,模拟“更真实的 Linux 环境”。

下面我来详细解释这三个挂载点的意义和用途:


✅ 1. /proc虚拟的进程信息文件系统

  • /proc 是一个由内核提供的虚拟文件系统,不是真正存在的文件,而是系统运行时动态生成的内容。
  • 它包含了进程信息(如 /proc/[pid]/status)、内核配置、CPU、内存等信息。

🚀 如果不挂载 /proc

  • ps, top, htop, free, uptime, cat /proc/cpuinfo 等命令将无法工作;
  • 会报错:procfs not mounted, No such file or directory, ps: command failed.

✅ 沙箱中挂载示例:

1
mount -t proc proc /sandbox/rootfs/proc

✅ 2. /dev设备节点目录

  • /dev 包含各种设备文件,例如:

    • /dev/null, /dev/zero, /dev/random
    • /dev/tty, /dev/pts/*(终端)
    • /dev/sda, /dev/loop0(磁盘)
  • 许多命令和 shell 交互都会依赖这些设备节点。

🚀 如果不挂载 /dev

  • 很多命令会报错,例如:

    • ls 输出时写不到 /dev/tty
    • 程序访问 /dev/null 失败
    • 无法输入密码、不能交互

✅ 挂载方式(复制宿主 /dev 进沙箱):

1
mount --bind /dev /sandbox/rootfs/dev

⚠️ 注意:这不是“完全隔离的设备”,只是复用了宿主 /dev,安全性适中。


✅ 3. /sys内核对象模型文件系统(sysfs)

  • /sys 是另一种虚拟文件系统,用于查看和配置内核设备与模块信息,如:

    • /sys/class/net(网卡信息)
    • /sys/block(磁盘信息)
    • /sys/kernel(内核状态)
  • 很多系统工具(如 udevadm, ip, lsblk, systemd)都依赖它。

🚀 如果不挂载 /sys

  • ip, ifconfig, udevadm, lsblk 等命令会失效;
  • 可能报错:sysfs not mounted, cannot read /sys/...

✅ 挂载方式:

1
mount --bind /sys /sandbox/rootfs/sys

🎯 总结:为什么挂这三大目录?

目录 类型 作用/必要性 如果不挂会怎样
/proc 虚拟 fs 提供进程/内核/内存等信息 ps, top, free 等都失效
/dev 设备节点 提供基本输入/输出、tty、null 等设备支持 无法交互、输出失败、命令报错
/sys 虚拟 fs 提供内核/硬件/网络等信息 ip, lsblk, udevadm 无法使用

🧠 想象一下如果你用 Docker

你运行一个 Docker 容器时,其底层也会挂载这些内容(可能是隔离版或 bind mount):

1
docker run -it ubuntu

Docker 就会自动挂载:

  • --mount type=proc
  • --mount type=sysfs
  • --mount /dev(部分绑定)

✅ 补充建议

如果你想提高安全性,也可以选择只挂一些最小需要的设备(比如 /dev/null, /dev/tty)而不是整挂 /dev,甚至配合 devtmpfsudevd 模拟完整环境。

links

Flight of the Iron Condor: Soaring in Range-Bound Markets
https://thetradinganalyst.com/iron-condor/

Iron Condor Options Strategy: Maximize Returns with Less Risk
https://tradewiththepros.com/iron-condor-options-strategy/

从零构建大模型
Build a Large Language Model (From Scratch)
https://www.manning.com/books/build-a-large-language-model-from-scratch

LLM Embeddings Explained: A Visual and Intuitive Guide
https://huggingface.co/spaces/hesamation/primer-llm-embedding

数理统计讲义
https://bookdown.org/hezhijian/book/

终于把 Transformer 算法搞懂了!!
https://mp.weixin.qq.com/s/GSgcb4EuMsrHoLAU5NdzTQ

最强总结,解决过拟合问题必会的七大方法!!
https://mp.weixin.qq.com/s/O3yiUd1kxzyf8rQGttBPEA

终于把机器学习中的评估指标搞懂了!!
https://mp.weixin.qq.com/s/UU3SzID-YXyQ4lG1FTMT-g

-分类任务评估指标
- 1.混淆矩阵
- 2.准确率
- 3.精确率
- 4.召回率
- 5.F1-Score
- 6.ROC 曲线与 AUC
- 7.PR 曲线 (Precision-Recall Curve)

  • 回归任务评估指标
    • 1.均方误差
    • 2.均方根误差
    • 3.平均绝对误差
    • 4.决定系数 R^2
    • 5.调整后的 R^2
  • 聚类任务的评估指标
    • 轮廓系数

ChatGPT技术原理解析
https://zhuanlan.zhihu.com/p/618320262

OpenAI ChatGPT(三):十分钟读懂 GPT-2
https://zhuanlan.zhihu.com/p/613895056

ck

ck distinct 爆内存,可以设置不同的 distinct 算法

SET count_distinct_implementation = 'uniq';

SELECT countDistinct(xxx)
FROM data 
WHERE xxx != '';
实现名 描述
uniq 使用 HyperLogLog++,近似但非常快
uniqCombined 平衡准确性和内存
uniqExact 完全精确,但慢
uniqHLL12 12-bit HyperLogLog(近似)

向量的 L1,L2,L∞ 范数的作用

向量的 L1 范数L2 范数L∞(无穷)范数 是衡量向量“大小”或“长度”的不同方式。它们在数学、机器学习、优化等领域中有广泛用途。下面我分别介绍它们的定义、直观理解和典型应用:


✅ 1. L1 范数(曼哈顿距离)

定义:

$$
|x|1 = \sum{i=1}^{n} |x_i|
$$

即所有分量的绝对值之和

几何理解:

  • 表示从原点到点 $x$ 的“曼哈顿距离”。
  • 在二维平面上,等 L1 范数的点集是一个菱形。

作用 / 应用:

  • 稀疏性:L1 范数常用于稀疏建模(如 Lasso 回归),能使一些系数变为0,达到特征选择的效果。
  • 在某些优化问题中,L1 范数约束比 L2 更容易生成稀疏解。

✅ 2. L2 范数(欧几里得范数)

定义:

$$
|x|2 = \sqrt{\sum{i=1}^{n} x_i^2}
$$

即向量的平方和的平方根

几何理解:

  • 这是我们最熟悉的“距离”概念。
  • 在二维平面上,等 L2 范数的点集是一个圆。

作用 / 应用:

  • 稳定性强:L2 范数会平滑参数,不会像 L1 那样强制为0,适合保留所有特征。
  • 用于岭回归(Ridge),可以缓解共线性问题。
  • 常用于损失函数,如 MSE(均方误差)中的平方项就是 L2 范数的平方。

✅ 3. L∞ 范数(无穷范数 / 最大范数)

定义:

$$
|x|\infty = \max{i} |x_i|
$$

即向量中绝对值最大的分量

几何理解:

  • 在二维平面上,等 L∞ 范数的点集是一个正方形(轴对齐)。

作用 / 应用:

  • 最大误差控制:适用于当你想限制某个变量偏差不能太大,比如鲁棒优化、控制最大误差。
  • 有时用于神经网络权重的约束,确保每个权重不超过某个值。

✅ 对比总结

范数 数学表达 特点和作用 常见应用
L1 ( \sum x_i ) 稀疏、易于特征选择 Lasso、稀疏编码
L2 $\sqrt{\sum x_i^2}$ 平滑、稳定,强调整体误差 Ridge 回归、MSE、神经网络
L∞ ( \max x_i ) 控制单个最大误差、注重极端值 鲁棒优化、最大误差约束

最大似然估计法的思想是使训练数据出现的概率最大化,依此确定概率分布中的未知参数,估计出的概率分布也就最符合训练数据的分布。最大后验概率法的思想则是根据训练数据和已知的其他条件,使未知参数出现的可能性最大化,并选取最可能的未知参数取值作为估计值。
解释这段话

这段话是在对比两种常见的统计推断方法
最大似然估计(Maximum Likelihood Estimation, MLE)
最大后验概率估计(Maximum A Posteriori Estimation, MAP)


我们来逐句拆解和解释这段话:


🔹 1. 「最大似然估计法的思想是使训练数据出现的概率最大化,依此确定概率分布中的未知参数」

解释:

  • 给定一组观测数据(训练数据),我们假设这些数据是从某种分布 $P(x \mid \theta)$ 中产生的,$\theta$ 是我们想估计的参数。
  • 最大似然的目标是:找一个参数 $\theta$,使得在这个参数下,整个训练数据出现的可能性最大

公式上写作:

$$
\hat{\theta}{\text{MLE}} = \arg\max{\theta} P(D \mid \theta)
$$

其中 $D$ 是观测数据,$P(D \mid \theta)$ 是数据在参数 $\theta$ 下出现的“似然函数”。

所以你可以理解为:

MLE 用模型解释已有数据,并找一个最可能“生成”这些数据的参数。


🔹 2. 「估计出的概率分布也就最符合训练数据的分布。」

解释:

MLE 得到的参数 $\hat{\theta}$,是最可能生成训练数据的那个参数,因此它构建出的分布 $P(x \mid \hat{\theta})$ 就最接近数据分布的形状(在模型允许的范围内)。


🔹 3. 「最大后验概率法的思想则是根据训练数据和已知的其他条件,使未知参数出现的可能性最大化」

解释:

这时你不再只根据数据来估计参数,还考虑参数本身可能的先验分布 $P(\theta)$。

也就是说,你相信:

参数 $\theta$ 并不是完全未知的,它服从某个先验概率分布。

MAP 的目标是:

$$
\hat{\theta}{\text{MAP}} = \arg\max{\theta} P(\theta \mid D)
$$

也就是:

找出在给定数据 $D$ 之后,参数 $\theta$ 出现概率(后验概率)最大的那个取值。

根据贝叶斯公式:

$$
P(\theta \mid D) \propto P(D \mid \theta) \cdot P(\theta)
$$

所以:

$$
\hat{\theta}{\text{MAP}} = \arg\max{\theta} P(D \mid \theta) \cdot P(\theta)
$$

✅ 可见:MAP = MLE × 先验
(如果先验是均匀分布,MAP就退化成MLE)


🔹 4. 「并选取最可能的未知参数取值作为估计值。」

这就是“最大后验”的意义:

在考虑了数据和先验之后,最有可能的参数取值是谁?我们就选它作为我们的参数估计。


✅ 总结对比

方法 核心思想 数学形式 是否使用先验 典型场景
MLE 找一个参数,使训练数据的出现概率最大 $\arg\max_\theta P(D \mid \theta)$ ❌ 不使用 模型拟合、最大化似然
MAP 找一个参数,使它在观测数据下最有可能 $\arg\max_\theta P(D \mid \theta) P(\theta)$ ✅ 使用 有先验信息,希望正则化参数

🎯 类比理解

  • MLE 就像一个只看考试成绩的老师,谁考得高就选谁
  • MAP 就像一个考虑了“平时表现”的老师,不仅看这次考试,还看学生的日常表现(先验)

为什么P(D∣θ) 是个函数而P(x∣θ)是一种分布呢,不太理解

你这个问题非常关键,是很多人在学习统计推断时的“认知断层”之一。我们来逐步、深入但通俗地解释:


🎯 首先区分两个视角:

符号 是谁在变? 是谁被视为“已知” 本质
$P(x \mid \theta)$ x 是变量 $\theta$ 已知 这是一个分布(给定 $\theta$,x 的分布)
$P(D \mid \theta)$ θ 是变量 D(数据)已知 这是一个函数(θ 的函数),叫“似然函数

🧠 更直白地讲:

  • $P(x \mid \theta)$ 是“生成数据的模型”:

    给你一套参数(比如正态分布的均值和方差),那么 x 是如何分布的?我们就可以画出这个分布图。

  • $P(D \mid \theta)$ 是“观察了数据后,θ 的可能性如何变化”:

    数据是观察到的事实,我用它来评估每个 $\theta$ 对这份数据的解释能力有多强。它是 $\theta$ 的函数。


🔍 举个直观例子:硬币抛掷

你要估计一个硬币正面概率 $\theta$

  • 你观察到:抛了 10 次,结果是 7 次正面、3 次反面(数据 $D$)

A. 用 $P(x \mid \theta)$:描述模型

这是“给定θ,某次抛正面的概率是多少”:

$$
P(x = H \mid \theta) = \theta \
P(x = T \mid \theta) = 1 - \theta
$$

这是一个分布
每一个θ值,都会生成一个特定的抛硬币模型。


B. 用 $P(D \mid \theta)$:评价 θ 的可能性

这是似然函数,告诉你:如果正面概率是θ,出现“7正3反”的这个结果有多大可能?

$$
P(D \mid \theta) = \theta^7 (1 - \theta)^3
$$

你可以把这个看成是 θ 的函数,在 θ∈[0,1] 上作图,它的最大值对应最可能的 θ(这就是 MLE)。


✅ 所以你的问题是:

为什么 $P(x \mid \theta)$ 是个分布,而 $P(D \mid \theta)$ 是个函数?

✅ 答案:

  • 因为两者的“自变量”不同

    • 在 $P(x \mid \theta)$ 里,x 是变量,θ是固定的 → 所以它是“x 的概率分布”
    • 在 $P(D \mid \theta)$ 里,θ 是变量,D是固定的 → 所以它是“θ 的函数”,即似然函数

✅ 它们本质上是同一个公式,只是关注点不同:

名称 形式 谁是变量 用来干什么
概率分布 $P(x \mid \theta)$ x 用已知参数描述数据如何分布
似然函数 $\mathcal{L}(\theta) = P(D \mid \theta)$ θ 用已知数据估计参数θ

📌 总结口诀:

同一个公式,换个变量看主角,
x是变量就是分布,θ是变量就是似然!


如果你愿意,我可以画一个图,展示这个视角的“切换”过程,更直观。是否需要图示说明?

ck

clickhouse中如何每隔1000条数据取一条数据

1
2
3
4
5
6
7
8
SELECT *
FROM (
SELECT
*,
row_number() OVER () AS rn
FROM your_table
) AS sub
WHERE rn % 1000 = 1

ck中如何查看一个字段的分散度或基数?

1
2
3
4
5
SELECT
uniq(your_column) AS uniq_count,
count() AS total_count,
uniq(your_column) / count() AS dispersion_ratio
FROM your_table;
  • uniq 是 ClickHouse 提供的近似去重计数函数(基于 HyperLogLog),比 count(DISTINCT …) 快得多。
  • 如果需要更高精度,也可以使用 uniqExact(your_column)。
  • dispersion_ratio 越接近 1,说明字段越分散(越接近每行一个不同值)
  • 越接近 0,说明字段值高度集中(低基数)

python

wav to mp3

from pydub import AudioSegment

# 读取 WAV 文件
audio = AudioSegment.from_wav("output.wav")

# 导出为 MP3
audio.export("output.mp3", format="mp3")

shell

sudo apt-get install sox libsox-dev
sox input.wav output.mp3

ck

cityHash64和crc32的区别

特性 cityHash64 crc32
目标用途 哈希分片、采样、去重 数据完整性校验
位数 64 位 32 位
速度 极快(专为性能优化) 非常快
碰撞率 极低 高(不适合作为哈希键)
安全性 非加密,不可逆 非加密,不可逆
用于采样/分片 ✅ 推荐使用 ❌ 不推荐使用

我有一个crc32的列,如何分成100个均等的段儿,查看每个段的数据量?

SELECT
    intDiv(crc32_value, pow(2, 32) / 100) AS bucket,
    count(*) AS count
FROM your_table
GROUP BY bucket
ORDER BY bucket;

如何求出每个桶的数量的均值和标准差

SELECT
    avg(cnt) AS mean,
    stddevPop(cnt) AS stddev
FROM (
    SELECT
        intDiv(crc32_value, pow(2, 32) / 100) AS bucket,
        count(*) AS cnt
    FROM your_table
    GROUP BY bucket
) AS bucket_counts;
  • stddevPop(cnt):总体标准差(不是样本标准差);
  • 如果你更倾向于样本标准差,可用 stddevSamp(cnt)。

如何均匀的遍历一个cityhash64范围,用python,遍历的过程中调用一个函数,如果函数报错,则缩小本次遍历的范围,如果缩小后函数仍然报错,继续缩小,如果无法再缩小,则跳出循环。要做到不重不漏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
MAX_UINT64 = 2**64 - 1
MIN_BLOCK_SIZE = 1000 # 最小粒度,防止无限分裂

def do_task(start, end):
"""
你自定义的函数,比如处理某个 cityHash64 范围
报错可以是内存、网络、查询失败等
"""
if end - start > 10**9:
raise RuntimeError("模拟处理失败")
print(f"Processed range: {start} ~ {end}")

def process_range(start, end):
try:
do_task(start, end)
except Exception as e:
if end - start <= MIN_BLOCK_SIZE:
print(f"Too small to split further: {start} ~ {end}, skipping. Error: {e}")
return
mid = (start + end) // 2
process_range(start, mid)
process_range(mid + 1, end)

def main():
STEP = 2**32 # 初始大步长
for bucket_start in range(0, MAX_UINT64, STEP):
bucket_end = min(bucket_start + STEP - 1, MAX_UINT64)
process_range(bucket_start, bucket_end)

if __name__ == "__main__":
main()

ClickHouse vs StarRocks 选型对比
https://zhuanlan.zhihu.com/p/441059030

LLM 的推理优化技术纵览
https://blog.csdn.net/hellozhxy/article/details/131897500

安卓端侧大模型MLC-LLM部署全攻略:以InternLM2.5-1.8B为例
https://zhuanlan.zhihu.com/p/714316090

为您的应用找到合适的 AI/机器学习解决方案
https://developer.android.com/ai/overview?hl=zh-cn
我们提供一系列示例应用,帮助您开始使用机器学习套件。
https://developers.google.com/ml-kit/samples?hl=zh-cn
https://github.com/googlesamples/mlkit/tree/master

MediaPipe LLM Inference task for web
https://github.com/google-ai-edge/mediapipe-samples/tree/main/examples/llm_inference/js

Transformer 如何用于日内交易

Transformer在日内交易中的应用主要通过其强大的时序建模和多模态处理能力,结合金融市场的高频数据特性,实现从预测到策略执行的全流程优化。以下是具体应用场景和技术实现:

一、高频时序预测与订单执行优化

Transformer通过自注意力机制捕捉分钟级甚至秒级数据的长期依赖,在成交量预测、价格趋势判断等任务中表现突出。例如,IVE模型采用对数正态变换处理高波动性成交量数据,结合时间编码和股票特征嵌入,构建编码器-解码器Transformer预测一分钟级成交量比。该模型在韩国市场实盘测试中,执行VWAP策略的表现优于传统基准,平均击败率达59%,且能通过概率预测捕捉成交量峰值的均值和标准差,为订单拆分提供动态依据。

在价格预测方面,Transformer可通过滑动窗口技术构建多因子特征矩阵(如MACD、RSI、波动率等),结合位置编码和因果多头注意力机制,避免未来信息泄露。例如,某研究采用60分钟级特征输入,输出未来1步的涨/跌/平概率,测试数据中三只股票的百分比RMSE均低于2%,并通过夏普比率损失函数直接优化风险调整后收益,策略净值曲线显示年化超额收益达7.15%。

二、多模态数据融合与事件驱动分析

金融市场的波动性不仅受价格序列影响,还与新闻、政策、社交媒体情绪等非结构化数据密切相关。Transformer的多模态处理能力可通过以下方式实现:

  1. 四通道并行编码器:整合技术指标、金融文本、宏观数据和事件知识图,通过动态门控机制自动学习不同模态的重要性。例如,在分析“碳中和”政策影响时,模型能量化事件对特定行业的动态冲击,提升预测准确性。
  2. 动态事件响应:引入双重时间轴编码,区分交易日周期和事件冲击强度。例如,在美联储议息会议期间,模型通过低频子带(0.1Hz)的注意力权重调整,提前18小时预测到标普500的2%波动。
  3. 情绪-价格联动建模:将新闻文本情感极性与订单流数据编码为768维向量,通过异构计算实现30秒内多模态融合预测。例如,在特斯拉电池日行情中,模型在开盘后45分钟触发买入信号,当日收益率达8.7%。

三、动态策略生成与风险控制

Transformer不仅用于预测,还可直接生成交易信号并优化仓位管理:

  1. 夏普比率导向的策略优化:将夏普比率作为损失函数,模型输出直接映射为仓位权重。例如,某策略通过动态EMA交叉结合Transformer预测,在单边万1费率下实现7.15%的超额收益,且与传统截面策略的相关性仅12.18%,有效分散风险。
  2. 波动率自适应仓位管理:基于预测收益率与历史波动率的比值,通过tanh函数压缩仓位大小。例如,当预测收益为2%、波动率为1%时,仓位自动调整为tanh(2/1)=0.761,避免过度杠杆。
  3. 增量学习与动态阈值:针对市场结构变化,采用每季度重训模型并调整多空阈值。例如,某高频策略在2024年美联储加息周期中,通过动态阈值将盈亏比锁定在1.8:1以上,样本外衰减控制在每年6.68%以内。

四、工程实现与挑战应对

  1. 计算资源优化
    • 模型压缩:采用Kronecker分解将注意力矩阵计算量降低60%,在预测精度损失5%的情况下,交易频率翻倍使盈亏比提升至1.6:1。
    • 异构计算:结合GPU与量子退火技术,在波动率曲面预测等低维任务中,量子处理器比GPU快120倍。
  2. 数据延迟与噪声处理
    • 实时流处理:采用分布式架构实现微秒级数据摄入,通过卡尔曼滤波平滑订单流噪声。例如,某系统将Level2行情延迟控制在300毫秒内,确保预测准确率稳定在75%以上。
    • 对抗训练:在数据中注入±5%的股价扰动,提升模型对异常波动的鲁棒性。例如,在2024年中东局势动荡期间,模型仍保持61%的胜率。
  3. 跨市场迁移学习
    • 行业特征解耦:将Transformer的注意力头拆分为通用经济周期头和行业特性头。例如,Hidformer模型在A股电力板块训练后,迁移至美股科技股仍保持68%胜率,并在能源危机中自动强化油气板块权重。

五、实际应用案例与性能对比

  1. 韩国市场VWAP策略:IVE模型通过概率预测优化订单执行,在两个月半实盘测试中,执行价格平均优于市场VWAP 4.82个基点,标准差预测与实际波动率相关性达0.81。
  2. A股时序策略:改进动量Transformer模型构建日内+隔夜交易策略,在单边万1费率下,年化超额收益7.15%,最大回撤24.4%,夏普比率2.8,显著优于买入持有基准。
  3. 高频交易系统:某私募采用16卡A100集群处理纳斯达克限价订单簿数据,F1分数达92.8%,但需每日承担五位数电费,且需每季度重训应对样本外衰减。

六、未来发展方向

  1. 量子增强Transformer:探索量子退火技术在注意力矩阵优化中的应用,目标将计算速度提升100倍以上。
  2. 神经符号系统:结合符号逻辑(如监管规则)与神经网络,实现可解释的合规交易策略。
  3. 联邦学习框架:在保护隐私的前提下,跨机构共享数据训练全局模型,提升小市值股票预测精度。

总结

Transformer在日内交易中的核心价值在于其动态时序建模能力多模态信息整合,通过概率预测、动态策略生成和实时风险管理,实现从数据到收益的端到端优化。尽管面临计算成本高、样本外衰减等挑战,但其在高频预测、多资产联动分析等场景中的优势已被实证研究和实盘交易验证。未来,随着硬件技术进步和模型架构创新,Transformer有望成为量化交易领域的主流工具。


Transformer在日内交易策略中的应用,核心在于利用其自注意力机制对高频时序数据的长期依赖捕捉能力、多模态信息融合能力,以及端到端的策略生成能力,实现从数据处理到信号输出的全流程优化。以下从技术架构、核心模块、实战场景及优化方向四个维度进行详解:

一、日内交易场景的核心挑战与Transformer的适配性

日内交易(如股票、期货的分钟级/秒级交易)需解决三大核心问题,而Transformer天然具备针对性优势:

  1. 高频数据的时序依赖复杂性:日内价格受短期波动(如订单流冲击)和中期趋势(如早盘情绪)共同影响,传统RNN/LSTM难以捕捉跨度超过1小时的长程依赖。
    • Transformer的自注意力机制可通过全局注意力权重分配,同时关注5分钟前的订单簿突变和1小时前的开盘缺口,例如在处理期货1分钟K线时,能动态识别“早盘跳空+午盘成交量放大”的联动模式。
  2. 多源信息的实时融合:日内行情不仅依赖价格数据,还受新闻公告(如突发政策)、盘口数据(如Level2订单流)、资金流向等多模态信息影响。
    • Transformer的多模态编码器可将文本、数值、图形等异构数据映射至同一向量空间,例如将“央行降准”新闻的情感向量与国债期货的tick数据实时融合,提前30分钟预测利率期货的波动方向。
  3. 策略的动态适应性:日内市场结构(如波动率、流动性)随时间变化(如开盘/收盘时段特征不同),固定参数策略易失效。
    • Transformer可通过动态注意力调整(如不同时段的注意力头权重分配不同),自动适配“早盘高波动”和“午盘低波动”场景,例如在A股9:30-10:00自动提升对成交量的关注度,14:00后则更关注持仓量变化。

二、Transformer日内策略的技术架构与核心模块

一个完整的Transformer日内策略通常包含数据预处理层特征编码层Transformer模型层信号生成层风险控制层,各模块的设计需贴合日内交易特性:

1. 数据预处理层:高频数据的降噪与标准化

日内高频数据(如1分钟K线、tick级订单簿)存在噪声多、分布不稳定的问题,预处理需针对性优化:

  • 异常值处理:采用移动中位数滤波剔除极端价格(如瞬间涨跌停的废单),例如对期货tick数据,用±3倍标准差过滤偏离正常波动范围的价格点。
  • 时间对齐:将非同步数据(如每3秒更新的订单流与每分钟更新的MACD)统一到1分钟时间轴,缺失值用前向填充(适用于流动性低的时段)。
  • 特征工程:构建日内专属特征,例如:
    • 时序特征:5分钟波动率(RV5)、早盘30分钟涨跌幅、日内累计成交量占比(VPT);
    • 盘口特征:买卖盘口价差(Bid-Ask Spread)、订单簿深度(Depth)、大单成交占比;
    • 情绪特征:资金净流入率、多空成交量比。

2. 特征编码层:适配日内周期的位置与模态编码

Transformer的输入需通过编码将特征转化为向量,关键在于时间编码多模态融合

  • 时间编码:区分日内周期性(如9:30、11:30、15:00等关键时点),采用周期性位置编码(如sin/cos函数)+时段标记(如开盘/盘中/收盘的独热编码),例如:

    1
    位置编码 = sin(时间戳/10000^(2k/d_model)) + 时段标记向量

    使模型识别“早盘波动>午盘”的规律。

  • 多模态编码:对不同类型数据设计专属编码器:

    • 数值特征(如价格、成交量):通过全连接层映射为d_model维度向量;
    • 文本特征(如新闻标题):用BERT微调生成情感向量(如“利多”=+0.8,“利空”=-0.7);
    • 订单簿数据:将买一至买五、卖一至卖五的价格和数量拼接为矩阵,用CNN提取局部特征后再映射至d_model维度。

3. Transformer模型层:针对日内任务的结构优化

标准Transformer需调整以适配高频场景:

  • 编码器设计:采用因果注意力(Causal Attention),确保预测时仅使用过去信息(避免未来数据泄露),即注意力矩阵的上三角部分(未来时刻)设为-∞,无法被关注。
  • 层数与维度:高频数据噪声多,过深模型易过拟合,通常采用4-6层编码器,d_model=128-256(平衡计算速度与精度),例如处理1分钟K线时,输入序列长度设为60(即1小时历史数据)。
  • 轻量化优化:采用稀疏注意力(如只关注最近30分钟+每个整点时刻的数据),将计算复杂度从O(n²)降至O(n),满足日内策略的实时性要求(如每5分钟更新一次信号)。

4. 信号生成层:从预测到交易决策

模型输出需直接映射为交易信号(如多空方向、仓位大小):

  • 分类任务:预测未来5分钟涨(1)、跌(-1)、平(0),用交叉熵损失函数,例如输出概率>0.6则做多,<0.4则做空。

  • 回归任务:预测未来10分钟的收益率,用MSE损失函数,结合波动率动态调整仓位:

    1
    仓位 = 预测收益率 / 历史5分钟波动率 * 风险系数(如0.02)

    避免高波动时过度交易。

  • 强化学习融合:将“收益-风险”作为奖励函数(如夏普比率),用PPO算法微调模型,使输出直接优化策略的风险调整后收益,例如:

    1
    奖励 = (当前收益 - 无风险利率) / 策略波动率

5. 风险控制层:日内策略的止损与止盈

结合Transformer的预测结果设计动态风控规则:

  • 动态止损:根据模型预测的波动率设置止损线,例如预测未来5分钟波动率为1%,则止损线设为-0.8%(避免正常波动触发止损)。
  • 仓位限制:单品种仓位不超过总资金的5%,多品种合计不超过20%,避免集中度风险。
  • 时段过滤:通过模型对“低流动性时段”(如午盘休市前10分钟)的识别,自动降低仓位至1/3,减少滑点损失。

三、实战场景:Transformer在不同日内策略中的应用案例

1. 期货高频趋势跟踪策略(1分钟级别)

  • 数据输入:60分钟历史1分钟K线(开盘价、收盘价、成交量、持仓量)+ 实时订单簿(买一卖一价差、深度)。
  • 模型设计:4层因果Transformer编码器,输入序列长度60,输出未来5分钟收益率预测。
  • 信号规则:当预测收益率>0.1%且多头注意力权重(对上涨时段的关注度)>0.6时做多,反之做空,持仓不超过15分钟。
  • 回测效果:在螺纹钢期货上,2023年样本内年化收益28%,最大回撤8%,夏普比率2.1,胜率58%。

2. 股票日内事件驱动策略(5分钟级别)

  • 数据输入:30分钟历史价格数据 + 实时新闻流(如公司公告、行业政策)。
  • 模型设计:多模态Transformer(数值编码器+文本编码器),文本用金融领域微调的BERT编码,输出未来10分钟的涨跌概率。
  • 信号规则:当新闻情感向量>0.7且模型预测上涨概率>0.65时,在5分钟内分批买入,持仓至当日收盘前30分钟平仓。
  • 回测效果:在A股半导体板块,2024年样本外测试中,事件发生后1小时内介入,平均单次收益0.8%,盈亏比1.8:1。

3. 跨品种套利策略(3分钟级别)

  • 数据输入:豆粕与豆油期货的1分钟数据(价差、成交量、持仓量),以及两者的库存数据比值。
  • 模型设计:双输入Transformer(分别编码豆粕、豆油序列),通过交叉注意力捕捉两者的价差偏离规律,预测未来3分钟价差回归概率。
  • 信号规则:当价差偏离历史均值2个标准差,且模型预测回归概率>0.7时,做多价差(买豆粕、卖豆油)或做空价差,止损设为偏离3个标准差。
  • 回测效果:2023年样本内年化收益15%,最大回撤4%,夏普比率2.5,每笔交易平均持仓20分钟。

四、优化方向:解决Transformer在日内策略中的痛点

  1. 样本外衰减问题:日内市场结构随政策、资金流动变化快,模型易失效。

    • 解决方案:采用增量学习(每周末用新数据微调模型,冻结底层特征提取层,仅更新顶层分类器),结合动态阈值(根据近期胜率调整多空信号的概率阈值,如胜率下降时从0.6提高至0.65)。
  2. 计算实时性:高频策略需在毫秒级生成信号,标准Transformer速度不足。

    • 解决方案:用TensorRT量化模型(从FP32转为FP16),结合GPU并行计算,将单次推理时间压缩至10毫秒内;或采用蒸馏技术,用小模型(如DistilBERT)替代大模型,精度损失<3%但速度提升5倍。
  3. 过拟合风险:日内数据量有限(如1分钟K线每年约240*240=57600条),易过拟合。

    • 解决方案:加入对抗性训练(在输入中注入微小噪声,如价格±0.1%扰动),并采用早停法(监控验证集的夏普比率,下降时停止训练)。

总结

Transformer在日内策略中的核心价值是通过自注意力机制整合多源高频信息,动态捕捉短期市场规律,其优势在多模态融合、长程依赖识别和实时适应性上尤为突出。实际应用中需结合日内数据特性(如周期性、噪声多)优化模型结构,并通过轻量化设计和风险控制确保策略的实盘可行性。随着硬件算力提升和模型轻量化技术的发展,Transformer有望成为日内量化交易的主流工具。

PCA

PCA 是一种常用的降维技术,它通过线性变换将原始数据投影到新的坐标系中,使得新的坐标轴(主成分)是数据方差最大的方向。


好的,我们来把这句话拆解开,用一个非常直观的例子来理解它。

这句话的核心可以分解为三个部分:

  1. PCA是一种降维技术。
  2. 它通过“线性变换”将数据投影到“新的坐标系”中。
  3. 这个新坐标系的特点是:新的坐标轴(主成分)是数据“方差最大”的方向。

用一个形象的比喻来理解:给一团“椭圆形”的点云拍照

想象一下,你面前有一团由很多数据点组成的、在三维空间中漂浮的点云。这团点云的形状不是一个完美的球形,而是一个有点被压扁的“橄榄球”或“椭球”形状。

现在,你的任务是拍一张二维照片(从3D降到2D),要求这张照片尽可能地展现出这团点云的原始形状和分布

你怎么拍?

  • 拍法A(糟糕的拍法): 你从橄榄球的“顶端”或者“尖端”对着它拍。结果是什么?照片上,所有的点都挤在一起,看起来像一个“圆形”的点阵。你完全看不出它原来是个被压扁的椭球。这种拍法丢失了大量信息。

  • 拍法B(最好的拍法): 你从橄榄球的“侧面”,也就是它最长、最舒展的方向,垂直于它进行拍摄。结果是什么?照片上,你能清晰地看到这团点云是一个“椭圆形”的,点与点之间拉得很开,分布得也很清楚。这种拍法最大限度地保留了点云的分布信息。

这个“拍照”的过程,就是PCA的核心思想。

现在,我们把这个比喻和PCA的术语对应起来:

1. 降维 (Dimensionality Reduction)

  • 原始数据: 三维空间中的点云(每个点有 (x, y, z) 三个坐标/特征)。
  • 降维目标: 用一张二维照片来表示它(每个点变成 (u, v) 两个新坐标/特征)。
  • PCA的作用: 找到“最好”的拍照角度,实现从3D到2D的降维,同时信息损失最小。

2. 线性变换 (Linear Transformation) & 新的坐标系 (New Coordinate System)

  • “拍照”这个动作,本质上就是一种“投影”,在数学上就是一种“线性变换”。
  • 原始坐标系: 就是你最初描述点云的 (X, Y, Z) 坐标轴。
  • 新的坐标系: 就是你为了拍出最好照片而找到的那个“新视角”。这个新坐标系的轴不再是 (X, Y, Z),而是:
    • 第一主成分 (PC1): 橄榄球最长的那个方向。这是照片的“横轴”。
    • 第二主成分 (PC2): 与PC1垂直(正交)的、橄榄球第二长(或者说“最宽”)的那个方向。这是照片的“纵轴”。
    • 第三主成分 (PC3): 与PC1和PC2都垂直的、橄榄球最短(或者说“最扁”)的那个方向。

PCA做的就是帮你找到 PC1, PC2, PC3 这三个新的、更有效率的坐标轴。

3. 方差最大的方向 (Direction of Greatest Variance)

这是理解PCA最关键的一点。

  • 什么是方差? 方差衡量的是数据的“离散程度”或“分散程度”。方差越大,数据点分布得越开,包含的信息就越多。
  • “方差最大的方向”是什么意思?
    • 回到橄榄球的比喻。你在哪个方向上能看到点与点之间被拉得最开、分布得最广?显然是沿着橄榄球最长的那个轴的方向。这个方向就是“方差最大的方向”
    • 因此,第一主成分 (PC1) 就是数据方差最大的方向
  • 为什么这很重要?
    • 因为方差越大,代表数据在这个方向上的差异性越大,信息量也越丰富。
    • PCA的目标就是首先抓住数据“最主要”的变化方向(PC1),然后抓住次要的变化方向(PC2),以此类推。
    • 在降维时,我们优先保留方差大的主成分(比如PC1和PC2),舍弃方差小的主成分(比如PC3,因为从这个方向看,点都挤在一起,没什么信息)。这样就能在减少数据维度的同时,最大程度地保留原始数据的信息。

总结一下

再读一遍原始定义:

PCA是一种常用的降维技术,它通过线性变换将原始数据投影到新的坐标系中,使得新的坐标轴(主成分)是数据方差最大的方向。

我们可以这样“翻译”:

PCA能帮你给高维数据“降维打击”(比如从3D降到2D)。它的方法是:不再使用原来平平无奇的坐标系(如X,Y,Z),而是为数据“量身定做”一个新的坐标系。这个新坐标系的**第一根轴(PC1)会指向数据分布最“伸展”、最“散开”**的方向(即方差最大的方向),第二根轴(PC2)会指向次一等伸展的方向,且与第一根轴垂直…以此类推。最后,我们只保留前面几个最重要的轴,丢掉后面的,就完成了信息损失最小的降维。

什么是好的损失函数?

这是个非常关键且进阶的问题,涉及到损失函数在优化过程中的“可训练性”与“收敛性”特性。一个好的损失函数,不仅要表达目标,还要支持高效、稳定的优化。我们可以从以下几个角度来定义“好”的损失函数。


✅ 一个好的损失函数应具备的性质

属性 是否必须 理由
可导性(至少一阶) ✅ 必须 用于梯度下降等优化算法
连续性(光滑性) ✅ 非常重要 避免震荡、跳跃式优化
凸性或局部凸性 ⚠️ 推荐 保证收敛到全局/局部最优,减少陷入坏局部最小值的风险
良好的梯度分布 ✅ 必须 避免梯度消失/爆炸,提升学习效率
二阶可导(Hessian 存在) ⚠️ 非必须,但有利 对于牛顿法、优化收敛分析很有帮助
平滑梯度变化(Lipschitz 连续性) ⚠️ 建议有 确保训练稳定,便于理论分析
与目标评估指标一致性 ✅ 非常关键 如果训练目标(损失)和测试指标(如准确率)差别太大,训练方向可能跑偏

🔧 关于梯度分布

理想的梯度特性:

特性 说明
非零梯度区域广泛 模型在大多数样本上都能得到有意义的更新(不像 MAE 在平坦区域几乎不给梯度)
梯度尺度适中 避免梯度爆炸(如对数极限处)或梯度消失(如 sigmoid 输出尾部)
梯度方向稳定 不会频繁震荡,方向一致性强,利于收敛

示例对比:

  • 交叉熵 + softmax:梯度方向稳定,分布均匀 → 优秀
  • MAE:梯度恒定,对误差大小不敏感 → 收敛慢
  • Focal Loss:小概率样本梯度大,大概率样本梯度小 → 适合类不平衡

📐 二阶导数(Hessian)有什么用?

用途 是否必要
牛顿法/二阶优化 ✅ 需要
训练曲率分析 ✅ 有利
Loss Landscape 可视化 ✅ 依赖
自适应学习率调节(如 RMSProp, Adam) ❌ 不直接依赖

说明:

  • 大多数现代优化器(如 SGD、Adam)只用一阶导数

  • 但了解二阶导数可以帮助:

    • 分析收敛速度
    • 判断某点是鞍点/最小值/最大值
    • 评估“损失曲面”是否陡峭、平滑等

🚫 不好的损失函数有哪些问题?

问题 表现
不可导 训练过程无法反向传播
梯度为常数或消失 无法学习微小误差变化
非凸且极小值过多 优化过程不稳定、易陷局部最优
数值不稳定 出现 NaN、过拟合、震荡现象

✅ 总结一句话:

一个好的损失函数应当是光滑的、可导的(最好一阶甚至二阶),拥有合理梯度分布,且其最小化能真正推动我们想要的性能指标提升。

用 ticks 数据做量化

字段名 说明 字段类型
time 时间 float
open 当日开盘价 float
current 当前价 float
high 截至到当前时刻的日内最高价 float
low 截至到当前时刻的日内最低价 float
volume 累计成交量 float
money 累计成交额 float
a1_v~a5_v 五档卖量 float
a1_p~a5_p 五档卖价 float
b1_v~b5_v 五档买量 float
b1_p~b5_p 五档买价 float
现在能达到一个股票的ticks数据,如何训练一个量化模型来实现盈利


要用你提供的tick数据训练一个量化交易模型实现盈利,这其实是一个系统性工程,涉及数据处理、特征工程、策略建模、回测、风控和实盘部署等步骤。

以下是一个完整的流程框架,帮助你从tick数据到盈利模型:


✅ 1. 数据准备

数据特点

你的tick数据字段包括:

  • 行情基础数据time, open, current, high, low

  • 成交量相关volume, money

  • 盘口数据

    • 卖五档:a1_v ~ a5_v, a1_p ~ a5_p
    • 买五档:b1_v ~ b5_v, b1_p ~ b5_p

✅ 2. 特征工程(Feature Engineering)

基于tick数据构造有预测意义的特征:

🧠 常用特征包括:

  • 价格类

    • 当前价与开盘价的比值:(current - open)/open
    • 当前价距离当日最高/最低的百分比
    • 盘口中位价(mid-price):(b1_p + a1_p)/2
    • 买卖价差(spread):a1_p - b1_p
  • 成交量类

    • 每笔成交量的变化率(delta_volume
    • 成交额/成交量比(反映平均成交价)
  • 盘口压力特征

    • 买一/卖一挂单量的差值:b1_v - a1_v
    • 买五档总量 vs 卖五档总量:sum(b1_v~b5_v) - sum(a1_v~a5_v)
    • 买一档挂单压制(反映支撑):b1_v / total_volume
  • 资金流向指标

    • 主动买入或卖出估算(可借助price变化和盘口对比推断)

✅ 3. 标签设计(监督学习)

你需要一个预测目标(也叫标签),例如:

📌 预测未来收益:

1
label = future_return = (price[t+N] - price[t]) / price[t]
  • 比如设 N = 20 ticks,你就预测未来20个tick的收益

  • 设一个阈值,变成分类问题:

    • label = 1(涨), 0(平), -1(跌)

✅ 4. 模型选择

📈 常见模型选择:

  • 传统机器学习:

    • LightGBM / XGBoost
    • Random Forest
    • Logistic Regression
  • 深度学习:

    • LSTM / Transformer(用于时间序列)
    • CNN(可视化盘口特征)

✅ 5. 策略构建(Signal to Trade)

模型只是给出买入/卖出信号,还需要构建交易策略:

🚀 示例策略:

  • 如果预测涨幅概率 > 0.6 → 做多
  • 如果预测跌幅概率 > 0.6 → 做空
  • 否则不交易

加上风控:

  • 每笔最多亏损X%
  • 单日最多交易N次

✅ 6. 回测系统(Backtesting)

你需要搭建或使用一个支持tick级别的回测框架,例如:

  • bt, backtrader, rqalpha, 或自建系统
  • Tick级回测需要考虑滑点、交易延迟、挂单队列等

✅ 7. 实盘部署

技术栈建议:

  • 数据流 → Kafka / Redis
  • 模型预测 → Python + FastAPI 服务
  • 下单接口 → 接券商 API / 模拟接口

✅ 8. 风险控制

非常重要,策略再好不风控都会爆:

  • 单笔最大损失控制
  • 最大持仓时间
  • 波动率监控(防止突发事件)

✅ 9. 评估指标

衡量策略的盈利能力和稳定性:

指标 含义
Sharpe Ratio 风险收益比
Win Rate 胜率
Max Drawdown 最大回撤
PnL 净利润
Turnover 换手率

✅ 示例工具链推荐

环节 工具
数据处理 Pandas, NumPy
特征处理 Sklearn, Featuretools
模型训练 LightGBM, PyTorch
回测 Backtrader, Qlib
实盘 fastapi + websocket + broker API

如果你愿意,我可以:

  • 给你写一个示例代码(比如用LightGBM做tick预测)
  • 或帮你设计一个最简tick策略+回测框架

两样本假设检验

当然!让我帮你解释一下 Two Sample Hypothesis Testing(两样本假设检验)


什么是两样本假设检验?

两样本假设检验是统计学中用来比较两个独立样本是否来自同一个总体分布,或者它们的均值、比例等参数是否存在显著差异的统计方法。


什么时候用?

  • 比较两个群体的均值,比如治疗组和对照组的效果。
  • 比较两个群体的比例,比如两个城市吸烟率是否不同。
  • 总体分布未知但想检验两个样本是否来自同一分布。

基本步骤

  1. 提出假设

    • 零假设 $H_0$:两个总体参数相等(例如,均值相等 $\mu_1 = \mu_2$)
    • 备择假设 $H_a$:两个总体参数不等(例如,均值不等 $\mu_1 \neq \mu_2$)
  2. 选择检验统计量

    • 对均值差异常用t检验(Student’s t-test)
    • 对比例差异用Z检验
    • 也有非参数检验(如Mann-Whitney U检验)
  3. 计算统计量并求p值

    • 统计量衡量样本数据偏离零假设的程度
    • p值表示在零假设为真的前提下,观察到样本数据或更极端数据的概率
  4. 做出决策

    • 如果p值 < 预设显著水平(如0.05),拒绝零假设,认为两样本差异显著
    • 否则不拒绝零假设,无法确认差异显著

举例:两独立样本t检验

假设有两组样本 $X_1, \dots, X_{n_1}$ 和 $Y_1, \dots, Y_{n_2}$,想比较均值是否相等:

  • 计算样本均值 $\bar{X}, \bar{Y}$,样本方差 $s_X^2, s_Y^2$
  • 计算t统计量:

$$
t = \frac{\bar{X} - \bar{Y}}{\sqrt{\frac{s_X^2}{n_1} + \frac{s_Y^2}{n_2}}}
$$

  • 查t分布表得到p值,判断是否拒绝$H_0: \mu_X = \mu_Y$

关键点

  • 独立样本:两个样本互不相关
  • 假设检验是概率推断,不是确定性结论
  • 样本量和样本方差影响检验的统计功效(power)
  • 可以选择单尾或双尾检验,取决于备择假设

我们来推一下 t统计量公式,为什么它是

$$
t = \frac{\bar{X} - \bar{Y}}{\sqrt{\frac{s_X^2}{n_1} + \frac{s_Y^2}{n_2}}}
$$


1. 假设条件

我们先假设:

  1. 两个总体 $X$ 和 $Y$ 独立
  2. 总体均值分别是 $\mu_X, \mu_Y$
  3. 总体方差分别是 $\sigma_X^2, \sigma_Y^2$(先考虑已知的情况)
  4. 零假设 $H_0$:$\mu_X = \mu_Y$(均值差为 0)

2. 样本均值的分布

样本均值 $\bar{X}$ 和 $\bar{Y}$ 都是随机变量:

  • $\bar{X} \sim N\left(\mu_X, \frac{\sigma_X^2}{n_1}\right)$
  • $\bar{Y} \sim N\left(\mu_Y, \frac{\sigma_Y^2}{n_2}\right)$

因为样本独立,所以差值 $\bar{X} - \bar{Y}$ 的分布是:

$$
\bar{X} - \bar{Y} \sim N\left( \mu_X - \mu_Y, \frac{\sigma_X^2}{n_1} + \frac{\sigma_Y^2}{n_2} \right)
$$


3. 构造标准化统计量(已知方差)

如果我们知道 $\sigma_X^2, \sigma_Y^2$,那么检验统计量可以写为:

$$
Z = \frac{(\bar{X} - \bar{Y}) - (\mu_X - \mu_Y)}{\sqrt{\frac{\sigma_X^2}{n_1} + \frac{\sigma_Y^2}{n_2}}}
$$

在零假设下 $\mu_X - \mu_Y = 0$,这个 $Z$ 服从标准正态分布 $N(0,1)$。


4. 实际中方差未知

现实中我们通常不知道 $\sigma_X^2, \sigma_Y^2$,只能用样本方差 $s_X^2, s_Y^2$ 去估计:

$$
\widehat{\mathrm{SE}} = \sqrt{\frac{s_X^2}{n_1} + \frac{s_Y^2}{n_2}}
$$

于是统计量变成:

$$
t = \frac{\bar{X} - \bar{Y}}{\sqrt{\frac{s_X^2}{n_1} + \frac{s_Y^2}{n_2}}}
$$


5. 为什么叫 t 而不是 z?

因为我们用样本方差估计总体方差,这个标准化后的比值不再精确服从正态分布,而是服从 t分布(自由度由 Welch’s 方法或 pooled 方法计算)。
当样本量很大时,t分布会趋近于正态分布。


直观理解

  • 分子:观测到的均值差
  • 分母:这个差的“标准差”(标准误)
  • 比值越大,说明均值差异相对波动越显著 → 越容易拒绝零假设

解释标准化统计量

1. 什么是统计量?

统计量(statistic)就是用样本数据计算出来的数值,不依赖未知的总体参数。例如:

  • 样本均值 $\bar{X}$
  • 样本方差 $s^2$
  • 样本比例 $\hat{p}$

它们是用来估计总体特征、或者做假设检验的工具。


2. 什么是标准化?

标准化(standardization)的意思是:

把一个随机变量变换成均值为 0、方差为 1的变量。

常见公式是:

$$
Z = \frac{\text{原变量} - \text{均值}}{\text{标准差}}
$$

这样做的目的是:

  • 消除量纲(不同单位/尺度可以比较)
  • 把变量转化成可直接和标准分布(如标准正态分布)比较的形式

3. 标准化统计量的定义

在假设检验里,我们会计算一个统计量(比如均值差、比例差),然后:

  1. 减去它在零假设下的理论均值
  2. 除以它的标准差(或标准误 SE)

结果就是标准化统计量

公式:

$$
\text{标准化统计量} = \frac{\text{样本统计量} - \text{零假设下的期望值}}{\text{零假设下的标准误}}
$$


4. 为什么要标准化?

  • 不同样本数据的波动幅度不同,直接比较不公平
  • 标准化后,统计量变成了**“差异有多少个标准差”**的度量
  • 标准化统计量有已知分布(正态、t、卡方等),我们可以用它来计算 p 值、做决策

5. 直观例子

假设我们检验均值:

  • 样本均值差 = 5
  • 标准误 = 2

标准化统计量:

$$
t = \frac{5 - 0}{2} = 2.5
$$

意思是:样本均值差比零假设下的期望值高了 2.5 个标准差
标准差越小,差值显著性越大。


解释 正态、t、卡方

1. 正态分布(Normal Distribution)

  • 形状:经典的“钟形曲线”,对称、单峰。
  • 参数:均值 $\mu$(位置)和标准差 $\sigma$(宽度)。
  • 公式

$$
f(x) = \frac{1}{\sqrt{2\pi}\sigma} e^{-\frac{(x-\mu)^2}{2\sigma^2}}
$$

  • 用途

    • 自然界和社会中很多现象近似服从正态分布(身高、测量误差等)
    • 在样本量大时,中心极限定理保证样本均值近似正态
  • 标准正态分布:均值 0、方差 1,记作 $N(0,1)$


2. t分布(Student’s t-distribution)

  • 来源:当总体方差未知,用样本方差去估计,标准化统计量不再精确服从正态,而是服从 t 分布。
  • 定义

$$
t = \frac{\bar{X} - \mu_0}{S / \sqrt{n}}
$$

其中 $S$ 是样本标准差。

  • 参数:自由度(df, degrees of freedom),通常是 $n-1$。

  • 特性

    • 形状类似正态分布,但尾部更厚(小样本时更保守)
    • 随着自由度增加,t分布逐渐接近正态分布
  • 用途

    • 小样本均值检验
    • 构造均值的置信区间(方差未知)

3. 卡方分布(Chi-square distribution)

  • 来源:如果 $Z_1, Z_2, \dots, Z_k$ 是独立的标准正态变量,那么:

$$
\chi^2 = Z_1^2 + Z_2^2 + \dots + Z_k^2
$$

服从自由度为 $k$ 的卡方分布。

  • 参数:自由度 $k$。

  • 特性

    • 取值范围 $[0, \infty)$(只在非负区间有密度)
    • 自由度越大,分布越接近正态
  • 用途

    • 方差的假设检验(例如总体方差检验)
    • 拟合优度检验(Goodness-of-fit)
    • 列联表的独立性检验

4. 三者关系

它们其实是同一个家族的“表亲”:

  • t分布:由一个标准正态变量除以卡方变量的平方根得到:

$$
t = \frac{Z}{\sqrt{\chi^2 / k}}
$$

  • 卡方分布:是若干个独立标准正态平方和的分布
  • 正态分布:是这三者的基础,t分布和卡方分布都是由正态推出来的

解释自由度

1. 自由度的直观含义

自由度可以理解为:

在计算某个统计量时,数据中有多少个独立的信息可以自由变化

一旦你引入了约束(比如用数据本身估计了某个参数),就会“损失”一部分自由度。


2. 一个简单例子

假设你有 3 个数,它们的平均值是固定的 10。

  • 第一个数可以任意取值
  • 第二个数也可以任意取值
  • 但第三个数就不自由了,必须由前两个数决定(保证均值为 10)。

所以:

  • 总共有 3 个数据点
  • 约束条件占掉了 1 个自由度
  • 剩下的自由度是 $3 - 1 = 2$

3. 常见统计中的自由度

(1) 样本方差

样本方差的公式:

$$
s^2 = \frac{\sum_{i=1}^n (x_i - \bar{x})^2}{n-1}
$$

为什么是 $n-1$?
因为在计算 $x_i - \bar{x}$ 时,$\bar{x}$ 是用数据本身算的,所以有一个约束 $\sum (x_i - \bar{x}) = 0$,损失了 1 个自由度。


(2) t 分布的自由度

单样本 t 检验:

  • 自由度 $df = n - 1$(因为估计了均值)

双样本 t 检验:

  • 等方差假设:$df = n_1 + n_2 - 2$(估计了两个均值和一个共同方差)
  • Welch’s t 检验:自由度公式更复杂,是加权方差的结果

(3) 卡方分布的自由度

  • 如果是正态平方和的卡方分布,自由度就是平方和的项数
  • 拟合优度检验中:

$$
df = \text{类别数} - 1 - \text{估计的参数个数}
$$

(因为总概率为 1,且部分概率由模型参数决定)


4. 直观类比

可以把自由度想象成:

  • 你有 n 根独立的绳子
  • 如果用 1 根绳子固定了某个位置(约束条件),剩下的绳子可以随便动的数量就是自由度
  • 约束越多,自由度越少

为什么样本均值的方差要除以 n, 以及均值差的方差是两个值的和?


1. 为什么样本均值的方差要除以 $n$?

假设总体是

$$
X_1, X_2, \dots, X_n \stackrel{\text{i.i.d.}}{\sim} N(\mu_X, \sigma_X^2)
$$

样本均值定义:

$$
\bar{X} = \frac{1}{n} \sum_{i=1}^n X_i
$$

方差的性质

  • $\mathrm{Var}(aZ) = a^2 \mathrm{Var}(Z)$
  • 独立变量的方差可加:$\mathrm{Var}(Z_1 + Z_2) = \mathrm{Var}(Z_1) + \mathrm{Var}(Z_2)$

计算:

$$
\mathrm{Var}(\bar{X}) = \mathrm{Var} \left( \frac{1}{n} \sum_{i=1}^n X_i \right)
$$

$$
= \frac{1}{n^2} \sum_{i=1}^n \mathrm{Var}(X_i)
$$

因为每个 $X_i$ 的方差都是 $\sigma_X^2$:

$$
= \frac{1}{n^2} \cdot n \sigma_X^2
$$

$$
= \frac{\sigma_X^2}{n}
$$

所以样本均值的方差会比单个样本的方差小 $n$ 倍,因为取均值降低了波动。


2. 为什么差值的方差是两个方差的和?

我们有两个样本均值:

$$
\bar{X} \sim N\left(\mu_X, \frac{\sigma_X^2}{n_1}\right)
$$

$$
\bar{Y} \sim N\left(\mu_Y, \frac{\sigma_Y^2}{n_2}\right)
$$

假设两组样本独立,考虑:

$$
D = \bar{X} - \bar{Y}
$$

方差运算:

$$
\mathrm{Var}(D) = \mathrm{Var}(\bar{X} - \bar{Y})
$$

因为方差对常数乘法敏感,但对符号无所谓($\mathrm{Var}(-Z) = \mathrm{Var}(Z)$),并且 $\bar{X}$ 和 $\bar{Y}$ 独立:

$$
= \mathrm{Var}(\bar{X}) + \mathrm{Var}(\bar{Y})
$$

$$
= \frac{\sigma_X^2}{n_1} + \frac{\sigma_Y^2}{n_2}
$$

所以两个独立随机变量的差的方差,等于它们方差的和。


3. 总结

  • 除以 $n$:因为取均值相当于缩放了数据,方差会缩小 $n$ 倍
  • 方差相加:因为独立随机变量的方差是可加的,不管是加还是减

word2vec

Here’s how CBOW word2vec works step by step:

Choose a context window (e.g. 2 in the image above)
Take the two words before and two words after a particular word as input
Encode these four context words as one-hot vectors
Pass the encoded vectors through the hidden layer, which has a linear activation function that outputs the input unchanged
Aggregate the outputs of the hidden layer (e.g. using a lambda mean function)
Feed the aggregated output to the final layer which uses Softmax to predict probabilities for each possible word
Select the token with the highest probability as the final output of the network

详细解释这个过程,用中文


下面用通俗+一点点公式把 CBOW(Continuous Bag-of-Words)版 word2vec 的训练过程完整解释一遍,并顺手纠正一个常见误解:隐藏层虽是线性的(恒等激活),但它不是“输出输入不变”,而是通过权重矩阵把独热向量投影到低维“词向量”空间。

核心直觉

给定目标词周围的上下文词(一个窗口内的若干个词),用这些上下文的向量平均/求和,再去预测中心词。训练好后,你得到的就是每个词的稠密向量(embedding),它们在语义上会“靠近相似、远离不相似”。


逐步过程(对应你列的步骤)

  1. 选定上下文窗口
    窗口大小 window = 2 意味着每个目标词左右各取 2 个词作为上下文。句首/句尾不够就少取(或用特殊 PAD 符号)。

  2. 构造一个训练样本
    对句子里每个位置的中心词 $w_t$,取它左右的上下文 ${c_1,\dots,c_M}$(通常 $M=2!\times!window$,遇到边界会变小)。

  3. 把上下文词做成独热向量(one-hot)
    词表大小 $V$。每个上下文词 $c_i$ 编码成 $\mathbf{x}_{c_i}\in\mathbb{R}^V$,只有该词的索引位置为 1,其余为 0。

  4. 经过“隐藏层”:从独热到词向量(线性投影/查表)
    隐藏层是一组权重矩阵 $W\in\mathbb{R}^{V\times d}$(无偏置、激活为恒等)。
    把独热向量乘以 $W$:

$$
\mathbf{h}{c_i} ;=; \mathbf{x}{c_i}^{\top} W
$$

因为 $\mathbf{x}{c_i}$ 只有一个 1,这一步等价于直接取出 $W$ 的第 $c_i$ 行——也就是上下文词 $c_i$ 的词向量 $\mathbf{e}{c_i}\in\mathbb{R}^d$。

这就是“线性但不是原样输出”的原因:输入是高维独热,输出是低维词向量(查表)。

  1. 聚合上下文向量(求和/平均)
    把所有上下文词向量 ${\mathbf{h}_{c_i}}$ 聚合:

$$
\mathbf{h} ;=; \frac{1}{M}\sum_{i=1}^{M}\mathbf{h}_{c_i}
$$

(你提到的 “lambda mean” 本质就是取平均;有些实现用“求和”,两者效果相近,平均更稳定些。)

  1. 输出层 + Softmax 得到对所有词的概率
    输出层再乘另一个矩阵 $U\in\mathbb{R}^{d\times V}$(可带偏置 $\mathbf{b}$):

$$
\mathbf{z} ;=; \mathbf{h}U + \mathbf{b},\qquad
p(w\mid context) ;=; \text{softmax}(\mathbf{z})
$$

Softmax 把分数 $\mathbf{z}$ 变成对整个词表的概率分布。

  1. 选最大概率词作预测
    $\arg\max$ 就是网络当前认为的中心词。如果只是“推断”,停在这里即可;如果是训练,还要计算损失并反向传播更新参数。

训练目标与反向传播

  • 目标:让真实中心词 $w_t$ 的概率尽量大。
    典型损失是交叉熵:

    $$
    \mathcal{L} ;=; -\log p(w_t\mid context)
    $$

  • 更新的参数

    • 输入矩阵 $W$(上下文词对应的那些行会被更新);
    • 输出矩阵 $U$(目标词的那一列,以及被采样到的词列会被更新)。
  • 高效训练技巧
    直接对全词表做 Softmax 成本高($V$ 很大)。常用两招:

    • 负采样(Negative Sampling):把多类 Softmax 变成若干个二分类(正样本=真实目标词,负样本=随机词),用 sigmoid 损失,极大地加速训练。
    • 分层 Softmax(Hierarchical Softmax):把词表组织成哈夫曼树,预测路径上的一串二分类,计算量降为 $\mathcal{O}(\log V)$。

训练时滑动窗口在语料上移动:不断“用上下文预测中心词”,反复更新,直到收敛。


直观小例子(极简)

  • 词表:{“我”, “爱”, “北京”, “天安门”}($V=4$),嵌入维度 $d=2$。
  • $W$ 是 $4\times 2$ 矩阵。独热向量乘 $W$ 就等于“查出该词的 2 维向量”。
  • 句子 “… 我 爱 北京 天安门 …”,窗口=1,拿“北京”做中心:上下文是 {“爱”, “天安门”}。
  • 查出这两个词的向量,取平均,过输出层算到 4 个词的分数,做 Softmax。
  • 若真实中心词是“北京”,就把“北京”的概率推高,更新 $W$ 的“爱”“天安门”两行,以及 $U$ 的“北京”那一列(或负采样到的列)。

训练完你得到了什么?

  • 词向量:通常取输入矩阵 $W$ 的每一行作为词的 embedding(有些实现也会把 $W$ 和 $U^\top$ 平均)。
  • 性质:相似词的向量会靠近;向量之间的余弦相似度常用于度量语义相近度;还会出现近似的向量运算关系(如类比)。

一些实现细节与经验

  • 窗口大小:大窗口更偏“主题/语义”,小窗口更偏“搭配/句法”。训练时可随机化窗口长度提升鲁棒性。

  • 子采样(subsampling):对高频词(如“的”“了”)按频率丢弃一部分,既提速又提升向量质量。

  • CBOW vs Skip-gram

    • CBOW:用上下文预测中心词,更快,对高频词表现好;
    • Skip-gram:用中心词预测上下文,对低频词更友好
  • OOV 词:不在词表的词通常映射为 <UNK>;或在子词模型(BPE、WordPiece)里用子词向量缓解。

  • 归一化:下游相似度常用向量 L2 归一化后做 cosine。


小结(把你的步骤串起来)

  • 选窗口 → 取上下文 → 独热编码 → 线性投影成词向量(查表) → 求平均/求和 → 输出层打分 → Softmax 得到分布 → 取最大者为预测;
  • 训练时用交叉熵/负采样等更新 $W,U$,最终 $W$ 的每一行就是学到的词向量。

第5步中的M不知道是啥意思,是词表的大小吗,还是句子中单词的个数,我i什么取平均不明白,是用了啥数学性质么?


好问题 👍。这里的 $M$ 很容易让人混淆,我给你详细拆开解释:


1. $M$ 是什么?

第5步“聚合上下文向量” 里,$M$ 表示的是 当前中心词的上下文中包含的词数,而不是词表大小 $V$,也不是整个句子长度。

  • 如果你的窗口大小是 2(左右各两个),在句子中间位置,理论上上下文就有 $M=4$ 个词。
  • 如果中心词在句子开头/结尾,可能不够,比如只有左边 1 个、右边 2 个,那 $M=3$。
  • 所以 $M$ 随位置变化,是“上下文词的个数”。

2. 为什么要求平均(除以 $M$)?

如果只是把上下文词向量直接 相加,那么:

  • 当 $M=4$ 时,和 $M=2$ 时,得到的向量尺度(数值大小)就不一样。
  • 网络在学习时会“受词数多少影响”,训练不稳定。

👉 为了让不同位置(不同上下文长度)的向量具有相同的量纲/尺度,我们把总和除以上下文词数 $M$,得到平均值。这样:

$$
\mathbf{h} = \frac{1}{M} \sum_{i=1}^M \mathbf{h}_{c_i}
$$

就保证了:

  • 不管上下文有几个词,$\mathbf{h}$ 的“数值范围”大致稳定。
  • 模型学到的 embedding 不会因为上下文长短而偏移。

3. 是用了什么数学性质吗?

不是什么特殊的数学定理,其实就是**归一化(normalization)**的思想。
简单说:

  • “平均” = “先求和,再除以个数”,是一种缩放操作
  • 它保证不同上下文长度时,输入向量的尺度可比,不会随 $M$ 改变而放大/缩小。

所以:

  • 用和:模型能学,但会更依赖窗口大小。
  • 用平均:更常见,更稳健。

4. 小例子直观感受

假设 embedding 维度 $d=2$,

  • “爱” = (2, 0),

  • “北京” = (0, 2),

  • “天安门” = (1, 1)。

  • 如果上下文 = {“爱”, “北京”},求和 = (2,0)+(0,2)=(2,2)。

  • 如果上下文 = {“爱”, “北京”, “天安门”},求和 = (3,3),数值更大。

👉 直接喂给网络,数值大小随上下文数量变化。
👉 如果改成平均:

  • 两个词平均 = (1,1),
  • 三个词平均 = (1,1),尺度一致,更好学习。

✅ 总结一句:

  • $M$ = 当前中心词上下文的单词数。
  • 平均不是特殊定理,而是归一化,让输入尺度不受上下文长度影响。

MAC 自动化

https://github.com/sveinbjornt/Platypus?tab=readme-ov-file
https://github.com/Hammerspoon/hammerspoon?tab=readme-ov-file

sort 外部排序

有3个csv文件,如何只取它们的第一列,合并并去除重复后生成一个新的csv。备注:csv很大,每个文件几亿行,内存放不下

pv file1.csv file2.csv file3.csv | cut -d',' -f1 | sort -u -T /path/to/tmp -S 2G > merged_unique.csv

pv -l -s $(wc -l file1.csv file2.csv file3.csv | awk '!/total/{s+=$1} END {print s}') \
   file1.csv file2.csv file3.csv \
| cut -d',' -f1 \
| tr -d '\r' \
| sort -u -T /path/to/tmp -S 2G > merged_unique.csv

vega和vol的关系为啥不是单调递增函数呢?

这是个很好的观察 👌
直觉上可能觉得「波动率越大,Vega 应该越大」,但实际上 Vega 和波动率并不是单调递增关系。原因在于 Black-Scholes 定价公式里的结构


1. Vega 的公式

$$
Vega = S \cdot \phi(d_1) \cdot \sqrt{T}
$$

其中

$$
d_1 = \frac{\ln(S/K) + (r + \tfrac{1}{2}\sigma^2)T}{\sigma\sqrt{T}}, \quad \phi(d_1)=\frac{1}{\sqrt{2\pi}}e^{-\tfrac{1}{2}d_1^2}
$$

所以 Vega 的关键取决于 $\phi(d_1)$,而 $\phi(d_1)$ 在 $|d_1|$ 较小时最大(即 $d_1=0$ 时最大)。


2. 当波动率 σ 较小时

  • 分母 $\sigma \sqrt{T}$ 很小 → $d_1$ 可能特别大或特别小(取决于 $S/K$ 的关系)。
  • 这会导致 $\phi(d_1)$ 接近 0 → Vega 很小。

直观上:如果波动率几乎为 0,期权价格几乎固定,价格对波动率变化就“不敏感”,所以 Vega 接近 0。


3. 当波动率 σ 适中时

  • $d_1$ 可能落在 0 附近(特别是 平值期权,即 $S \approx K$)。
  • 这时 $\phi(d_1)$ 最大,Vega 也达到峰值。

所以 Vega 在中等波动率时最大


4. 当波动率 σ 很大时

  • 分母 $\sigma \sqrt{T}$ 很大 → $d_1$ 逼近 0。
  • 这时候虽然 $\phi(d_1)$ 接近最大值 $1/\sqrt{2\pi}$,但注意 Vega 里还有一项 $\sqrt{T}$(固定不变) → 为什么还会下降呢?

关键在于:

  • 当 $\sigma$ 过大时,期权价格已经接近标的价格的一半(因为行权概率几乎变成 50%),继续增加波动率,对价格的边际影响减小。
  • 从概率分布角度看,过高波动率让收益分布「摊平」,价格曲线趋于饱和,Vega 自然下降。

5. 总结直觉

  • 低 σ → Vega 小(期权价格几乎不动,对 σ 不敏感)。
  • 中等 σ → Vega 最大(特别是平值期权)。
  • 高 σ → Vega 又下降(因为价格变化趋于饱和)。

👉 所以,Vega 和波动率的关系呈现一个“凸起”的形状,而不是单调递增函数

为什么平值期权的theta的绝对值最大,而虚值和实值的时间价值流逝较慢?

问得很到位 👍,这个涉及到 期权时间价值 (time value) 的核心逻辑。我们来分步骤解释:


1. 期权价格的组成

期权价格 = 内在价值 (intrinsic value) + 时间价值 (time value)

  • 内在价值:看涨期权 $\max(S-K, 0)$,看跌期权 $\max(K-S, 0)$
  • 时间价值:市场愿意为「未来可能更有利」的机会付出的额外溢价。

Theta 衡量的是期权价格随时间流逝的变化率。换句话说:

$$
\Theta = \frac{\partial C}{\partial t}
$$

它大多数时候是负的(时间流逝使期权贬值),我们一般说 Theta 是时间价值的衰减速率


2. 平值期权 (ATM) 的特点

  • 平值期权时,$S \approx K$,未来向上走或向下走的概率最均衡。
  • 这种状态下,期权价格 几乎完全由时间价值构成(内在价值≈0)。
  • 因为「不确定性最大」→ 投资者愿意为这种可能性支付更多溢价 → 时间价值最多。

👉 所以,随着到期日临近,时间价值损耗最快,导致 Theta 绝对值最大


3. 深度实值 (ITM) 期权

  • 深度实值时,期权价格主要是 内在价值,时间价值只占一小部分。
  • 到期时间减少,对内在价值几乎没有影响(标的差不多肯定在行权区间内)。
  • 因此,Theta 较小。

4. 深度虚值 (OTM) 期权

  • 深度虚值时,期权价格几乎全是 时间价值,但这个时间价值本来就接近 0。
  • 时间减少,损耗的金额也很小。
  • 所以,Theta 也比较小。

5. 总结直觉

  • ATM (平值期权):时间价值最多 → 流逝最快 → Theta 绝对值最大。
  • ITM (实值期权):价格主要是内在价值,时间价值少 → Theta 较小。
  • OTM (虚值期权):期权几乎一文不值,损耗的也不多 → Theta 较小。

这就是为什么 Theta 呈现“中间大,两边小”的形状

为什么vega会随到期日增加而增加

好问题 👍,这个涉及 Vega 与到期时间 $T$ 的关系。我们拆开解释一下:


1. Vega 的公式

在 Black–Scholes 模型里:

$$
Vega = S \cdot \phi(d_1) \cdot \sqrt{T}
$$

其中:

  • $S$:标的价格
  • $\phi(d_1)$:标准正态分布的密度函数,取值在 $0 \sim 0.4$ 之间
  • $\sqrt{T}$:到期时间的平方根

2. $\sqrt{T}$ 的作用

  • 当 $T$ 增大时,$\sqrt{T}$ 单调递增 → 直接把 Vega 往上推。
  • 所以,在其他条件不变时,Vega 会随着 $T$ 增加而增加

3. 直觉解释

  • 到期时间短:市场给期权的「未来不确定性」很少,波动率再变动,对价格影响也有限 → Vega 小。
  • 到期时间长:不确定性更大,波动率对未来价格分布影响更显著 → Vega 更敏感。
  • 可以理解为「未来的路还很长,波动率越大,可能走得越偏 → 对价格影响就越大」。

4. 注意 ⚠️

  • 虽然公式里 Vega 随 $\sqrt{T}$ 增加,但它还乘了 $\phi(d_1)$。
  • $\phi(d_1)$ 取决于标的价和执行价的相对位置。如果期权非常深度实值/虚值,$|d_1|$ 很大 → $\phi(d_1)$ 很小 → 这时候即使 $T$ 很长,Vega 也不会无限大。
  • 所以:平值期权 + 长到期时间 → Vega 最大

✅ 总结:

  • Vega 随 $T$ 增大而上升,是因为公式中存在 $\sqrt{T}$,同时长到期增加了未来不确定性,使波动率对期权价格更敏感。
  • 但这种增长在深度实值/虚值时会被抵消。

为啥波动率越低,gamma越高呢?

这个问题问得非常棒 👍,也是很多人第一次学习希腊字母时的困惑。我们来分几个层次解释「为什么波动率越低,Gamma 越高」。


1. Gamma 的公式

在 Black–Scholes 模型下:

$$
\Gamma = \frac{\phi(d_1)}{S \cdot \sigma \sqrt{T}}
$$

其中:

  • $\phi(d_1)$ = 标准正态密度函数(最大值约 0.4,范围在 $0\sim0.4$ 之间)
  • 分母里有 $\sigma \sqrt{T}$

2. 直观推导

  • 波动率 $\sigma$ 在分母:波动率越低,分母越小 → Gamma 越大。
  • $\phi(d_1)$ 在平值期权附近比较大,所以 ATM 的 Gamma 特别敏感。

3. 直觉解释

(1)低波动率时

  • 期权价格曲线(对标的价格的函数)变得更「陡峭」:

    • 因为市场认为标的未来波动不大 → 价格曲线会紧紧围绕执行价弯曲。
    • 所以,Delta 在 $S$ 稍微变动时就会快速变化 → Gamma 高。

(2)高波动率时

  • 期权价格曲线变得更「平滑」:

    • 因为市场认为未来可能性范围很大 → 行权概率分布变宽。
    • Delta 的变化不那么剧烈(更接近线性),Gamma 就低。

4. 总结

  • 低波动率 → 曲线更陡 → Delta 对 $S$ 更敏感 → Gamma 高。
  • 高波动率 → 曲线更平滑 → Delta 变化不剧烈 → Gamma 低。

这也是为什么:

  • 平值期权 + 低波动率 = Gamma 最大
  • 深度实值/虚值期权 = Gamma 接近 0(因为 Delta 已经接近 0 或 1,不太变化)