分类 默认分类 下的文章

研究 pypots 和 TimeMixer

目标

  1. 弄清楚 pypots 能做什么, 主要应用场景是什么, 亲身实践2个核心使用场景
  2. 搞清楚 TimeMixer 是怎么应用的, 大概了解它的核心原理.

步骤

pypots 是什么?

Python toolbox for Partially-Observed Time Series, 首先对于程序员来说, 它是一个开源python 库, 主要应用在时序数据的分析上面. 为什么强调部分观测数据? 因为现实情况中很多时候无法获取完整数据, 数据有缺失, 必须要数据清理, 整理, 而 pypots 直接面对这些有缺失数据的时序数据. 内置了 50 多种最先进的(SOTA)经典与深度学习算法(涵盖了基于 GAN、Transformer、扩散模型等技术), 并使用统一的 API 接口(fit/transform/predict),

pypots 能做啥?

  1. 缺失值插补 (Imputation)
  2. 时间序列预测 (Forecasting)
  3. 分类 (Classification)
  4. 聚类 (Clustering)
  5. 异常检测 (Anomaly Detection)

参考:

  1. https://pypots.com/
  2. https://github.com/kwuking/TimeMixer
  3. https://deepwiki.com/kwuking/TimeMixer

投资词汇

  1. ETF: Exchange Trade Funds 交易型开放式基金, 它兼具基金组合投资和股票在二级市场交易的属性.

    • 主动 ETF(主动选择投资标的) / 被动 ETF(被动跟踪指数)
    • 场内基金 / 场外基金 (ETF 联接基金, 方便没有股票账户的投资者购入)
  2. 一级市场: Primary Market 证券首次被创造和出售(IPO或再融资)的地方,是发行人和初始投资者之间的交易,资金直接流向发行公司。
  3. 二级市场: 已经发行的证券进行交易和流通的地方,为已发行的证券提供流动性和价格发现.

  1. 预测: 短期预测, 长期(半年/1年,3年预测), 行业预测/单公司预测
  2. 信息收集, 信息推理

诊断 Python 占用一个 CPU 的问题

早上刚打开 MAC 笔记本 5分钟, 就提示我电池快没电了, 于是感觉给它供电. 紧接着, 就听到风扇呼呼作响, 于是查看 Activity Monitor, 发现有个 Python 进程几乎占用一个CPU, 感觉有 bug, 也许是项目的那个代码没写好. hmm, 生产环境不会也是这样吧?

Activity_Monitor.png

先确定进程信息

有了进程号, 进程很容易确定.

% ps aux  | grep 24315
xiatian          24315  99.3  0.0 36938856   9804   ??  R    Mon10PM 1044:13.73 /usr/local/Cellar/[email protected]/3.11.11/Frameworks/Python.framework/Versions/3.11/Resources/Python.app/Contents/MacOS/Python /Users/supra/work/projects/agent-ui/main.py

再做 CPU profiling

py-spy 是一个非常流行的采样 profiler,可以在不修改代码的情况下分析任何正在运行的 Python 程序。

pip install py-spy
py-spy record -o profile.svg --pid 24315

火焰图如下:
profile_svg.png

前面三行都是 Python 自带 python3.11/threading.py 里面的代码. 最后一行是 concurrent/futures/thread.py) 的代码, 代码如下:

    try:
        while True:
            work_item = work_queue.get(block=True)
            if work_item is not None:
                work_item.run()
                # Delete references to object. See issue16284
                del work_item

                # attempt to increment idle count
                executor = executor_reference()
                if executor is not None:
                    executor._idle_semaphore.release()
                del executor
                continue

            executor = executor_reference()
            if _shutdown or executor is None or executor._shutdown:
                # Flag the executor as shutting down as early as possible if it
                # is not gc-ed yet.
                if executor is not None:
                    executor._shutdown = True
                # Notice other workers
                work_queue.put(None)
                return
            del executor
    except BaseException:
        _base.LOGGER.critical('Exception in worker', exc_info=True)

看上去从 work_queue.get(block=True) 拿 item , 每次拿到的都是 None. 那么下一个问题就是这个 work_queue 从哪里来的, 为什么会以极快的速度返回一个 None?

交叉验证

要回答上面的问题, 就要深入内存去看这个 work_queue 从哪里来的, 它引用了那些对象, 哪些对象还在引用它. 这样才能确定这个 work_queue 有什么问题. 但是, 在此之前, 我们可以去production 看一下, 看看在prod 的 Linux 上是不是有类似的问题, 结果发现完全没问题, 并且它运行的时间更长.

于是猜测, 这个问题难道只是个 MAC 有关? 或者和 MAC 休眠有关?