绵绵不绝的工作压力让我对每一段休息时间都非常珍视,同时在自己意识到周末过得很快的时候又非常懊悔。我喜欢待在家里、想要休息,但是一直在家睡觉又感觉缺乏出门探险的新鲜感.. 让人很是纠结。我想要快乐,想知道怎么做才可以在仅有的空闲时间收获快乐。
于是听从乐忻的建议做了一些记录。我尽可能记录了 2024 年给我留下印象的周末,包含 74 条日记。记录、主观心情以及其他元数据可以被我存在我的 Notion 笔记里。Art Kohn 认为 70% 的经历会在 24h 后忘记[1],因此部分待在家里的记录,或者没有当天留下日记或者照片的条目,就真的无论如何也想不起来了.. 更不要说客观描述心情。因此 2024 年的 70+ 条记录对我来说已经是非常极限了 T T。
但好在要进行简单数据分析,对我需要的 NLP 任务而言这个数量已经足够😺
我希望至少弄明白两件事:
针对上文的目标,在做日常记录时,我只会简单记录如下字段:
{
'Week': '记录所在周序号',
'Title': '记录标题,通常无意义',
'OutsideHour': '出门时长',
'Mood': '主观心情打分,是介于0~5之间的浮点数,越高表示记录时认为自己的心情越好',
'Description': '当日日程的详细描述',
'CreatedTime': '记录时间'
}
这里我通过 Notion 表格的触发器让数据库每个周末增加两条对应时间的空白记录,来确保筛选和排序时通过CreatedTime
字段可以精准过滤到具体哪个周末,对没能及时记录的条目也不用想上个周末是几号了。
那如何把写好的笔记数据塞进 Python 进行分析呢?一开始我想爬取发布网站上的表格,但我发现 Notion 的网页会动态地渲染表格内容,相当于你需要一边滑鼠标一边才能加载出窗口中间一小截的表格内容 - 让想拿齐全部数据的过程迅速脱离了一两下就搞好的舒适区。
好在我发现 Notion 是提供了集成服务的,并且完成支持使用 API 访问自己的账号内容。唯一离谱的点是官方文档[2]提供的 SDK 只有 JavaScript SDK 和 cURL 实例。
好在好在我在 Github 社区发现了 Python SDK[3],它甚至已经有 2k stars 了.. 总之对着完全对不上的文档连蒙带猜地拿到了数据。
到这里距离最后一条 24 年记录完成已经过去四个多月了.. 我的天啊!不行了我一定要赶紧.. 至少这个月内把想做的分析弄完!
本节记录我直接提取记录中的简单数据,使用传统描述性统计分析方法用仅有的量化数据进行一些分析。值得一提的是心情(Mood)字段是主观填写的,这里的分析只能说明一种偏主观的关系。
但谁在意呢?心情当然是主观的。
如果单独看看数据集中心情和外出时长(OutsideHour)的分布,容易看出心情的分布比较正态,而且感觉确实自己在评价平静温和的一天的时候倾向于给一个3.0。 实际上3分以上的日子对我来说应该显著包含一些快乐的因素 (虽然只是凭感觉在评,完全没有自己提前订好标准😶🌫️) 。
这样看来,快乐的日子还是比难过的多好多 - 平均心情比我的预设平均值要多0.53的样子。
相比之下出门时长分布就偏了很多,大多数时候我都不怎么出门,或者只是短短地体验了一下“超市25分钟”这样的半月/月度活动。
同时打印了一下出门时长和心情值的全年趋势。可以注意到几个高峰有一些重合,但是由于比例尺的关系看得不是很清楚。
但单独看心情变化的话,可以尝试观察一下季节对自己的心情影响。为了让趋势更易读我进一步以窗口大小为 5 周做了平滑处理:
显然还是没有发现什么特别的影响。硬要说的话年初好像真的挺开心的,也许是因为过年和元旦给我很多特别的仪式感和假期..?
但心情和外出时长确实有一些关系。
从上图的散点可以看出一个非常明显的相关关系:不出门不一定不快乐,但出远门一定很开心!
不过相关性不能代表因果,因为往往能吸引我出门很长时间的事情往往是有意思的线下活动或长途旅游。而且对我来说有计划的一次出行会塞满各种我喜欢的事情,即使旅途可能会比较累或者有其他未知的麻烦,但计划中的快乐事件赋予了行程很大程度的稳定快乐。比如 5月1日区天津泡泡岛听 YOASOBI 的事,就是累得要死站得要不行了结束还打不到车,在防波堤一样什么也没有的滨海新区狂走了数公里才打上车回酒店.. 即使这样也很难说是不快乐的回忆。
最后对上文提到的时间(周数)/心情/外出时长绘制了 Pearson 和 Spearman 相关系数的热力图。这里展示了 Pearson 相关度。
同时体现了另一个数值 Score,这其实是我后来使用 LLM 进行的心情打分,后文会展开这部分的分析。
根据热力图,可以说我的出门时长和心情其实很有关系,但是心情随时间基本没影响。同时 LLM 的判断似乎还不如我的样子。
理论上如果衡量单调关系这里选择 Spearman 相关度更好,它不要求正态分布(因为我有一些OutsideHour
集中在 0 侧),对异常值也更鲁棒。不过从结果上来看影响不大:
Pearson Correlation Matrix:
Week Mood OutsideHour
Week 1.000000 -0.093533 -0.060592
Mood -0.093533 1.000000 0.587222
OutsideHour -0.060592 0.587222 1.000000
Spearman Correlation Matrix:
Week Mood OutsideHour
Week 1.000000 -0.171926 -0.150199
Mood -0.171926 1.000000 0.402214
OutsideHour -0.150199 0.402214 1.000000
因为 Pearson 明显高于 Spearman,表明关系更偏向线性而非非线性单调。
0.58 表示中等偏强正相关: 出门时间对心情有积极影响,但不是极强。 同时有 p < 0.01,认为关系显著。
接下来我想挖掘一下日记具体内容中包含的语义信息。
尤其在我完全不记得以前写过了什么的现在,感觉像拿着刮刮乐的小朋友.. 希望能发现一些意外惊喜。
在没有去除 stopwords 的情况下做了词频统计,因为这里可以发现一些更有趣的事:即使是记录心情,我的语言特征也很明显。比如“..”的写法真的已经用了十几年,被我用来作为一种淡淡的语气衔接标记,成为胜过“啊”/“emmm”等各种赛博逗号的挚爱用法。
在去除部分无意义 stopwords 后,构建Description
字段的词云。结合词频统计表可以看到更全面的日程偏好(口癖)。
首先就是和探索动作有关的“深圳” “出门”和“商场”。大量市区的线下活动(比如宝可梦快闪)也安排在商场里,出门和逛商场对生活在深圳的人来说一定程度上是等价的。至少对我很是如此。
“自己”,在描述一切的时候讨论的最终目标。
以及和探索过程有关的内容,“好吃” “二次元” 和“活动”看起来像很多次日常的主题。
完成分词后,可以尝试使用感兴趣的关键词针对性地判断特殊事件对心情的影响。这里我选择了出现次数相对多,又能说明问题的两个主题:工作与学习。
对我来说,工作之后在周末的学习通常是一些感兴趣的事情,往往是自驱的活动;但加班真的不是。虽然不代表加班一定会有坏心情,但加班给心情带来的波动方差很大。
这里的活动关键词我还尝试了天气、运动类型的主题,发现自己其实不怎么提这些内容。尤其是天气这种事,对我完全没有影响.. 似乎只是生活背景色的一部分。毕竟我至今也没有装过天气预报的APP。
情感分析是最开始打算做这个记录的时候就计划做的事,作为经典 NLP 任务实现起来有很多现成的轮子,而且也很有意思(NLP魂狠狠动了)。
考虑到调用方便和准确度,这里同时使用 SnowNLP().sentiments
基于贝叶斯模型,和今天的第一梯队 LLM gemini-2.5-flash-preview-04-17
进行了日记Description
字段的情感分析。贝叶斯模型的方法主要用于筛选情感相关的关键词,用于本阶段的其他实验中;LLM 方法生成的结果会更多给我自己参考。
顺带一提,这里我使用的 prompt 如下:
system_prompt = dedent('''
你是能力极强的情感分析师。接下来你会收到用户关于某个休息日的描述,你需要分析用户的日程描述,给出一段简短的评价,以及一个由你决定的当日心情量化得分。
接收到的输入以一个JSON表示,包含的键与含义如下:
{
'Week': '记录所在周序号',
'Title': '记录标题,通常无意义',
'OutsideHour': '出门时长',
'Mood': '用户的主观心情打分,是0~5之间的浮点数,越高表示记录时认为自己的心情越好',
'Description': '当日日程的详细描述,你应当以此为主要依据来分析用户心情',
'Created_time': '记录时间'
}
请注意:
1. 你的最终目的是积极地引导用户理解如何过上更快乐、更有意义的生活,因此你需要在评价中用温和的语气对用户进行正面引导,同时你的分析应当尽可能专业、详细。
2. 你仍然需要客观地根据'Description'字段内容给出一个客观的用户一日心情评价。这个评价不需要参考'Mood'字段,而应该由你的独立分析给出。这里的评分也应该是0~5之间的浮点数,越高表示你认为当日记录的心情越好。
''').strip()
借助 Google genai 的 GenerateContentConfig
对象可以设置一个类作为 response schema,让生成内容以 JSON 格式遵从这个 schenma,相比使用 prompt 进行格式约束更加稳定[4]。
我的约束类如下:
class SentimentEvaluation(BaseModel):
mood_analysis: str
score: float
意思是,除了让 Gemini 帮我给日程打分以外,我还想听听它(们没有硅基偏旁的他感觉未来会成为问题)如何评价我的生活。当然不能说得太过分。(别真太客观了我是说
Gemini 确实给了很鼓励性的回答。我应该会找时间慢慢看完。
到这里,我还想解决一个问题。
就是,我费力气自己给自己评价心情,这一步可以省略吗?
观察一下 LLM(gemini-2.5-flash-preview-04-17)的打分结果Score
,可以发现 Gemini 的心态比我好很多。绝大多数事情它都认为是很快乐的,也许平平淡淡才是真?或者其实我的生活比我想象得快乐很多吗?
进一步观察了一下每条记录里主观心情和 LLM 判断的重合度,顺便做了一下拟合。
理想状态下这里应该拟合成 y = x 的一条直线,LLM 的判断其实和我自己的写法有一些差距。
但是可以用来替换吗?
这里我额外绘制了 Bland-Altman 图用以进行一致性检验。
绝大多数点都落在 ±1.96个标准差之间,在这个一致性界限内,理论上可以认为这两个特征可以相互替代。
如果可以相互替代是可以的,有没有办法证明哪种量化方法更好呢?
考虑到心情是没有 ground truth 的,如果有也应该是自己标的Mood
字段才算。
这里我用了一些自动化方法对文本中的正面和负面关键词进行分类。用下面的箱线图比较两个字段在不同情感类别关键词中的分布,以评估哪个变量能更好地根据描述中的上下文线索区分情绪。
实际上能得出的结论是 LLM 能更好识别积极内容,但对消极关键字也有较高的打分。这和前文的判断一致。对中性词有较多负面 outlier,我推测是 LLM 提取语义的能力远超传统方法单个给词的语义分类后粗暴认为内容开心与否的做法,毕竟真正的伤心不是大喊大叫!
到这里我认为情绪关键字分类进行指标好坏的分析意义已经不大了,就像其他被 LLM 洪流冲烂的模型、行业、方法和人。
一定要说的话,考虑到 Mood
在正负关键词间差异更显著(p-value: 0.005),可能能更敏感地反映心情变化吧。
Records with |Score - Mood| > 1:
Week Mood Score Description
11 6 3.3 2.0 去永泰泡了温泉!和想象的温泉酒店设施有一点差距名单还是很幸福。晚上去排了永泰唯一必吃榜金莲葱...
18 11 4.5 2.5 晚上回到酒店甚至感觉还很兴奋.. 尤其发现横琴口岸有pokestop的时候。一直到四点我都还...
19 12 3.0 4.7 和嘉豪去打羽毛球了。不得不说这个地方真的偏僻地要死,和荒凉的厂区还不太一样,很多断裂的混凝土...
23 14 4.0 2.0 在家看书。捣鼓了一下我的文石墨水屏。
...
出于好奇,打印了一下两个字段评分相差有些大的条目。发现 Gemini 真的很严格。而且有些日子我确实有点不高兴,但是没想把事情写进日记 - 没想到这样的隐藏特征被发现了,是巧合吗..!
我用完整记录问了问业界主流产品,说实话gemini-2.5-pro-preview-05-06
的答案是我最满意的.. 非常wholesome而且有帮助!我觉得很意外,远远超过现在商用的马斯克家的 Grok 3,也比奥特曼家的 4o 有人味一些。
与你共勉:
好的,这份休息日记录非常详尽,充满了生活气息!让我们从多个角度来分析你过去一年的休息日,并为你量身定制一些建议。
一、数据概览与初步印象
二、多角度深入分析
1. 心情与活动类型的强关联性:
2. 外出时长与心情的关系:
3. 社交互动的重要性:
4. 兴趣爱好的广泛性与深度:
5. “深圳”这个城市的印记:
6. 周期性情绪与思考:
三、你可能忽略的内容 (Insights You Might Have Missed)
四、让你变得更好、更快乐的建议
你已经拥有一个非常丰富多彩的休息日生活,充满了对世界的好奇和感知幸福的能力。上述建议旨在帮你锦上添花,让这份精彩更持久、更深入。希望你能越来越快乐,活出自己喜欢的样子!
我很少犯同样的错误,但我觉得自己可能会因为忘记要怎么做(或者做什么)而陷入一些纠结。在某种程度上记录本身解决了这个问题,允许我回过头审视自己,得出一些未来还可以参考的经验。
希望可以打磨一下记录方案,做出更有意思的东西。
最后应该有一个关于目标问题的两个结论,但 Gemini 已经说得很明白了.. 我想我会在有意识增加外出的基础上尝试过更规律更有计划的生活。
p.s. 我尝试在图表中使用了马卡龙配色,这个配色方案是由 Grok 3 帮我完成的。
[1] Dr. Art Kohn Explains How to Achieve the Optimal Learning Experience with Boosts and Bursts
[2] Notion API Reference - https://developers.notion.com/reference/intro#code-samples–sdks
[3] notion-sdk-py - https://github.com/ramnes/notion-sdk-py
[4] Structured output - https://ai.google.dev/gemini-api/docs/structured-output