Skip to content

📊 数据分析工作流

本教程帮助你建立系统的笔记数据分析流程,通过数据洞察知识库的健康状况和优化方向。

🎯 学习目标

  • 建立数据收集机制
  • 创建分析脚本和报告
  • 设定改进指标和目标
  • 持续优化知识管理系统

📋 数据分析框架

核心指标体系

markdown
# 知识库健康指标

## 增长指标
- 日均新增笔记数
- 周均字数增量
- 月均附件增长

## 活跃指标
- 日活跃笔记数(修改)
- 平均笔记年龄
- 僵尸笔记比例

## 连接指标
- 平均双向链接数
- 孤岛笔记比例
- 聚类系数

## 质量指标
- 平均笔记长度
- Front Matter 完整率
- 标签使用率

分析周期

周期分析内容产出
每日记录统计、习惯追踪每日摘要
每周活跃度分析、任务完成率周报
每月增长趋势、内容审计月度报告
每季知识网络分析、结构调整季度回顾

📈 自动数据收集

每日统计脚本

dataviewjs
// 每日知识库统计
const today = dv.date("today");
const vault = app.vault;

// 获取统计数据
const totalNotes = dv.pages().length;
const notesToday = dv.pages()
  .where(p => p.file.ctime >= today).length;
const modifiedToday = dv.pages()
  .where(p => p.file.mtime >= today).length;

const totalSize = dv.pages()
  .map(p => p.file.size)
  .reduce((a, b) => a + b, 0);

const avgLinks = dv.pages()
  .map(p => p.file.outlinks.length)
  .reduce((a, b) => a + b, 0) / totalNotes;

// 生成报告
dv.paragraph(`
### 📊 今日统计 (${today.toFormat("yyyy-MM-dd")})

| 指标 | 数值 |
|------|------|
| 笔记总数 | ${totalNotes} |
| 今日新增 | ${notesToday} |
| 今日修改 | ${modifiedToday} |
| 总大小 | ${(totalSize / 1024 / 1024).toFixed(2)} MB |
| 平均链接数 | ${avgLinks.toFixed(1)} |
`);

周度趋势分析

dataviewjs
// 过去 7 天的活动趋势
const endDate = dv.date("today");
const startDate = endDate.minus({days: 7});

const dailyStats = [];
for (let i = 6; i >= 0; i--) {
  const date = endDate.minus({days: i});
  const created = dv.pages()
    .where(p => p.file.ctime >= date && p.file.ctime < date.plus({days: 1}))
    .length;
  const modified = dv.pages()
    .where(p => p.file.mtime >= date && p.file.mtime < date.plus({days: 1}))
    .length;
  
  dailyStats.push({
    date: date.toFormat("MM-dd"),
    created,
    modified
  });
}

// 显示表格
dv.table(
  ["日期", "新增", "修改"],
  dailyStats.map(s => [s.date, s.created, s.modified])
);

// 计算平均值
const avgCreated = dailyStats.reduce((a, b) => a + b.created, 0) / 7;
const avgModified = dailyStats.reduce((a, b) => a + b.modified, 0) / 7;

dv.paragraph(`
**本周平均**
- 日均新增: ${avgCreated.toFixed(1)} 篇
- 日均修改: ${avgModified.toFixed(1)} 篇
`);

🔍 内容健康分析

孤岛笔记检测

dataviewjs
// 检测没有入链和出链的笔记
const pages = dv.pages()
  .where(p => !p.file.folder.startsWith("Templates"))
  .where(p => !p.file.folder.startsWith("Archive"));

const orphans = [];
for (let page of pages) {
  const inlinks = page.file.inlinks.length;
  const outlinks = page.file.outlinks.length;
  
  if (inlinks === 0 && outlinks === 0) {
    orphans.push({
      link: page.file.link,
      age: Math.floor((dv.date("today") - page.file.ctime) / (1000 * 60 * 60 * 24))
    });
  }
}

dv.header(3, `🏝️ 孤岛笔记 (${orphans.length} 篇)`);

if (orphans.length > 0) {
  dv.table(
    ["笔记", "年龄(天)"],
    orphans
      .sort((a, b) => b.age - a.age)
      .slice(0, 20)
      .map(o => [o.link, o.age])
  );
} else {
  dv.paragraph("太棒了!没有孤岛笔记。");
}

僵尸笔记报告

dataviewjs
// 检测超过 90 天未修改的笔记
const threshold = 90;
const today = dv.date("today");

const zombies = dv.pages()
  .where(p => !p.file.folder.startsWith("Templates"))
  .where(p => !p.file.folder.startsWith("Archive"))
  .where(p => {
    const daysInactive = Math.floor((today - p.file.mtime) / (1000 * 60 * 60 * 24));
    return daysInactive > threshold;
  })
  .map(p => ({
    link: p.file.link,
    daysInactive: Math.floor((today - p.file.mtime) / (1000 * 60 * 60 * 24)),
    created: p.file.ctime
  }))
  .sort(p => p.daysInactive, 'desc');

dv.header(3, `🧟 僵尸笔记 (超过 ${threshold} 天未修改)`);

dv.table(
  ["笔记", "未活跃天数", "创建时间"],
  zombies.slice(0, 20).map(z => [
    z.link, 
    z.daysInactive,
    z.created.toFormat("yyyy-MM-dd")
  ])
);

dv.paragraph(`共发现 ${zombies.length} 篇僵尸笔记,建议归档或删除。`);

标签使用分析

dataviewjs
// 标签使用频率分析
const tagCounts = {};
const pages = dv.pages().where(p => p.file.tags);

for (let page of pages) {
  for (let tag of page.file.tags) {
    tagCounts[tag] = (tagCounts[tag] || 0) + 1;
  }
}

const sortedTags = Object.entries(tagCounts)
  .sort((a, b) => b[1] - a[1])
  .slice(0, 20);

dv.header(3, "🏷️ 标签使用排行 (Top 20)");

dv.table(
  ["标签", "使用次数", "占比"],
  sortedTags.map(([tag, count]) => [
    tag,
    count,
    ((count / pages.length) * 100).toFixed(1) + "%"
  ])
);

// 分析标签健康度
const totalTags = Object.keys(tagCounts).length;
const avgTagsPerNote = pages.map(p => p.file.tags.length).reduce((a, b) => a + b, 0) / pages.length;

dv.paragraph(`
**标签健康度**
- 总标签数: ${totalTags}
- 平均每篇笔记标签数: ${avgTagsPerNote.toFixed(1)}
- 单次使用标签: ${sortedTags.filter(([_, c]) => c === 1).length}
`);

📊 定期报告生成

周报模板

markdown
---
type: weekly-report
week: {{date:gggg-[W]ww}}
generated: {{date:YYYY-MM-DD}}
---

# 📊 知识库周报 - {{week}}

## 📈 概览

```dataviewjs
const startOfWeek = dv.date("today").minus({days: 7});
const endOfWeek = dv.date("today");

const stats = {
  created: dv.pages().where(p => p.file.ctime >= startOfWeek).length,
  modified: dv.pages().where(p => p.file.mtime >= startOfWeek).length,
  tasks: dv.pages('"tasks"').where(p => p.completed).length
};

dv.paragraph(`
| 指标 | 数值 |
|------|------|
| 新增笔记 | ${stats.created} |
| 修改笔记 | ${stats.modified} |
| 完成任务 | ${stats.tasks} |
`);

🆕 本周新增

dataview
TABLE 
  file.name as "笔记",
  file.folder as "位置"
FROM ""
WHERE file.ctime >= date(today) - dur(7 days)
SORT file.ctime DESC
LIMIT 10

✅ 任务完成情况

dataview
TABLE 
  task as "任务",
  due as "截止日期",
  completed as "完成时间"
FROM "tasks"
WHERE completed >= date(today) - dur(7 days)
SORT completed DESC

📝 下周计划

  • [ ]
  • [ ]

💡 本周发现

🎯 改进建议


### 月度报告脚本

```dataviewjs
// 月度报告生成器
const month = dv.date("today").toFormat("yyyy-MM");
const startOfMonth = dv.date("today").startOf("month");
const endOfMonth = dv.date("today").endOf("month");

// 统计数据
const monthlyStats = {
  newNotes: dv.pages().where(p => p.file.ctime >= startOfMonth).length,
  activeDays: new Set(
    dv.pages()
      .where(p => p.file.mtime >= startOfMonth)
      .map(p => p.file.mtime.toFormat("yyyy-MM-dd"))
  ).size,
  totalSize: dv.pages()
    .map(p => p.file.size)
    .reduce((a, b) => a + b, 0),
  avgNoteLength: dv.pages()
    .map(p => p.file.size)
    .reduce((a, b) => a + b, 0) / dv.pages().length
};

// 增长对比
const lastMonth = startOfMonth.minus({months: 1});
const lastMonthNotes = dv.pages()
  .where(p => p.file.ctime >= lastMonth && p.file.ctime < startOfMonth).length;
const growth = ((monthlyStats.newNotes - lastMonthNotes) / lastMonthNotes * 100).toFixed(1);

// 生成报告
dv.paragraph(`
# 📊 ${month} 月度报告

## 📈 核心指标

| 指标 | 数值 | 环比变化 |
|------|------|----------|
| 新增笔记 | ${monthlyStats.newNotes} | ${growth > 0 ? "+" : ""}${growth}% |
| 活跃天数 | ${monthlyStats.activeDays} 天 | - |
| 知识库大小 | ${(monthlyStats.totalSize / 1024 / 1024).toFixed(2)} MB | - |
| 平均笔记长度 | ${(monthlyStats.avgNoteLength / 1024).toFixed(1)} KB | - |

## 📊 增长趋势

本月新增 ${monthlyStats.newNotes} 篇笔记,${growth > 0 ? "相比上月增长" : "相比上月减少"} ${Math.abs(growth)}%。

## 🎯 月度总结

请手动填写...

## 📋 下月计划

- [ ] 
- [ ] 
`);

🎯 目标追踪系统

知识库增长目标

markdown
# 🎯 年度目标追踪

## 笔记数量目标

```dataviewjs
const target = 1000; // 年度目标
const current = dv.pages().length;
const progress = (current / target * 100).toFixed(1);
const remaining = target - current;
const daysLeft = 365 - dv.date("today").dayOfYear;
const neededPerDay = (remaining / daysLeft).toFixed(1);

dv.paragraph(`
**目标**: ${target} 篇笔记
**当前**: ${current} 篇
**进度**: ${progress}%
**剩余**: ${remaining} 篇
**日均需求**: ${neededPerDay} 篇/天

[${"█".repeat(Math.floor(progress / 5))}${"░".repeat(20 - Math.floor(progress / 5))}] ${progress}%
`);

标签覆盖率目标

dataviewjs
const targetCoverage = 90; // 90% 笔记有标签
const notesWithTag = dv.pages().where(p => p.file.tags.length > 0).length;
const totalNotes = dv.pages().length;
const coverage = (notesWithTag / totalNotes * 100).toFixed(1);

dv.paragraph(`
**目标覆盖率**: ${targetCoverage}%
**当前覆盖率**: ${coverage}%
**状态**: ${coverage >= targetCoverage ? "✅ 达标" : "⚠️ 需改进"}
`);

### 习惯追踪系统

```markdown
# 📊 习惯追踪

```dataviewjs
// 计算连续天数
const today = dv.date("today");
const dailyNotes = dv.pages('"daily-notes"')
  .where(p => p.file.ctime <= today)
  .sort(p => p.file.ctime, 'desc');

let streak = 0;
for (let note of dailyNotes) {
  const expectedDate = today.minus({days: streak});
  if (note.file.ctime.toFormat("yyyy-MM-dd") === expectedDate.toFormat("yyyy-MM-dd")) {
    streak++;
  } else {
    break;
  }
}

dv.paragraph(`
**当前连续记录**: ${streak} 天
**最长记录**: ${Math.max(streak, ...)} 天

${streak >= 7 ? "🎉 连续一周!继续保持!" : 
  streak >= 3 ? "💪 不错的开始!" : 
  "🌱 开始你的连续记录吧!"}
`);

---

## 🔧 自动化工具

### 定期报告脚本

```javascript
// .obsidian/scripts/monthly-report.js
// 可通过 Templater 或命令触发

function generateMonthlyReport() {
  const { vault, workspace } = app;
  const today = new Date();
  const monthStr = today.toISOString().slice(0, 7);
  
  const reportContent = `---
type: monthly-report
month: ${monthStr}
generated: ${today.toISOString().slice(0, 10)}
---

# 📊 月度报告 - ${monthStr}

[自动生成内容...]

## 手动补充

- 本月亮点:
- 遇到的问题:
- 下月计划:
`;

  const fileName = `Reports/${monthStr}-report.md`;
  vault.create(fileName, reportContent);
  
  workspace.openLinkText(fileName, '', true);
}

数据导出功能

dataviewjs
// 导出笔记统计为 CSV
const pages = dv.pages();
const csvContent = [
  ["文件名", "创建时间", "修改时间", "大小", "链接数"].join(","),
  ...pages.map(p => [
    p.file.name,
    p.file.ctime.toFormat("yyyy-MM-dd HH:mm"),
    p.file.mtime.toFormat("yyyy-MM-dd HH:mm"),
    p.file.size,
    p.file.outlinks.length
  ].join(","))
].join("\n");

// 创建下载链接
const blob = new Blob([csvContent], {type: "text/csv"});
const url = URL.createObjectURL(blob);

dv.paragraph(`
📥 [下载笔记统计 CSV](${url})

数据包含 ${pages.length} 篇笔记的统计信息。
`);

📱 移动端适配

简化统计视图

markdown
# 📱 移动端统计

```dataview
TABLE WITHOUT ID
  length(rows) as "总计"
FROM ""
GROUP BY true
dataview
LIST WITHOUT ID
"📝 笔记: " + length(dv.pages())
"📁 大小: " + round(sum(dv.pages().file.size) / 1024 / 1024, 1) + " MB"
"🔗 链接: " + sum(dv.pages().file.outlinks.length)

---

## 📊 最佳实践

### 分析原则

```markdown
# 数据分析三原则

1. **目的明确**
   每个指标都要服务于具体目标

2. **行动导向**
   分析结果要能指导具体行动

3. **适度即可**
   不要过度收集和分析,避免分析瘫痪

常见陷阱

markdown
# 避免这些错误

❌ 只看数量不看质量
   解决:结合内容审计

❌ 过度依赖自动化
   解决:定期人工审查

❌ 忽视趋势只看快照
   解决:建立长期追踪

❌ 指标过多失去焦点
   解决:聚焦核心指标

📚 进阶资源

推荐插件

  • Dataview: 数据查询和分析
  • Tracker: 习惯和趋势追踪
  • Charts: 数据可视化
  • Heatmap Calendar: 热力图展示

社区模板


🎯 小结

分析维度关键指标工具
增长分析新增笔记、字数增长Dataview
活跃分析修改频率、活跃天数DataviewJS
连接分析链接数、孤岛比例Graph View
质量分析完整率、标签覆盖Dataview
习惯追踪连续天数、完成率Tracker

📖 相关内容

  • [[dataview|Dataview 入门]]
  • [[dataview-advanced|Dataview 进阶]]
  • [[data-visualization|数据可视化]]
  • [[periodic-notes|周期性笔记]]

💡 提示:数据分析的最终目的是优化知识管理,而不是追求数据本身。定期回顾指标,确保它们仍在服务于你的目标。

最后更新:2026年4月7日编辑此页反馈问题