2026-08-31

PHP / Laravel / 后端 / MySQL / Redis / API / 老项目维护,我建议不要装一大堆 Skills,精选 6~10 个最实用的就够了

Cursor 现在原生支持 Agent Skills,Skill 本质上是 SKILL.md + 可选 references/scripts,Agent 会根据任务自动加载;也可以在 Agent 里通过 / 调用。(Cursor)

最推荐你的 PHP 技能组合

① Laravel Best Practices —— 必装 ⭐⭐⭐⭐⭐

这个最适合你。

目前有一个比较成熟的 Laravel Skill:

agent-laravel-skills

它主要解决:

  • Controller / Service / Model 分层
  • Eloquent
  • FormRequest
  • Policy / Authorization
  • Validation
  • Migration
  • Queue
  • Cache
  • N+1
  • SQL 性能
  • Security
  • Laravel 架构
  • 重构

而且明确支持 Cursor / Codex / Claude Code。(GitHub)

安装:

npx skills add PauloFelipeM/agent-laravel-skills -a cursor

② Laravel/PHP Troubleshooting —— 非常适合你 ⭐⭐⭐⭐⭐

你平时经常遇到:

PHP-FPM
Nginx
Laravel
MySQL
Redis
Docker
权限
队列
数据库
线上异常

我反而非常推荐这种 troubleshooting skill

有一个 Laravel/PHP Skills 项目专门包含:

troubleshooting
troubleshooting-backend
unexpected-situations

其中 troubleshooting-backend 就是针对 Laravel/PHP 后端错误排查。(GitHub)

Laravel/PHP Agent Skills


③ TDD / Pest PHP ⭐⭐⭐⭐

如果你让 Cursor 给 Laravel 项目补测试,这个非常有用。

尤其是:

Service
Repository
Controller
Job
Command
API

可以让 Agent 按:

先写测试
↓
实现
↓
运行 Pest
↓
修复
↓
再次测试

而不是直接给你生成一堆看起来正确、实际上没跑过的代码。

上面的 ceilidhboy/skills 就包含:

tdd-laravel

专门针对 Pest PHP。(GitHub)


④ Laravel Queue ⭐⭐⭐⭐⭐

这个我特别推荐你

因为你做后端,经常会遇到:

Redis Queue
Job
队列并发
失败重试
延迟任务
Batch
Horizon

现在有一个专门的 Laravel AI Skills 项目,把:

Laravel Queues
Laravel Horizon

单独做成 Skills,并且针对 Laravel 11~13。(GitHub)

安装对应 Skill 后,你可以直接告诉 Cursor:

把这个任务改成 Laravel Queue Job,
要求支持失败重试、超时、幂等。

Agent 会更容易按照 Laravel 的正确方式实现。


⑤ Laravel Horizon ⭐⭐⭐⭐⭐

如果你的项目使用:

Redis
Laravel Queue
Horizon

建议和 Queue 一起装。

尤其是生产环境:

supervisor
balance
worker
timeout
retry
failed_jobs

这些东西让普通 AI 很容易胡写。

专门的 Horizon Skill 会比单纯问 Cursor:

“帮我配置 Horizon”

靠谱很多。(GitHub)


⑥ Laravel Data / DTO ⭐⭐⭐⭐

如果你的项目 API 比较多,我推荐。

例如:

UserData
OrderData
ProductData
CreateOrderData
UpdateOrderData

让 Cursor 不要所有东西都:

$request->all()

然后 Controller 里面写一大堆业务逻辑。

目前有专门针对 spatie/laravel-data 的 Skill。(GitHub)


⑦ Laravel Security ⭐⭐⭐⭐⭐

这个我建议你一定加

特别是你这种后端项目,AI 很容易写出:

Model::where('id', $request->id)->first();

然后直接返回。

或者:

$request->all()

批量赋值。

或者:

DB::raw(...)

等等。

Security Skill 可以让 Agent 在:

Authentication
Authorization
Validation
Mass Assignment
SQL Injection
IDOR
权限
敏感数据
API

这些方面多一层检查。

目前也有 Laravel Skills 项目专门把 Security、Testing、Performance、API 等作为不同 preset。(GitHub)


⑧ Laravel Performance ⭐⭐⭐⭐⭐

这个对你尤其有价值。

你以前经常处理:

MySQL
Redis
高并发
SQL
ETL
批处理

所以建议增加:

N+1
Eloquent
SQL
Index
Cache
Queue
Memory

这一类 Skill。

例如官方开源项目里的 Laravel Best Practices Skill,就明确包含:

N+1、query performance、caching、authorization、validation、queue 等检查。(GitHub)

⑨ Git / Code Review ⭐⭐⭐⭐⭐

这个虽然不是 PHP 专属,但是我认为比很多 PHP Skill 都重要

Cursor 官方 Marketplace 目前已经提供类似:

/code-review
/test
/fix-merge-conflicts
/pr

这样的技能/命令。(Cursor)

你的工作流可以变成:

Cursor
  ↓
写代码
  ↓
/test
  ↓
/code-review
  ↓
修复
  ↓
/pr

这个比单纯:

“帮我写 PHP”

强很多。


我给你配一套「PHP 后端开发套餐」

如果是你的开发场景,我会这样装:

                    Cursor
                       │
       ┌───────────────┼───────────────┐
       ↓               ↓               ↓
 Laravel Best      Troubleshooting    Code Review
 Practices
       │
       ├── Security
       ├── Performance
       ├── Testing / Pest
       ├── Queue
       ├── Horizon
       └── DTO / Laravel Data

第一批先装这 6 个

Skill推荐度用途
Laravel Best Practices⭐⭐⭐⭐⭐Laravel 日常开发
Troubleshooting Backend⭐⭐⭐⭐⭐排错
Security⭐⭐⭐⭐⭐安全
Performance⭐⭐⭐⭐⭐SQL/Eloquent/缓存
TDD / Pest⭐⭐⭐⭐自动化测试
Queue / Horizon⭐⭐⭐⭐⭐Redis 队列

还有一个我特别建议你装

Superpowers ⭐⭐⭐⭐⭐

Cursor 官方 Marketplace 已经有经过 Cursor 验证的 Superpowers Skill 集合。里面包括:

brainstorming
dispatching-parallel-agents
executing-plans
finishing-a-development-branch
receiving-code-review

等等。(Cursor)

这个不是 PHP 专用,但是对于你这种经常让 AI 改后端项目的人非常有用。

例如你说:

给这个 Laravel 项目增加订单批量导入。

普通 AI 很可能:

直接开始改代码

Superpowers 更倾向于:

分析需求
   ↓
理解项目
   ↓
制定方案
   ↓
拆任务
   ↓
实现
   ↓
测试
   ↓
Review

对于老 PHP 项目尤其有价值。


如果是我帮你配置 Cursor

我不会安装几十个 Skill。

我会给你配置:

① Laravel Best Practices
② PHP/Laravel Troubleshooting
③ Security
④ Performance
⑤ Pest/TDD
⑥ Queue
⑦ Horizon
⑧ Superpowers
⑨ Code Review

然后再给你的项目写一个:

.cursor/rules/php-backend.mdc

专门规定:

PHP 8.x
Laravel
MySQL
Redis
Nginx
PHP-FPM

Controller 不写业务
Service 处理业务
Repository 是否使用由项目决定
禁止无意义 Repository
所有 SQL 注意 N+1
大数据量必须考虑 chunk/cursor
Redis Key 必须统一规范
Queue 必须考虑幂等
API 必须验证参数
禁止 $request->all() 直接入库

这一层实际上比装 20 个 Skill 更重要。

2026-08-31

这套配置的目标是让 Cursor 不只是“会写 Yii2”,而是按后端工程师的方式分析、修改、测试和 Review Yii2 项目。

Cursor + PHP + Yii2 Backend Skill

目录结构

.cursor/
├── rules/
│   ├── php.mdc
│   ├── yii2.mdc
│   ├── mysql.mdc
│   ├── redis.mdc
│   ├── api.mdc
│   ├── security.mdc
│   └── testing.mdc
│
└── skills/
    └── yii2-backend/
        ├── SKILL.md
        └── references/
            ├── architecture.md
            ├── database.md
            └── review.md

1. .cursor/rules/php.mdc

---
description: PHP backend development standards
globs:
  - "**/*.php"
alwaysApply: true
---

# PHP Development Rules

## PHP Version

Before writing new PHP code:

1. Inspect composer.json.
2. Determine the project's PHP version.
3. Follow the project's existing PHP syntax and conventions.
4. Do not introduce syntax unsupported by the project's PHP version.

## Type Safety

Prefer:

- strict parameter types
- return types
- nullable types
- typed properties
- enums when supported by the project

Avoid unnecessary mixed values.

Example:

GOOD:

```php
public function getUser(int $id): ?User
{
    return User::findOne($id);
}

Avoid:

public function getUser($id)
{
    return User::findOne($id);
}

unless the existing project intentionally follows weak typing.

Error Handling

Do not silently swallow exceptions.

Bad:

try {
    // ...
} catch (\Throwable $e) {
}

If an exception must be caught:

  • log it
  • add meaningful context
  • either recover or rethrow

Null Handling

Do not assume database queries always return records.

Bad:

$user = User::findOne($id);

return $user->name;

Prefer:

$user = User::findOne($id);

if ($user === null) {
    throw new NotFoundHttpException('User not found.');
}

Code Duplication

Before adding a new helper:

  1. Search the project.
  2. Check whether the functionality already exists.
  3. Reuse existing abstractions when appropriate.

Do not create unnecessary utility classes.

Backward Compatibility

When modifying existing code:

  • preserve existing public method signatures when possible
  • preserve API response formats
  • preserve database behavior
  • avoid unnecessary refactoring
  • avoid changing unrelated files

Dependency Policy

Do not add Composer packages automatically.

Before adding a dependency:

  1. Check whether the project already has equivalent functionality.
  2. Check composer.json.
  3. Explain why the dependency is necessary.
  4. Prefer Yii2/PHP standard functionality when sufficient.

---

# 2. `.cursor/rules/yii2.mdc`

```md
---
description: Yii2 framework architecture and development rules
globs:
  - "**/*.php"
alwaysApply: true
---

# Yii2 Development Rules

## Architecture

Prefer:

Controller
    ↓
Service
    ↓
Model / ActiveRecord
    ↓
Database

Controllers should remain thin.

Controllers are responsible for:

- receiving HTTP parameters
- authentication
- authorization
- request validation
- calling services
- formatting responses

Controllers should NOT contain complex business logic.

## Controller

Avoid:

```php
public function actionCreate()
{
    $model = new Order();

    if ($model->load(Yii::$app->request->post())) {
        // hundreds of lines of business logic
    }
}

Prefer:

public function actionCreate()
{
    $params = Yii::$app->request->post();

    $order = $this->orderService->create($params);

    return $order;
}

Service

Use services for:

  • business workflows
  • transactions
  • cross-model operations
  • external API calls
  • complex business rules
  • queue dispatch
  • multi-step operations

Example:

final class OrderService
{
    public function create(array $params): Order
    {
        return Yii::$app->db->transaction(function () use ($params) {
            // business logic
        });
    }
}

ActiveRecord

Use ActiveRecord for:

  • entity persistence
  • simple queries
  • relationships
  • validation

Avoid putting large business workflows inside ActiveRecord.

ActiveQuery

Prefer readable queries:

Order::find()
    ->where(['status' => Order::STATUS_PENDING])
    ->orderBy(['id' => SORT_DESC])
    ->all();

N+1 Prevention

Always check for N+1 when using relations.

Potentially dangerous:

$orders = Order::find()->all();

foreach ($orders as $order) {
    echo $order->user->name;
}

Prefer:

$orders = Order::find()
    ->with('user')
    ->all();

When modifying relationship-heavy code, inspect the generated SQL if necessary.

Large Dataset

Never blindly use:

Model::find()->all();

for potentially large datasets.

Prefer:

foreach (
    Model::find()->batch(500) as $models
) {
    foreach ($models as $model) {
        // ...
    }
}

or:

foreach (
    Model::find()->each(500) as $model
) {
    // ...
}

updateAll/deleteAll

For large bulk operations consider:

Model::updateAll(
    ['status' => Model::STATUS_DONE],
    ['status' => Model::STATUS_PENDING]
);

and:

Model::deleteAll([
    'status' => Model::STATUS_DELETED,
]);

But check:

  • events
  • behaviors
  • timestamps
  • business rules

because bulk operations bypass normal ActiveRecord lifecycle behavior.

Transactions

Use transactions when multiple writes must succeed or fail together.

Yii::$app->db->transaction(function () {
    // write A
    // write B
});

Do not create unnecessary long transactions.

Do not hold database transactions while waiting for:

  • HTTP requests
  • external APIs
  • long-running jobs
  • user input

Validation

Never trust HTTP input.

Use:

  • rules()
  • scenarios
  • explicit validation
  • typed DTOs when appropriate

Do not blindly persist:

$model->load($request->post());
$model->save();

without checking validation result.

Dependency Injection

For new code prefer dependency injection where practical.

Avoid unnecessary:

Yii::$app->someComponent

inside deeply nested business logic.

Use constructor injection for stable dependencies when compatible with the project architecture.

Existing Project Conventions

Before creating a new class:

  1. Search similar classes.
  2. Follow existing namespace conventions.
  3. Follow existing directory structure.
  4. Follow existing naming conventions.
  5. Reuse existing base classes.

---

# 3. `.cursor/rules/mysql.mdc`

```md
---
description: MySQL database development and performance rules
globs:
  - "**/*.php"
  - "**/*.sql"
alwaysApply: true
---

# MySQL Rules

## Query Safety

Never concatenate user input into SQL.

Bad:

```php
$sql = "SELECT * FROM user WHERE name = '" . $name . "'";

Use parameterized queries.

Query Performance

When modifying database code, consider:

  1. indexes
  2. WHERE conditions
  3. ORDER BY
  4. JOIN
  5. GROUP BY
  6. LIMIT
  7. result size
  8. N+1 queries

Indexes

Before adding an index:

  • inspect existing indexes
  • check query patterns
  • avoid duplicate indexes
  • consider composite index ordering

Do not add indexes blindly.

N+1

Always inspect loops containing database queries.

Bad:

foreach ($orders as $order) {
    User::findOne($order->user_id);
}

Prefer eager loading or batch querying.

Large Data

Avoid:

->all()

for millions of records.

Prefer:

  • batch()
  • each()
  • pagination
  • cursor-like processing where appropriate

COUNT

Be careful with expensive COUNT queries on large tables.

Transactions

Keep transactions short.

Never perform slow external HTTP requests inside database transactions unless absolutely necessary.

SQL Review

For complex queries, consider using:

EXPLAIN

before recommending a performance optimization.

Never claim a query is optimized without examining its execution characteristics when performance is the actual task.


---

# 4. `.cursor/rules/redis.mdc`

```md
---
description: Redis caching, locking and queue rules
globs:
  - "**/*.php"
alwaysApply: true
---

# Redis Rules

## Key Naming

Redis keys must have a consistent namespace.

Prefer:

```text
project:user:{id}
project:order:{id}
project:lock:order:{id}

Avoid random key formats.

Cache

Every cache entry must consider:

  • key
  • TTL
  • invalidation
  • serialization
  • stampede protection

Do not cache everything.

Cache Stampede

For hot data consider:

  • locking
  • early refresh
  • stale-while-revalidate
  • randomized TTL

Distributed Lock

When using Redis locks:

  • always define TTL
  • always release the lock
  • avoid infinite locks
  • make operations idempotent

Example conceptual pattern:

acquire lock
    ↓
execute
    ↓
finally release lock

Queue

Queue jobs must be:

  • idempotent
  • retry-safe
  • timeout-aware
  • failure-aware

Do not assume a job executes exactly once.

Retry

When implementing retries consider:

  • transient errors
  • permanent errors
  • retry count
  • backoff
  • dead-letter/failed queue

Redis Memory

Do not store unlimited collections.

Consider:

  • TTL
  • maximum list size
  • maximum set size
  • memory usage

---

# 5. `.cursor/rules/api.mdc`

```md
---
description: Yii2 REST API development rules
globs:
  - "**/controllers/**/*.php"
  - "**/modules/**/*.php"
alwaysApply: true
---

# API Rules

## Input

Never trust request input.

Validate:

- required fields
- type
- length
- range
- enum
- authorization

## Response

API responses should follow the project's existing response format.

Do not introduce a new response structure without checking existing APIs.

## HTTP Status

Use appropriate status codes when the project supports them:

200 - success
201 - created
204 - no content
400 - invalid request
401 - unauthenticated
403 - unauthorized
404 - not found
409 - conflict
422 - validation error
500 - server error

## Authentication

Authentication and authorization are different.

Always check authorization for resources.

Example:

User A must not be able to access User B's resource simply by changing:

```text
?id=123

Pagination

For potentially large API results use pagination.

Do not return unlimited database records.

Serialization

Do not blindly return ActiveRecord objects if that may expose:

  • password hashes
  • tokens
  • internal IDs
  • internal status
  • sensitive fields

Use explicit fields when appropriate.

API Compatibility

Before changing:

  • field names
  • response structure
  • HTTP status
  • error format

search existing frontend/client usage.


---

# 6. `.cursor/rules/security.mdc`

```md
---
description: PHP Yii2 security rules
globs:
  - "**/*.php"
alwaysApply: true
---

# Security Rules

Every new backend feature must consider:

- authentication
- authorization
- input validation
- SQL injection
- XSS
- CSRF
- IDOR
- mass assignment
- file upload
- SSRF
- command injection
- sensitive information exposure
- logging of secrets

## SQL Injection

Never concatenate user-controlled SQL.

## Mass Assignment

Do not blindly assign:

```php
$model->attributes = $request->post();

without checking Yii2 safe attributes and validation.

IDOR

Never assume an authenticated user can access a resource.

Bad:

$order = Order::findOne($id);

if authorization is not checked.

Prefer checking ownership or RBAC.

Passwords

Never:

  • log passwords
  • return password hashes
  • put secrets into source code

Tokens

Never log:

  • JWT
  • access token
  • refresh token
  • API key
  • session cookie

File Upload

Validate:

  • extension
  • MIME type
  • file size
  • filename
  • storage location

Do not trust the uploaded filename.

Command Execution

Be extremely careful with:

exec()
shell_exec()
system()
passthru()

Never pass untrusted user input directly into shell commands.

External URL

Validate external URLs before making server-side HTTP requests.

Consider SSRF.

Logging

Logs should contain enough information for debugging but must not contain secrets or sensitive user data.


---

# 7. `.cursor/rules/testing.mdc`

```md
---
description: PHP Yii2 testing rules
globs:
  - "**/*.php"
alwaysApply: true
---

# Testing Rules

When modifying business logic:

1. Identify existing tests.
2. Add or update tests when practical.
3. Run the relevant test suite.
4. Do not claim tests pass unless they were actually executed.

## Unit Tests

Prioritize:

- business rules
- services
- complex calculations
- permission checks
- edge cases

## API Tests

Test:

- successful request
- invalid parameters
- unauthorized request
- nonexistent resource
- boundary conditions

## Database Tests

When database behavior matters, test:

- insert
- update
- transaction rollback
- unique constraints
- relations

## Regression

When fixing a bug:

1. reproduce the bug
2. create a regression test
3. implement the fix
4. run the test
5. run related tests

## Test Claims

Never say:

"All tests pass."

unless tests were actually executed.

8. .cursor/skills/yii2-backend/SKILL.md

---
name: yii2-backend
description: Expert PHP Yii2 backend development skill. Use for Yii2 architecture, ActiveRecord, ActiveQuery, REST APIs, services, database operations, Redis, performance optimization, security, debugging, refactoring and backend code review.
---

# Yii2 Backend Expert

You are an experienced PHP/Yii2 backend engineer.

Your job is not merely to generate code.

Before changing code, understand the existing project architecture and conventions.

## Workflow

For every non-trivial task:

### Step 1: Understand the project

Inspect:

- composer.json
- config/
- common/
- frontend/
- backend/
- console/
- api/
- modules/
- models/
- services/
- components/
- behaviors/

Do not assume the project follows the standard Yii2 structure.

### Step 2: Search existing implementation

Before creating new code search for:

- similar Controller
- similar Model
- similar Service
- existing helper
- existing component
- existing Redis wrapper
- existing HTTP client
- existing response formatter
- existing validation rules

Prefer reuse over duplication.

### Step 3: Understand data flow

Determine:

```text
Request
 ↓
Controller
 ↓
Validation
 ↓
Service
 ↓
Model
 ↓
Database

or the actual architecture used by the project.

Step 4: Implement minimum necessary changes

Do not refactor unrelated code.

Avoid changing:

  • unrelated formatting
  • unrelated classes
  • dependency versions
  • database schema

unless required.


Yii2 ActiveRecord

Before modifying ActiveRecord code check:

  • rules()
  • scenarios()
  • relations()
  • behaviors()
  • events
  • beforeSave()
  • afterSave()
  • beforeDelete()
  • afterDelete()

Remember:

updateAll()
deleteAll()

do not behave exactly like individual ActiveRecord save/delete operations.


Query Optimization

When the task involves performance:

  1. inspect SQL
  2. identify query count
  3. identify N+1
  4. inspect indexes
  5. consider eager loading
  6. consider batch processing
  7. consider caching
  8. consider database execution plans

Do not optimize based solely on intuition.


Large Dataset

For large tables prefer:

->batch(500)

or:

->each(500)

instead of:

->all()

Do not load millions of records into PHP memory.


Business Transactions

If a business operation modifies multiple related records:

Yii::$app->db->transaction(function () {
    // operation
});

Keep transaction scope small.

Do not perform external network calls inside transactions unless necessary.


API Development

When creating an API:

  1. inspect existing API conventions
  2. validate input
  3. authenticate
  4. authorize
  5. execute business logic
  6. return consistent response
  7. avoid exposing sensitive fields

Debugging

When debugging:

  1. reproduce
  2. inspect stack trace
  3. identify first meaningful error
  4. inspect surrounding code
  5. check configuration
  6. check database/Redis/external dependencies
  7. propose root cause
  8. implement minimal fix
  9. test

Do not blindly patch the last exception line.


Performance

When asked to optimize:

First establish the bottleneck.

Possible bottlenecks:

  • MySQL
  • Redis
  • PHP CPU
  • PHP memory
  • network
  • external API
  • serialization
  • filesystem
  • queue
  • locking

Do not automatically add Redis caching.


Security

Every change must consider:

  • SQL injection
  • XSS
  • CSRF
  • IDOR
  • RBAC
  • mass assignment
  • file upload
  • SSRF
  • command injection
  • secret leakage

Code Review

When reviewing code, check:

Correctness

  • business logic
  • edge cases
  • null handling
  • concurrency

Database

  • N+1
  • indexes
  • transaction scope
  • unnecessary queries
  • large dataset handling

Performance

  • loops
  • memory
  • caching
  • Redis
  • external requests

Security

  • authorization
  • validation
  • injection
  • sensitive information

Maintainability

  • naming
  • duplication
  • complexity
  • coupling

Compatibility

  • existing API
  • existing database schema
  • existing callers

Response Format

For implementation tasks:

  1. Explain the root cause or approach briefly.
  2. Show the changed files.
  3. Provide complete relevant code.
  4. Explain important design decisions.
  5. Provide test commands.
  6. Clearly state what was actually tested.

Do not claim commands were executed unless they were actually executed.


Important Rule

Do not blindly follow the user's proposed implementation if it introduces:

  • security vulnerabilities
  • data corruption risk
  • obvious performance problems
  • broken Yii2 conventions

Instead explain the problem and provide a safer implementation.


---

# 9. `.cursor/skills/yii2-backend/references/architecture.md`

```md
# Yii2 Architecture Reference

Recommended default architecture:

Controller
    ↓
Request/DTO
    ↓
Service
    ↓
Domain/Model
    ↓
Repository/ActiveRecord
    ↓
Database

However, do not force this architecture onto an existing project.

Existing architecture always takes priority.

## Controller

Responsibilities:

- HTTP
- authentication
- authorization
- parameter extraction
- validation
- response

Avoid business logic.

## Service

Responsibilities:

- business workflow
- transaction
- multiple model coordination
- external service interaction
- queue dispatch

## Model

Responsibilities:

- data representation
- validation
- relationships
- persistence

Avoid putting huge business workflows into models.

## Repository

Do not introduce Repository classes automatically.

Use them when:

- query complexity is high
- data access must be abstracted
- multiple data sources exist
- existing project architecture already uses repositories

Do not create:

Controller → Repository → ActiveRecord

just for the sake of patterns.

## Transaction

Transaction should surround the atomic business operation.

Avoid:

transaction {
    HTTP request
    database operation
}

Prefer:

HTTP request

↓

validate

↓

external preparation if needed

↓

transaction {
    database writes
}

↓

response

10. .cursor/skills/yii2-backend/references/database.md

# Yii2 Database Reference

## Query Checklist

When reviewing a query ask:

1. How many SQL statements execute?
2. Is there N+1?
3. Are indexes available?
4. Is ORDER BY indexed?
5. Is the result set bounded?
6. Is the query executed inside a loop?
7. Is the same query repeated?
8. Can eager loading help?
9. Can batch processing help?
10. Is caching appropriate?

## Common Bad Pattern

```php
foreach ($users as $user) {
    $orders = Order::find()
        ->where(['user_id' => $user->id])
        ->all();
}

Potential N+1.

Better

Use eager loading:

$users = User::find()
    ->with('orders')
    ->all();

or fetch data in batches depending on the use case.

Large Data

Bad:

$rows = Order::find()->all();

Potentially dangerous for large tables.

Better:

foreach (Order::find()->batch(1000) as $orders) {
    // process
}

Bulk Update

Order::updateAll(
    ['status' => Order::STATUS_DONE],
    ['status' => Order::STATUS_PENDING]
);

Remember that ActiveRecord events and behaviors may not run as with individual save() calls.

EXPLAIN

For slow SQL:

EXPLAIN SELECT ...

Inspect:

  • type
  • possible_keys
  • key
  • rows
  • Extra

---

# 11. `.cursor/skills/yii2-backend/references/review.md`

```md
# Yii2 Code Review Checklist

## PHP

- [ ] PHP version compatible
- [ ] types appropriate
- [ ] null handling
- [ ] exception handling
- [ ] no unnecessary duplication

## Yii2

- [ ] Controller is thin
- [ ] validation exists
- [ ] ActiveRecord relations checked
- [ ] N+1 checked
- [ ] transaction scope correct
- [ ] behaviors/events considered

## MySQL

- [ ] indexes checked
- [ ] unnecessary SQL avoided
- [ ] large result set controlled
- [ ] batch processing considered
- [ ] transaction performance checked

## Redis

- [ ] key naming consistent
- [ ] TTL exists where appropriate
- [ ] cache invalidation considered
- [ ] distributed lock has timeout
- [ ] queue job is idempotent

## Security

- [ ] authentication
- [ ] authorization
- [ ] SQL injection
- [ ] XSS
- [ ] CSRF
- [ ] IDOR
- [ ] mass assignment
- [ ] file upload
- [ ] SSRF
- [ ] command injection
- [ ] secrets

## API

- [ ] input validation
- [ ] response compatibility
- [ ] status codes
- [ ] pagination
- [ ] sensitive fields excluded

## Testing

- [ ] regression test
- [ ] edge cases
- [ ] relevant tests executed
- [ ] no false test claims

推荐使用方式

完成配置后,可以直接在 Cursor Agent 中这样使用:

帮我分析这个 Yii2 项目的订单创建流程。

先不要改代码。

先找出:
1. Controller
2. Model
3. Service
4. 数据库表
5. Redis
6. 事务
7. 权限验证
8. 可能的 N+1

最后给出改造方案。

然后:

按照刚才的方案实施。

要求:
1. 不修改无关文件
2. 保持现有 API 兼容
3. 保持 Yii2 项目现有架构
4. 所有数据库写操作检查事务
5. 检查 N+1
6. 增加必要测试
7. 修改完成后运行相关测试

代码完成后:

请按照 yii2-backend 的 review checklist 对刚才的修改进行 Code Review。

重点检查:
- N+1
- SQL 性能
- Redis
- 事务
- 并发
- 权限
- IDOR
- 参数验证
- API 兼容性
- PHP 内存
- 大数据量处理

不要修改代码,只输出问题和严重程度。

最后:

根据刚才 Code Review 的结果修复所有 P0/P1 问题。

修复后重新运行相关测试,并告诉我实际执行了哪些测试。
2026-04-10

一、什么是支持向量机(SVM)

支持向量机(Support Vector Machine)本质是:

寻找一个“间隔最大”的最优分类超平面

它不仅追求“分开”,更追求:

分得最稳、泛化最好

这是它和逻辑回归最大的区别。


1)二维直观理解

二维空间中,超平面就是一条直线:

[
w^T x + b = 0
]

其中:

  • (w):方向
  • (b):偏置
  • 距离超平面最近的点:支持向量

这些点决定最终边界。(AiDocZh)


二、最大间隔原理(核心)

SVM 的核心目标是:

让两类样本距离分类边界尽可能远

分类边界两侧还有两条间隔边界:

[
w^T x + b = 1
][
w^T x + b = -1
]

两条边界距离:

[
\frac{2}{|w|}
]

所以:

最大化间隔 = 最小化 (|w|^2)

核心优化目标

\min_{w,b} \frac{1}{2}|w|^2 \quad s.t.; y_i(w^Tx_i+b)\ge 1

这就是经典 Hard Margin SVM


三、为什么最大间隔泛化更强

因为间隔越大,模型对扰动越不敏感。

例如你的 OCR、合同分类场景里:

  • 文本特征有噪声
  • OCR 有误字
  • 向量空间有偏移

大间隔能显著提高鲁棒性。

这也是 SVM 在:

  • 文本分类
  • 小样本分类
  • 高维稀疏特征

里非常强的原因。(scikit-learn)


四、软间隔 SVM(生产最常用)

现实数据通常线性不可分。

所以引入松弛变量:

[
\xi_i
]

允许少量点越界。


优化目标

\min_{w,b,\xi} \frac{1}{2}|w|^2 + C\sum_i \xi_i \quad s.t.; y_i(w^Tx_i+b)\ge 1-\xi_i

其中:

  • (C):误分类惩罚系数
  • 大 (C):更严格
  • 小 (C):更平滑

五、核技巧(SVM 真正强大的地方)

这是 SVM 最核心进阶点。


核心思想

当低维不可分时:

映射到高维空间再线性可分
[
\phi(x)
]

但直接升维成本很高。

于是引入:

Kernel Trick

只计算内积:

[
K(x_i,x_j)=\phi(x_i)^T\phi(x_j)
]

(AiDocZh)


六、常见核函数


1)线性核

[
K(x,z)=x^Tz
]

适合:

  • 文本分类
  • TF-IDF
  • 高维稀疏特征

2)多项式核

[
K(x,z)=(x^Tz+c)^d
]

适合非线性交互。


3)RBF 高斯核(最常用)

K(x,z)=\exp(-\gamma|x-z|^2)

特点:

  • 默认首选
  • 泛化稳定
  • 非线性能力强

scikit-learn 默认就非常推荐。(scikit-learn)


七、Python 实战:线性 SVM


1)基础分类

import numpy as np
from sklearn.svm import SVC
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

X, y = load_iris(return_X_y=True)

X = X[:, :2]
scaler = StandardScaler()
X = scaler.fit_transform(X)

x_train, x_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

model = SVC(kernel="linear", C=1.0)
model.fit(x_train, y_train)

print("accuracy:", model.score(x_test, y_test))

(scikit-learn)


八、RBF SVM(推荐生产)

from sklearn.svm import SVC

rbf_model = SVC(
    kernel="rbf",
    C=2.0,
    gamma="scale"
)

rbf_model.fit(x_train, y_train)
print(rbf_model.score(x_test, y_test))

参数经验(非常重要)


C 参数

C = 0.1 / 1 / 10 / 100
  • 小:防过拟合
  • 大:拟合更强

gamma 参数

gamma = "scale"

经验:

  • 大 gamma:边界复杂
  • 小 gamma:边界平滑

九、可视化决策边界(深入理解)

import matplotlib.pyplot as plt

def plot_boundary(model, X, y):
    x_min, x_max = X[:,0].min()-1, X[:,0].max()+1
    y_min, y_max = X[:,1].min()-1, X[:,1].max()+1

    xx, yy = np.meshgrid(
        np.linspace(x_min, x_max, 300),
        np.linspace(y_min, y_max, 300)
    )

    Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)

    plt.contourf(xx, yy, Z, alpha=0.3)
    plt.scatter(X[:,0], X[:,1], c=y)
    plt.show()

这个对理解:

  • 核函数效果
  • C 对边界影响
  • gamma 复杂度

特别重要。


十、适合你的实战场景(重点)

结合你当前方向,SVM 很适合:


1)OCR 文本分类

例如:

  • 合同类型分类
  • 版权文件分类
  • 工单分类
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import TfidfVectorizer

text_svm = Pipeline([
    ("tfidf", TfidfVectorizer(max_features=10000)),
    ("svm", SVC(kernel="linear"))
])

高维文本特征里,线性 SVM 非常强。(scikit-learn)


2)图像小样本分类

例如:

  • 缺陷检测
  • OCR 字符分类
  • 边缘纹理识别

3)异常检测边界学习

One-Class SVM 也非常适合:

  • 风险合同检测
  • 非法文本检测
  • OCR 异常页

十一、SVM vs XGBoost 怎么选

这是生产里最常见问题。

场景推荐
小样本高维SVM
文本 TF-IDFLinear SVM
非线性中小数据RBF SVM
百万级结构化表XGBoost
超大规模在线服务LR / GBDT

十二、生产级调参方案(推荐)

from sklearn.model_selection import GridSearchCV

params = {
    "C": [0.1, 1, 10],
    "gamma": ["scale", 0.1, 0.01],
    "kernel": ["rbf"]
}

grid = GridSearchCV(SVC(), params, cv=5)
grid.fit(x_train, y_train)

print(grid.best_params_)

十三、面试高频总结

核心记忆:


SVM 本质

最大间隔分类器

核心目标

最小化 (|w|^2)

最强能力

核技巧处理非线性

2026-04-10
让 Agent 真正具备本地知识检索、混合召回、自动索引、文档问答、持续记忆能力
  • Elasticsearch 检索
  • OCR / 合同系统
  • 本地文档知识库
  • 自动化工作流
  • RAG Agent

OpenClaw + Ollama + Elasticsearch 本地知识库 Agent 实战

核心目标:
所有数据本地闭环,不走云端 API,OpenClaw 调度 Agent,Ollama 负责推理,Elasticsearch 负责混合检索与长期知识存储。(AI Agent Knowledge Base)

一、整体架构设计

推荐你直接采用这套生产架构:

User / Telegram / Web
        ↓
   OpenClaw Gateway
        ↓
   Agent Runtime
   ├── Tool Router
   ├── Memory Search
   ├── File Parser
   └── Workflow Skills
        ↓
   Ollama (Qwen2.5 / DeepSeek)
        ↓
Elasticsearch
   ├── BM25
   ├── Dense Vector
   ├── HNSW
   └── Metadata Filter
        ↓
MinIO / 本地文件

其中:

  • OpenClaw = Agent 编排层
  • Ollama = 本地 LLM
  • Elasticsearch = 混合检索层
  • MinIO = 原文档存储层

这正好和你现在的 ES + OCR 技术栈高度一致。


二、环境准备


1)启动 Elasticsearch

docker run -d \
  --name es \
  -p 9200:9200 \
  -e discovery.type=single-node \
  -e xpack.security.enabled=false \
  -e ES_JAVA_OPTS="-Xms2g -Xmx2g" \
  docker.elastic.co/elasticsearch/elasticsearch:8.15.0

2)启动 Ollama

ollama serve
ollama pull qwen2.5:7b
ollama pull nomic-embed-text

本地 embedding 强烈推荐 nomic-embed-text。社区在 OpenClaw hybrid RAG 中大量使用。(reddit.com)


3)启动 OpenClaw

openclaw onboard

新版已经支持自动发现本地 Ollama。(OpenClaw Alpha)


三、Elasticsearch 索引设计(核心)

这里是整个系统最关键的一层。


知识库索引 Mapping

PUT local_knowledge
{
  "mappings": {
    "properties": {
      "doc_id": { "type": "keyword" },
      "title": { "type": "text" },
      "content": { "type": "text" },
      "vector": {
        "type": "dense_vector",
        "dims": 768,
        "index": true,
        "similarity": "cosine",
        "index_options": {
          "type": "hnsw"
        }
      },
      "tags": { "type": "keyword" },
      "created_at": { "type": "date" }
    }
  }
}

非常适合:

  • 合同文档
  • OCR PDF
  • 技术文档
  • 项目知识库
  • API 文档

四、Python 文档入库 Pipeline(重点)

下面给你生产级 Python 脚本。


1)文档切块

from pathlib import Path


def chunk_text(text, size=500, overlap=100):
    chunks = []
    start = 0
    while start < len(text):
        end = start + size
        chunks.append(text[start:end])
        start += size - overlap
    return chunks

2)调用 Ollama Embedding

import requests


def embed(text):
    resp = requests.post(
        "http://localhost:11434/api/embeddings",
        json={
            "model": "nomic-embed-text",
            "prompt": text
        }
    )
    return resp.json()["embedding"]

3)写入 Elasticsearch

from elasticsearch import Elasticsearch
from datetime import datetime
import uuid

es = Elasticsearch("http://localhost:9200")


def index_doc(title, content):
    chunks = chunk_text(content)

    for chunk in chunks:
        vector = embed(chunk)

        es.index(
            index="local_knowledge",
            document={
                "doc_id": str(uuid.uuid4()),
                "title": title,
                "content": chunk,
                "vector": vector,
                "tags": ["contract"],
                "created_at": datetime.now()
            }
        )

五、混合检索(BM25 + 向量)

这是效果最好的方案。

OpenClaw 社区也非常推荐 hybrid memorySearch。(reddit.com)


Python Hybrid Search

def hybrid_search(query, query_vector):
    return es.search(
        index="local_knowledge",
        query={
            "bool": {
                "should": [
                    {"match": {"content": query}},
                    {
                        "script_score": {
                            "query": {"match_all": {}},
                            "script": {
                                "source": "cosineSimilarity(params.q, 'vector') + 1.0",
                                "params": {"q": query_vector}
                            }
                        }
                    }
                ]
            }
        },
        size=5
    )

六、接入 OpenClaw Skill(核心实战)

你真正要的是让 Agent 自动调用 ES。


skill 目录结构

skills/
└── es-rag/
    ├── SKILL.md
    └── search.py

SKILL.md

# ES RAG Search

When users ask about:
- contract
- OCR files
- project docs
- Elasticsearch architecture
- deployment scripts

Always call search.py first.
Use retrieved context before answering.

Skill 是 OpenClaw 最核心扩展能力。(TechRadar)


search.py

import sys

query = sys.argv[1]
vec = embed(query)
result = hybrid_search(query, vec)

for hit in result["hits"]["hits"]:
    print(hit["_source"]["content"])

七、OpenClaw Agent 工作流优化(非常关键)

很多人只做了“能检索”,但 Agent 不一定主动用。

社区最佳实践是:

强制写入 AGENTS.md 规则,让 Agent 优先 memorySearch,再读文件 (reddit.com)

AGENTS.md

Before opening files directly:
1. Always use Elasticsearch hybrid retrieval
2. Prefer semantic recall
3. Merge top5 chunks
4. Then ask Ollama to summarize

这一条非常关键。

否则 Agent 容易:

  • ls
  • 遍历文件夹
  • 逐个打开 markdown
  • 浪费大量 token

八、适配你的 OCR / 合同系统(强烈推荐)

你当前业务非常适合:

PDF
 ↓
OCR
 ↓
结构化字段抽取
 ↓
Chunk
 ↓
Embedding
 ↓
Elasticsearch
 ↓
OpenClaw Agent

例如:

  • 用户问:某合同违约条款是什么?
  • Agent 自动检索 OCR 结果
  • 返回原始 chunk + 总结结果
  • 自动附带合同编号

九、性能优化(生产级)


1)混合权重推荐

直接用社区验证过的权重:

{
  "vectorWeight": 0.7,
  "textWeight": 0.3
}

(reddit.com)


2)MMR 去重

lambda = 0.7

避免多个 chunk 高度重复。


3)时间衰减

halfLifeDays = 30

适合你的合同、版权咨询、工单系统。


十、最适合你的最终生产架构

Nginx
 ↓
OpenClaw
 ↓
Ollama(Qwen2.5)
 ↓
Elasticsearch(HNSW)
 ↓
MinIO
 ↓
OCR / Contract / Copyright System

这套是你当前最匹配的 本地私有 Agent 知识库方案


2026-04-10

OpenClaw 本地部署详细教程(Linux / Mac / Windows 通用)


一、OpenClaw 是什么

OpenClaw 是一个 本地优先的 AI Agent 自动化平台,你可以理解为:

本地版「可执行任务的 ChatGPT + 自动化助手」

它支持:

  • 本地 LLM(Ollama)
  • OpenAI / Claude / Gemini
  • 文件操作
  • Shell 执行
  • Web 自动化
  • Slack / Telegram / Discord
  • 定时任务
  • 多 Agent 协作

特别适合你这种做:

  • 本地知识库
  • 自动代码生成
  • 文档处理
  • 爬虫调度
  • 运维自动化
  • OCR / 合同流转

的场景。(TechRadar)


二、部署方式推荐(最稳)

对于本地部署,我建议你直接用:

官方 install-cli 本地前缀安装

优点:

  • 不污染系统 Node
  • 所有文件都在 ~/.openclaw
  • 好迁移
  • 好备份
  • 适合服务器长期运行

官方推荐命令:(OpenClaw)

curl -fsSL https://openclaw.ai/install-cli.sh | bash

三、服务器配置建议

最低配置

2 Core CPU
4GB RAM
20GB SSD

推荐配置(本地模型)

8 Core CPU
16GB RAM
100GB SSD
RTX 3060+

如果你准备接 Ollama 本地模型

建议:

32GB RAM + 12GB VRAM

四、Linux 本地部署(推荐 Ubuntu)


1)安装

curl -fsSL https://openclaw.ai/install-cli.sh | bash

默认目录:

~/.openclaw

目录结构一般如下:

~/.openclaw/
├── bin/
├── config/
├── data/
├── logs/
├── tools/
└── runtime/

2)验证安装

~/.openclaw/bin/openclaw --version

或者加入环境变量:

echo 'export PATH="$HOME/.openclaw/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

然后:

openclaw --version

3)初始化服务

openclaw onboard --install-daemon

这一步会自动:

  • 初始化配置
  • 安装守护进程
  • 创建用户服务
  • 启动 Gateway

官方推荐这样做。(OpenClaw)


五、接入本地 Ollama(重点)

这个是本地部署最关键的一步。


1)安装 Ollama

curl -fsSL https://ollama.com/install.sh | sh

2)拉取模型

推荐你先用:

ollama pull qwen2.5:7b

或者:

ollama pull llama3.1:8b

3)验证模型

ollama run qwen2.5:7b

4)OpenClaw 配置模型

编辑:

~/.openclaw/config/models.json

写入:

{
  "providers": {
    "ollama": {
      "base_url": "http://127.0.0.1:11434",
      "model": "qwen2.5:7b"
    }
  }
}

社区大量本地部署都这么配。(reddit.com)


六、Docker 部署(更适合服务器)

如果你服务器主要跑 Docker,推荐这个。


docker-compose.yml

version: "3.9"

services:
  openclaw:
    image: node:24
    container_name: openclaw
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - /data/openclaw:/root/.openclaw
    command: >
      sh -c "
      npm install -g openclaw@latest &&
      openclaw onboard --install-daemon &&
      tail -f /dev/null
      "

启动:

docker compose up -d

七、常用运维命令


查看状态

openclaw gateway status

查看健康检查

openclaw doctor

查看日志

tail -f ~/.openclaw/logs/gateway.log

重启

openclaw gateway restart

停止

openclaw gateway stop

八、Nginx 反向代理(生产推荐)

你经常做部署,这块对你很重要。

server {
    listen 80;
    server_name claw.yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

九、安全配置(非常重要)

OpenClaw 默认权限很高,一定要做权限收敛。研究显示其工具链调用存在较大攻击面。(arXiv)

建议:


禁止高危工具

进入配置:

Config -> Tools -> Deny

建议先禁用:

  • shell
  • browser
  • gateway
  • sessions
  • web_search

尤其你本地模型推理能力有限时,禁掉很多工具反而更稳。(reddit.com)


绑定本地

127.0.0.1:3000

不要直接公网裸露。


配合 Nginx + Basic Auth

auth_basic "OpenClaw";
auth_basic_user_file /etc/nginx/.htpasswd;

十、和你技术栈最搭的玩法(推荐)

结合你的方向,我建议你这样用:


1)本地代码 Agent

  • Vue 自动生成页面
  • Python 数据脚本
  • Shell 自动部署
  • Elasticsearch DSL 自动生成

2)文档自动化

  • 合同 OCR
  • DOCX 解析
  • PDF 分类
  • 自动标签抽取

3)RAG 自动化

  • 本地知识库索引
  • 自动 chunk
  • 自动 embedding
  • 自动 ES 入库

十一、故障排查(高频)


问题1:找不到命令

openclaw: command not found

修复:(OpenClaw)

export PATH="$HOME/.openclaw/bin:$PATH"

问题2:本地模型无响应

检查:

curl http://127.0.0.1:11434/api/tags

问题3:服务没启动

openclaw gateway status
openclaw doctor

十二、最适合你的生产级架构(推荐)

Nginx
   ↓
OpenClaw
   ↓
Ollama(Qwen2.5)
   ↓
Elasticsearch
   ↓
MinIO
   ↓
Your OCR / Contract System

这套特别适合:

  • OCR合同系统
  • 版权咨询平台
  • Elasticsearch检索
  • 自动化工作流

一、什么是 Quorum NWR 算法

在分布式存储系统中,同一份数据通常会保存多个副本:

  • N(Number of Replicas):副本总数
  • W(Write Quorum):写成功所需确认副本数
  • R(Read Quorum):读成功所需返回副本数

Quorum 的核心目标是在:

  • 一致性(Consistency)
  • 可用性(Availability)
  • 延迟(Latency)

之间取得平衡。

其核心公式:

R + W > N

满足该条件时,任意一次读操作与最近一次成功写操作一定至少命中一个共同副本。(systemoverflow.com)


二、NWR 的数学本质

假设:

N = 3
W = 2
R = 2

那么:

R + W = 4 > 3

说明:

  • 写入至少进入 2 个副本
  • 读取至少读取 2 个副本
  • 任意两组大小分别为 2 的集合,在 3 个节点内必然相交

这就是 Quorum Intersection(法定人数交集)


三、Python 从零实现 Quorum 存储模型

下面我们直接用 Python 构建一个最小可运行的 Quorum KV。

from dataclasses import dataclass, field
from typing import Dict, List, Tuple
import time
import random


@dataclass
class Replica:
    node_id: int
    store: Dict[str, Tuple[int, str]] = field(default_factory=dict)

    def write(self, key: str, version: int, value: str):
        self.store[key] = (version, value)
        return True

    def read(self, key: str):
        return self.store.get(key, (0, None))


class QuorumKV:
    def __init__(self, n: int, w: int, r: int):
        self.n = n
        self.w = w
        self.r = r
        self.version = 0
        self.replicas = [Replica(i) for i in range(n)]

    def put(self, key: str, value: str):
        self.version += 1
        ack = 0
        selected = random.sample(self.replicas, self.n)

        for replica in selected:
            replica.write(key, self.version, value)
            ack += 1
            if ack >= self.w:
                return True
        return False

    def get(self, key: str):
        selected = random.sample(self.replicas, self.r)
        versions = [replica.read(key) for replica in selected]
        return max(versions, key=lambda x: x[0])

四、验证 R+W>N 的强一致读取

cluster = QuorumKV(n=3, w=2, r=2)

cluster.put("name", "alice")
print(cluster.get("name"))

cluster.put("name", "bob")
print(cluster.get("name"))

输出:

(1, 'alice')
(2, 'bob')

说明读取到了最新版本。


五、为什么 Python 仿真最适合理解 Quorum

我们继续用 Monte Carlo 做随机一致性实验。


def simulate(n, w, r, rounds=10000):
    success = 0

    for _ in range(rounds):
        write_set = set(random.sample(range(n), w))
        read_set = set(random.sample(range(n), r))

        if write_set & read_set:
            success += 1

    return success / rounds


print(simulate(3, 2, 2))
print(simulate(5, 3, 3))
print(simulate(5, 2, 2))

预期:

1.0
1.0
0.7x

R+W<=N 时,交集概率下降,不再保证强一致。


六、深入分析:不同参数组合的系统特性

1)高可用读优化

N=3, W=2, R=1

特点:

  • 读非常快
  • 写保证多数派
  • 可能读旧数据

典型系统:Dynamo 风格系统。(arxiv.org)


2)强一致推荐组合

N=3, W=2, R=2

特点:

  • 工程上最常见
  • 可容忍 1 节点故障
  • 读写都具备较强一致性

3)写优先系统

N=5, W=4, R=2

适合:

  • 金融账本
  • 订单系统
  • 元数据管理

七、Python 模拟节点故障场景

class FaultyReplica(Replica):
    def __init__(self, node_id, fail_rate=0.2):
        super().__init__(node_id)
        self.fail_rate = fail_rate

    def write(self, key, version, value):
        if random.random() < self.fail_rate:
            return False
        return super().write(key, version, value)

扩展故障集群:

class FaultyQuorumKV(QuorumKV):
    def __init__(self, n, w, r, fail_rate=0.2):
        self.n = n
        self.w = w
        self.r = r
        self.version = 0
        self.replicas = [FaultyReplica(i, fail_rate) for i in range(n)]

    def put(self, key, value):
        self.version += 1
        ack = 0

        for replica in self.replicas:
            if replica.write(key, self.version, value):
                ack += 1

        return ack >= self.w

测试:

cluster = FaultyQuorumKV(5, 3, 3, fail_rate=0.3)

ok = sum(cluster.put("k", str(i)) for i in range(1000))
print(ok / 1000)

这可以直接用于分析:

  • 节点故障率
  • quorum 成功率
  • SLA 可用性

八、Quorum 与 Paxos / Raft 的区别

很多人容易混淆:

Quorum

  • 副本读写策略
  • 偏向存储层
  • 解决副本一致性

Paxos / Raft

  • 分布式共识
  • 偏向日志复制
  • 保证全局顺序一致

多数派提交本质也是一种特殊 Quorum。(geeksforgeeks.org)


九、生产级 Python:加入 Version + Read Repair

def read_repair(cluster: QuorumKV, key: str):
    selected = random.sample(cluster.replicas, cluster.r)
    versions = [r.read(key) for r in selected]
    latest = max(versions, key=lambda x: x[0])

    for replica in selected:
        version, _ = replica.read(key)
        if version < latest[0]:
            replica.write(key, latest[0], latest[1])

    return latest

这就是 Cassandra / Dynamo 常见的:

  • Read Repair
  • Hinted Handoff
  • Anti Entropy

思想基础。


十、面试级总结(高频)

核心公式

R + W > N

常见推荐

N=3, W=2, R=2

核心收益

  • 高可用
  • 可容错
  • 延迟可控
  • 一致性可调

核心代价

  • 存在脑裂窗口
  • 非线性一致性
  • 时钟/version依赖
  • repair 成本

十一、Python 性能压测脚本(进阶)

import time

cluster = QuorumKV(5, 3, 3)
start = time.time()

for i in range(100000):
    cluster.put("counter", str(i))
    cluster.get("counter")

print("QPS:", 100000 / (time.time() - start))

十二、结语

Quorum NWR 的价值不在于“背公式”,而在于:

N/W/R 三个参数直接控制一致性、可用性、延迟三角平衡
2025-10-09

第一章 无人机编队协同的基础概念与应用场景

1.1 无人机编队的定义

无人机编队(UAV Swarm Formation)是指多架无人机通过通信与协作控制,实现空间队形的自动保持、变换和任务分配的系统。它的核心目标是实现 分布式自治控制(Distributed Autonomous Control)

1.2 应用场景

  • 军事与巡逻任务:集群打击、编队侦察
  • 灾害搜救:大范围搜索、分区覆盖
  • 农业监测:智能喷洒、地形感知
  • 表演与娱乐:灯光秀、群体路径规划

1.3 集群智能的核心思想

每架无人机可视为一个 智能体(Agent)
整个编队系统是一个 多智能体系统(Multi-Agent System, MAS)

MAS 的关键特征:

  • 去中心化(Decentralized)
  • 局部通信(Local Communication)
  • 全局协作(Global Objective)
  • 复杂动态耦合(Dynamic Coupling)

第二章 分布式控制理论基础

2.1 集中式 vs 分布式控制

控制类型特点缺点
集中式控制所有无人机由中央节点统一决策单点故障、通信瓶颈
分布式控制每架无人机根据邻居状态独立决策收敛速度依赖拓扑结构

2.2 通信拓扑结构(Graph Topology)

设通信网络为图 ( G = (V, E) ):

  • ( V = {1, 2, ..., N} ):无人机集合
  • ( E \subseteq V \times V ):通信边集合

若无人机 ( i ) 能与 ( j ) 通信,则 ( (i, j) \in E )。

常见拓扑:

  • 全连接(Fully Connected)
  • 环形(Ring)
  • 星形(Star)
  • 网格(Grid)

2.3 邻接矩阵与拉普拉斯矩阵

定义邻接矩阵:

$$ A_{ij} = \begin{cases} 1, & (i,j) \in E\ 0, & 其他 \end{cases} $$

定义度矩阵 ( D = diag(d_1, d_2, ..., d_N) ),其中 ( d_i = \sum_j A_{ij} )。

拉普拉斯矩阵:

$$ L = D - A $$

它在一致性分析中扮演关键角色。


第三章 一致性算法(Consensus Algorithm)详解

3.1 一致性问题的定义

目标:让所有无人机的状态 ( x_i ) 收敛到共同值。

$$ \lim_{t\to\infty} |x_i(t) - x_j(t)| = 0, \quad \forall i, j $$

3.2 离散时间一致性模型

$$ x_i(k+1) = x_i(k) + \epsilon \sum_{j \in N_i} a_{ij}(x_j(k) - x_i(k)) $$

其中:

  • ( \epsilon ):步长
  • ( N_i ):邻居集合
  • ( a_{ij} ):通信权重

3.3 连续时间一致性模型

$$ \dot{x}*i = \sum*{j \in N_i} a_{ij}(x_j - x_i) $$

用矩阵形式写为:

$$ \dot{X} = -L X $$

其中 ( X = [x_1, x_2, ..., x_N]^T )。

若图连通,系统会收敛到平均值:

$$ x^* = \frac{1}{N} \sum_i x_i(0) $$


第四章 Leader-Follower 与行为层次控制模型

4.1 Leader-Follower 模型

部分无人机作为 Leader,其他为 Follower。

Follower 的控制律:

$$ u_i = k \sum_{j \in N_i} a_{ij} (x_j - x_i) $$

Leader 的状态由外部轨迹生成器定义:

$$ \dot{x}_L = f(t) $$

Follower 将收敛到 Leader 的轨迹附近。

4.2 行为层控制模型

基于 Boids 模型(Reynolds, 1987)

  • 分离(Separation):避免碰撞
  • 对齐(Alignment):速度方向一致
  • 聚合(Cohesion):靠近邻居中心

综合控制律:

$$ u_i = k_1 f_{sep} + k_2 f_{align} + k_3 f_{cohesion} $$


第五章 分布式控制算法设计与推导

以二维空间为例,定义每个无人机状态:

$$ p_i = [x_i, y_i]^T, \quad v_i = [v_{x_i}, v_{y_i}]^T $$

控制律:

$$ \dot{v}*i = \sum*{j \in N_i} a_{ij} (v_j - v_i) + b_i (p^* - p_i) $$

其中 ( p^* ) 为编队期望形态中心。

如果引入 Leader:

$$ \dot{v}_i = -c_1 (p_i - p_j^*) - c_2 (v_i - v_j) $$


第六章 Python 仿真环境搭建

6.1 仿真依赖

pip install numpy matplotlib

6.2 无人机类定义

import numpy as np

class UAV:
    def __init__(self, pos, vel=np.zeros(2)):
        self.pos = np.array(pos, dtype=float)
        self.vel = np.array(vel, dtype=float)
        
    def update(self, acc, dt=0.1):
        self.vel += acc * dt
        self.pos += self.vel * dt

6.3 控制器实现(基于一致性)

def consensus_control(uavs, A, k=1.0):
    N = len(uavs)
    acc = [np.zeros(2) for _ in range(N)]
    for i in range(N):
        for j in range(N):
            if A[i, j] == 1:
                acc[i] += k * (uavs[j].pos - uavs[i].pos)
    return acc

6.4 主仿真循环

import matplotlib.pyplot as plt

N = 5
A = np.ones((N, N)) - np.eye(N)
uavs = [UAV(np.random.rand(2) * 10) for _ in range(N)]

for t in range(200):
    acc = consensus_control(uavs, A, k=0.1)
    for i in range(N):
        uavs[i].update(acc[i], dt=0.1)
    
    if t % 10 == 0:
        plt.clf()
        plt.xlim(0, 10)
        plt.ylim(0, 10)
        for u in uavs:
            plt.scatter(u.pos[0], u.pos[1], color='b')
        plt.pause(0.05)

运行后,所有无人机会逐渐聚合到一个点。


第七章 从算法到编队:视觉化仿真实战

你可以扩展仿真以实现队形控制:

7.1 期望编队定义(如三角形)

formation = np.array([[0,0], [2,0], [1,1.732], [3,1.732], [2,3.464]])
center = np.mean([u.pos for u in uavs], axis=0)

7.2 队形控制律

def formation_control(uavs, formation, A, k=0.1):
    center = np.mean([u.pos for u in uavs], axis=0)
    acc = []
    for i, u in enumerate(uavs):
        target = center + formation[i] - np.mean(formation, axis=0)
        acc_i = k * (target - u.pos)
        acc.append(acc_i)
    return acc

运行后你将看到无人机自动形成规则队形。


第八章 通信延迟、丢包与容错机制设计

8.1 延迟建模

延迟 ( \tau ) 会导致控制律:

$$ u_i(t) = \sum_{j \in N_i} a_{ij} [x_j(t - \tau) - x_i(t)] $$

8.2 丢包机制

可使用 最近一次有效状态保持(Last-Valid-Hold) 策略。

last_positions = [u.pos.copy() for u in uavs]
for i in range(N):
    for j in range(N):
        if np.random.rand() < 0.9:  # 10% 丢包
            neighbor_pos = uavs[j].pos
        else:
            neighbor_pos = last_positions[j]

第九章 强化学习与分布式编队控制融合方向

现代研究将 强化学习(RL) 融入分布式控制:

  • 每个无人机为一个智能体
  • 状态:自身 + 邻居信息
  • 动作:速度或方向调整
  • 奖励:保持队形、避免碰撞

代表算法:

  • MADDPG (Multi-Agent Deep Deterministic Policy Gradient)
  • MAPPO (Multi-Agent Proximal Policy Optimization)

可参考开源框架:

  • PettingZoo + RLlib
  • MARLlib

目录

  1. 引言:限流的意义与应用场景
  2. 限流算法概览

    • 固定窗口限流
    • 滑动窗口限流
    • 漏桶与令牌桶
  3. 分布式滑动窗口限流的原理

    • 滑动窗口算法思路
    • 分布式实现挑战
    • Redis与Lua结合优势
  4. Redis+Lua实现分布式滑动窗口限流

    • 数据结构设计
    • Lua脚本详解
    • Redis调用方式
  5. 完整代码示例

    • Python示例
    • Node.js示例
  6. 工作流程图解
  7. 性能优化与注意事项
  8. 总结与实践建议

1. 引言:限流的意义与应用场景

在高并发场景下,服务端需要对请求进行限流,以防止系统过载。典型应用场景包括:

  • API接口防刷
  • 秒杀活动限流
  • 微服务调用流量控制

分布式系统中,单点限流容易成为瓶颈,因此采用Redis+Lua实现的分布式滑动窗口限流,成为高性能、高可用的方案。


2. 限流算法概览

2.1 固定窗口限流(Fixed Window)

  • 按固定时间窗口统计请求数量
  • 简单,但存在“临界点超额”的问题
窗口长度:1秒
请求限制:5次
时间段:[0s-1s]
请求次数统计:超过5次则拒绝

2.2 滑动窗口限流(Sliding Window)

  • 按时间连续滑动,统计最近一段时间的请求
  • 精度高,平滑处理请求峰值
  • 实现方式:

    • 精确计数(存储请求时间戳)
    • Redis Sorted Set(ZSET)存储请求时间戳

2.3 漏桶与令牌桶

  • 漏桶:固定出水速度,适合平滑处理请求
  • 令牌桶:以固定速率生成令牌,灵活控制突发请求
本文重点讲解滑动窗口算法。

3. 分布式滑动窗口限流的原理

3.1 滑动窗口算法思路

滑动窗口算法核心:

  1. 记录请求时间戳
  2. 每次请求:

    • 删除超出窗口的旧请求
    • 判断当前窗口内请求数量是否超限
    • 超限则拒绝,否则允许

公式

允许请求数量 = COUNT(时间戳 > 当前时间 - 窗口长度)

3.2 分布式实现挑战

  • 多实例并发请求
  • 原子性操作要求:检查+增加
  • 高并发下操作Redis性能问题

3.3 Redis+Lua结合优势

  • Lua脚本在Redis端执行,保证原子性
  • 减少网络往返次数,提高性能

4. Redis+Lua实现分布式滑动窗口限流

4.1 数据结构设计

使用 Redis Sorted Set (ZSET):

  • key:接口标识 + 用户ID
  • score:请求时间戳(毫秒)
  • value:唯一标识(可用时间戳+随机数)

4.2 Lua脚本详解

-- KEYS[1] : 限流key
-- ARGV[1] : 当前时间戳 (毫秒)
-- ARGV[2] : 窗口长度 (毫秒)
-- ARGV[3] : 最大请求数

local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])

-- 删除超出窗口的旧请求
redis.call('ZREMRANGEBYSCORE', key, 0, now - window)

-- 获取当前窗口请求数量
local count = redis.call('ZCARD', key)

if count >= limit then
    return 0  -- 限流
else
    -- 添加新请求
    redis.call('ZADD', key, now, now .. '-' .. math.random())
    -- 设置过期时间
    redis.call('PEXPIRE', key, window)
    return 1  -- 允许
end

4.3 Redis调用方式

Python调用示例(使用redis-py

import redis
import time

r = redis.Redis(host='localhost', port=6379, db=0)

lua_script = """
-- Lua脚本内容同上
"""

def is_allowed(user_id, limit=5, window=1000):
    key = f"rate_limit:{user_id}"
    now = int(time.time() * 1000)
    return r.eval(lua_script, 1, key, now, window, limit)

for i in range(10):
    if is_allowed("user123"):
        print(f"请求{i}: 允许")
    else:
        print(f"请求{i}: 限流")

Node.js调用示例(使用ioredis

const Redis = require('ioredis');
const redis = new Redis();

const luaScript = `
-- Lua脚本内容同上
`;

async function isAllowed(userId, limit=5, window=1000) {
    const key = `rate_limit:${userId}`;
    const now = Date.now();
    const result = await redis.eval(luaScript, 1, key, now, window, limit);
    return result === 1;
}

(async () => {
    for (let i = 0; i < 10; i++) {
        const allowed = await isAllowed('user123');
        console.log(`请求${i}: ${allowed ? '允许' : '限流'}`);
    }
})();

5. 工作流程图解

+---------------------+
|  用户请求到达服务端  |
+---------------------+
           |
           v
+---------------------+
|  执行Lua脚本(原子)  |
|  - 清理过期请求      |
|  - 判断请求数        |
|  - 添加请求记录      |
+---------------------+
           |
     +-----+-----+
     |           |
     v           v
  允许请求      限流返回
  • Lua脚本保证操作原子性
  • Redis ZSET高效管理时间戳

6. 性能优化与注意事项

  1. 键过期设置:使用PEXPIRE防止ZSET无限增长
  2. ZSET最大长度:可结合ZREMRANGEBYRANK控制极端情况
  3. Lua脚本缓存:避免每次发送脚本,提高性能
  4. 分布式部署:所有实例共享同一个Redis节点/集群

7. 总结与实践建议

  • 滑动窗口比固定窗口更平滑,适合高并发场景
  • Redis+Lua实现保证原子性和性能
  • 分布式系统可横向扩展,限流逻辑一致

实践建议

  1. 精确控制请求速率,结合缓存和数据库保护后端
  2. 监控限流命中率,动态调整参数
  3. Lua脚本可扩展:按接口/用户/IP限流

2025-09-06

1. 引言

1.1 为什么要降维?

在实际的机器学习项目中,我们经常面临这样的问题:

  • 数据维度过高,训练速度极慢;
  • 特征高度相关,模型泛化能力差;
  • 可视化维度太高,无法直观理解;
  • “维度灾难”导致 KNN、聚类等算法性能下降。

这些问题统称为 高维问题。解决方法之一就是 降维,即用更少的维度表示原始数据,同时保留尽可能多的信息。

1.2 PCA 的地位

主成分分析(Principal Component Analysis, PCA)是最经典的降维方法,广泛应用于:

  • 图像压缩(如人脸识别中的特征脸 Eigenfaces)
  • 金融因子建模(提取市场主要波动因子)
  • 基因组学(从上万个基因中提取少量主成分)
  • 文本处理(稀疏矩阵降维,加速训练)

1.3 本文目标

本文将从 理论原理、数学推导、代码实现、应用案例 四个方面,全面解析 PCA,并结合 Python 工程实践,展示如何在真实项目中使用 PCA 进行特征降维。


2. PCA 原理与数学推导

2.1 几何直观

假设我们有二维数据点,点云分布沿着一条斜线。如果我们要用一维表示这些点,那么最佳方式是:

  • 找到点云方差最大的方向
  • 把点投影到这个方向

这就是 第一主成分

进一步,第二主成分是与第一主成分正交的方向,方差次大。


2.2 协方差矩阵

数据矩阵 $X \in \mathbb{R}^{n \times d}$,先中心化:

$$ X_{centered} = X - \mu $$

协方差矩阵:

$$ \Sigma = \frac{1}{n} X^T X $$

$\Sigma$ 的元素含义:

$$ \sigma_{ij} = Cov(x_i, x_j) = \mathbb{E}[(x_i - \mu_i)(x_j - \mu_j)] $$

它描述了不同特征之间的相关性。


2.3 特征分解与主成分

我们要求解:

$$ \max_w \quad w^T \Sigma w \quad \text{s.t. } \|w\|=1 $$

解为:

$$ \Sigma w = \lambda w $$

也就是协方差矩阵的特征分解。最大特征值对应的特征向量就是第一主成分。

扩展到 k 维:取前 k 个特征值对应的特征向量组成矩阵 $V_k$,数据投影为:

$$ X_{reduced} = X \cdot V_k $$


2.4 与 SVD 的关系

奇异值分解(SVD):

$$ X = U \Sigma V^T $$

其中 $V$ 的列向量就是 PCA 的主成分方向。相比直接特征分解,SVD 更稳定,尤其适用于高维数据。


3. Python 从零实现 PCA

3.1 手写 PCA 类

import numpy as np

class MyPCA:
    def __init__(self, n_components):
        self.n_components = n_components
        self.components = None
        self.mean = None
    
    def fit(self, X):
        # 1. 均值中心化
        self.mean = np.mean(X, axis=0)
        X_centered = X - self.mean
        
        # 2. 协方差矩阵
        cov_matrix = np.cov(X_centered, rowvar=False)
        
        # 3. 特征分解
        eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
        
        # 4. 排序
        sorted_idx = np.argsort(eigenvalues)[::-1]
        eigenvectors = eigenvectors[:, sorted_idx]
        eigenvalues = eigenvalues[sorted_idx]
        
        # 5. 取前k个
        self.components = eigenvectors[:, :self.n_components]
    
    def transform(self, X):
        X_centered = X - self.mean
        return np.dot(X_centered, self.components)
    
    def fit_transform(self, X):
        self.fit(X)
        return self.transform(X)

3.2 应用到鸢尾花数据集

from sklearn.datasets import load_iris
import matplotlib.pyplot as plt

X = load_iris().data
y = load_iris().target

pca = MyPCA(n_components=2)
X_reduced = pca.fit_transform(X)

plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y, cmap='viridis')
plt.title("Iris Dataset PCA")
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.show()

结果:不同鸢尾花品种在二维平面上明显可分。


4. Scikit-learn 实现 PCA

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 标准化
X_scaled = StandardScaler().fit_transform(X)

pca = PCA(n_components=2)
X_reduced = pca.fit_transform(X_scaled)

print("解释方差比例:", pca.explained_variance_ratio_)

输出示例:

解释方差比例: [0.72 0.23]

说明前两个主成分解释了 95% 的方差。


5. PCA 在特征工程中的应用案例

5.1 图像压缩(Eigenfaces)

from sklearn.datasets import fetch_olivetti_faces

faces = fetch_olivetti_faces().data
pca = PCA(n_components=100)
faces_reduced = pca.fit_transform(faces)

print("原始维度:", faces.shape[1])
print("降维后:", faces_reduced.shape[1])
  • 原始数据:4096维
  • 降维后:100维

仍能保留主要人脸特征。


5.2 金融风险建模

import numpy as np
from sklearn.decomposition import PCA

np.random.seed(42)
returns = np.random.randn(1000, 200)  # 模拟股票收益率

pca = PCA(n_components=10)
factor_returns = pca.fit_transform(returns)

print("累计解释率:", np.sum(pca.explained_variance_ratio_))

结果:前 10 个因子即可解释 80%+ 的市场波动。


5.3 文本特征降维

在 NLP 中,TF-IDF 特征维度可能达到 10 万。PCA 可加速分类器训练:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import TruncatedSVD
from sklearn.datasets import fetch_20newsgroups

data = fetch_20newsgroups(subset='train')
vectorizer = TfidfVectorizer(max_features=20000)
X_tfidf = vectorizer.fit_transform(data.data)

svd = TruncatedSVD(n_components=100)
X_reduced = svd.fit_transform(X_tfidf)

print("降维后形状:", X_reduced.shape)

5.4 基因表达数据

基因表达数据常有上万个基因,PCA 可提取主要差异:

import pandas as pd
from sklearn.decomposition import PCA

# 模拟基因表达数据 (100个样本,5000个基因)
X = np.random.rand(100, 5000)

pca = PCA(n_components=50)
X_reduced = pca.fit_transform(X)

print("累计解释率:", np.sum(pca.explained_variance_ratio_))

6. 高级变体

6.1 增量 PCA

适合大数据集:

from sklearn.decomposition import IncrementalPCA

ipca = IncrementalPCA(n_components=50, batch_size=100)
X_reduced = ipca.fit_transform(X)

6.2 核 PCA

解决非线性问题:

from sklearn.decomposition import KernelPCA

kpca = KernelPCA(n_components=2, kernel='rbf')
X_kpca = kpca.fit_transform(X)

6.3 稀疏 PCA

提升可解释性:

from sklearn.decomposition import SparsePCA

spca = SparsePCA(n_components=2)
X_spca = spca.fit_transform(X)

7. 工程实践技巧与踩坑总结

  1. 必须标准化:不同量纲影响方差计算。
  2. 碎石图选择主成分数:避免过多或过少。
  3. 小心信息损失:过度降维可能导致分类性能下降。
  4. 核 PCA 参数敏感:需要调节核函数和参数。
  5. 大数据推荐 IncrementalPCA:避免内存溢出。

8. 总结与展望

本文从 数学原理 出发,逐步解析了 PCA 的核心思想,展示了 手写实现 → sklearn 实现 → 多领域应用 的完整路径。

2025-09-06

第 1 章 引言:为什么要学习 PCA

在数据科学和机器学习中,我们经常会遇到如下问题:

  1. 维度灾难
    数据维度过高会导致计算复杂度增加,模型训练缓慢,甚至出现过拟合。
  2. 特征冗余
    数据集中可能存在大量冗余特征,它们彼此高度相关,导致模型难以捕捉真正的模式。
  3. 可视化困难
    人类直觉主要依赖二维或三维空间,高维数据难以可视化。

为了解决这些问题,降维技术应运而生,而其中最经典、最常用的方法就是 主成分分析(Principal Component Analysis, PCA)

PCA 的核心思想是:

将高维数据映射到一组新的正交基(主成分)上,保留最大方差方向上的信息,从而实现降维、压缩和去噪

应用场景包括:

  • 机器学习预处理:降低维度、加速训练、去除噪声
  • 数据可视化:将高维数据映射到 2D 或 3D
  • 压缩存储:如图像压缩
  • 金融建模:降维后提取核心因子

第 2 章 数学原理解析

PCA 的原理来自于线性代数和概率统计。

2.1 数据中心化

对样本矩阵 $X \in \mathbb{R}^{n \times d}$:

$$ X = \{x_1, x_2, \dots, x_n\}, \quad x_i \in \mathbb{R}^d $$

先做中心化:

$$ X_{centered} = X - \mu, \quad \mu = \frac{1}{n}\sum_{i=1}^n x_i $$

2.2 协方差矩阵

定义样本协方差矩阵:

$$ C = \frac{1}{n-1} X_{centered}^T X_{centered} $$

2.3 特征值分解

对 $C$ 做特征值分解:

$$ C v_i = \lambda_i v_i $$

  • 特征值 $\lambda_i$:对应主成分方向的方差
  • 特征向量 $v_i$:主成分方向

2.4 主成分排序

按特征值大小排序,取前 $k$ 个主成分:

$$ W = [v_1, v_2, \dots, v_k] $$

2.5 数据降维

最终投影公式:

$$ Y = X_{centered} W $$

其中 $Y \in \mathbb{R}^{n \times k}$ 即降维后的新表示。


第 3 章 算法实现流程图

文字版流程:

原始数据 X 
   ↓
数据中心化(减去均值)
   ↓
计算协方差矩阵 C
   ↓
特征值分解 C = VΛV^T
   ↓
选取最大特征值对应的前 k 个特征向量
   ↓
数据投影 Y = X_centered × W

如果用图表示,则 PCA 本质上是把原始坐标系旋转到“最大方差方向”的新坐标系中。


第 4 章 从零实现 PCA

我们先不用 sklearn,而是自己实现。

4.1 数据生成

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)
# 生成二维数据(有相关性)
X = np.dot(np.random.rand(2, 2), np.random.randn(2, 200)).T

plt.scatter(X[:, 0], X[:, 1], alpha=0.5)
plt.title("原始数据分布")
plt.show()

4.2 PCA 实现

def my_pca(X, n_components):
    # 1. 数据中心化
    X_centered = X - np.mean(X, axis=0)
    
    # 2. 协方差矩阵
    cov_matrix = np.cov(X_centered, rowvar=False)
    
    # 3. 特征值分解
    eig_vals, eig_vecs = np.linalg.eigh(cov_matrix)
    
    # 4. 排序
    sorted_idx = np.argsort(eig_vals)[::-1]
    eig_vals = eig_vals[sorted_idx]
    eig_vecs = eig_vecs[:, sorted_idx]
    
    # 5. 取前 k 个
    W = eig_vecs[:, :n_components]
    X_pca = np.dot(X_centered, W)
    
    return X_pca, W, eig_vals

X_pca, W, eig_vals = my_pca(X, n_components=1)
print("特征值:", eig_vals)
print("降维后形状:", X_pca.shape)

4.3 可视化主成分

plt.scatter(X[:, 0], X[:, 1], alpha=0.3)
for i in range(W.shape[1]):
    plt.plot([0, W[0, i]*3], [0, W[1, i]*3], linewidth=2, label=f"PC{i+1}")
plt.legend()
plt.axis("equal")
plt.show()

这时能直观看到 PCA 的第一主成分就是数据分布方差最大的方向。


第 5 章 使用 sklearn 实现 PCA

from sklearn.decomposition import PCA

pca = PCA(n_components=1)
X_pca = pca.fit_transform(X)

print("解释方差比:", pca.explained_variance_ratio_)

scikit-learn 内部是基于 SVD 分解 的,更稳定、更高效。


第 6 章 PCA 实战案例

6.1 手写数字可视化

from sklearn.datasets import load_digits

digits = load_digits()
X = digits.data  # 1797 × 64
y = digits.target

pca = PCA(n_components=2)
X_reduced = pca.fit_transform(X)

plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y, cmap="tab10", alpha=0.6)
plt.colorbar()
plt.title("手写数字 PCA 可视化")
plt.show()

通过 PCA,64 维的数字图像被映射到 2D 平面,并且仍然能区分出类别分布。


6.2 图像压缩

from sklearn.datasets import load_digits

digits = load_digits()
X = digits.data

pca = PCA(n_components=20)
X_reduced = pca.fit_transform(X)
X_restored = pca.inverse_transform(X_reduced)

fig, axes = plt.subplots(1, 2, figsize=(8, 4))
axes[0].imshow(X[0].reshape(8, 8), cmap="gray")
axes[0].set_title("原始图像")
axes[1].imshow(X_restored[0].reshape(8, 8), cmap="gray")
axes[1].set_title("压缩后还原图像")
plt.show()

仅保留 20 个主成分,就能恢复接近原始的图像。


第 7 章 深入原理:SVD 与 PCA

PCA 其实可以通过 SVD 来实现。

7.1 SVD 分解

对中心化后的 $X$:

$$ X = U \Sigma V^T $$

其中:

  • $V$ 的列向量就是主成分方向
  • $\Sigma^2$ 对应特征值大小

7.2 Python SVD 实现

U, S, Vt = np.linalg.svd(X - np.mean(X, axis=0))
W = Vt.T[:, :2]
X_pca = (X - np.mean(X, axis=0)) @ W

第 8 章 PCA 的优缺点

优点

  • 降低维度、提高效率
  • 去除噪声
  • 可视化高维数据

缺点

  • 只能捕捉线性关系
  • 主成分缺乏可解释性
  • 需要数据标准化

第 9 章 进阶扩展

  1. Kernel PCA:解决非线性问题
  2. Incremental PCA:适合大规模数据
  3. PCA vs LDA:监督 vs 无监督的降维方法

附录:完整从零实现 PCA 类

class PCAFromScratch:
    def __init__(self, n_components):
        self.n_components = n_components
        self.components = None
        self.mean = None
    
    def fit(self, X):
        # 中心化
        self.mean = np.mean(X, axis=0)
        X_centered = X - self.mean
        
        # 协方差矩阵
        cov_matrix = np.cov(X_centered, rowvar=False)
        
        # 特征值分解
        eig_vals, eig_vecs = np.linalg.eigh(cov_matrix)
        
        # 排序
        sorted_idx = np.argsort(eig_vals)[::-1]
        self.components = eig_vecs[:, sorted_idx][:, :self.n_components]
    
    def transform(self, X):
        X_centered = X - self.mean
        return np.dot(X_centered, self.components)
    
    def fit_transform(self, X):
        self.fit(X)
        return self.transform(X)

总结

本文从 数学推导 → 算法实现 → Python 代码 → 应用案例 → 深入原理 全面剖析了 PCA 算法。

学习要点:

  • PCA 的本质是寻找最大方差方向
  • 可以用 特征值分解SVD 分解 实现
  • 在工程中,常用 sklearn.decomposition.PCA
  • 进阶可研究 Kernel PCA、Incremental PCA