Skip to content

[Feature] Frequency axis: add frequency_mode (day/view) and frequency_unit, with list-based binning (also extend recency_unit to accept a list) #15

Description

@jiro-iwanaga

Overview

Two related additions on the frequency axis, plus a list-binning extension shared with the
recency axis:

  1. frequency_mode — aggregate frequency at day granularity (distinct interaction days) in
    addition to the current view granularity (interaction count). Frequency-axis counterpart of
    recency_mode (v0.6.0); reuses the {day, view} vocabulary.
  2. frequency_unit — bin the frequency value, as an int (fixed-width / periodic bins, like
    recency_unit) or a list (explicit, non-periodic bin edges).
  3. recency_unit list support — extend recency_unit to also accept a list of bin edges
    (currently int only).
# Target API
RecencyFrequencyScorer(
    user_col="user", item_col="item", time_col="datetime",
    recency_mode="day", recency_unit=1,          # int OR list (e.g. [7, 30])
    frequency_mode="view", frequency_unit=1,      # int OR list (e.g. [1, 3, 10])  ← NEW
)

Part 1 — frequency_mode

Terminology

Term Definition mode
view freq (接触回数, current) Number of interaction events per (user, item) in the observation window frequency_mode="view" (default)
day freq (接触日数, new) Number of distinct days an item was interacted with per (user, item) frequency_mode="day"

Definition

  • frequency_mode="view" (default): frequency = interaction count — current behavior.
  • frequency_mode="day": frequency = number of distinct interaction days = nunique of the day
    ordinal (_SEQUENCE_COL).

Example

A user interacts with item A:

timestamp item
2026-06-28 17:00 A
2026-06-28 16:00 A (same day)
2026-06-27 10:00 A (previous day)
  • view freq = 3 (interaction count)
  • day freq = 2 (distinct days: 06-28, 06-27)

day freq caps many same-day interactions, bounding frequency by the number of days in the
observation window. Already demonstrated via manual preprocessing in
examples/tutorial_advanced_day_freq_{en,ja}.ipynb; this makes it a first-class parameter.

Design notes

  • Default must be "view" to preserve current behavior (intentional default asymmetry vs
    recency_mode="day": classic RF is time-based for recency, count-based for frequency).
  • Orthogonal to recency_mode and the high-resolution view key: day freq uses the day ordinal
    (_SEQUENCE_COL), which always exists. No high-resolution key needed.
  • Single-groupby swap in the _recency.py builders: the frequency named-agg entry is
    (seq_col, "count") for view, (seq_col, "nunique") for day. No extra groupby.

Part 2 — frequency_unit / recency_unit binning

Both recency_unit and frequency_unit accept an int or a list:

Int u (≥ 1): fixed-width / periodic bins

The raw metric is divided into width-u bins (1-indexed; smallest value → bin 1).

  • recency: (ref - last_view) // u + 1 (current behavior).
  • frequency: (f - 1) // u + 1 (the -1 makes f = 1 fall in bin 1).
  • u = 1 (default) = no extra binning.

List [e1, e2, …, ek] (ascending): explicit, non-periodic bin edges

Inclusive upper bounds; produces k + 1 bins (the last is open-ended):

  • value ≤ e1 → bin 1
  • e1 < value ≤ e2 → bin 2
  • …
  • value > ek → bin k + 1

Example (frequency): frequency_unit=[1, 3, 10] → 1→bin 1, 2–3→bin 2, 4–10→bin 3,
11+→bin 4.
Example (recency): recency_unit=[7, 30] → 0–7 days→bin 1, 8–30→bin 2, 31+→bin 3.

Intended usage (rationale)

  • recency_unit is typically an int, exploiting calendar periodicity (e.g. 7 = weekly,
    30 ≈ monthly).
  • frequency_unit is typically a list, since interaction counts are usually grouped
    non-periodically (e.g. 1 vs 2–3 vs 4–10).

Design / interaction notes

  • frequency_unit is orthogonal to frequency_mode: it bins the resulting frequency value
    whether it is view freq or day freq.
  • recency_unit (int or list) is ignored when recency_mode="view" (recency is a rank).
  • Binning is a pure post-step on the raw value in the _recency.py builders; no extra groupby.

Out of scope / open questions

  • Exact list-edge convention (inclusive upper bound vs other) to be finalized in design; the above
    is the proposed spec.
  • recency_mode="session" remains future and separate.

Acceptance criteria

  • frequency_mode: str = "view" added; unknown values raise ValueError
  • frequency_mode="view" reproduces current results; frequency_mode="day" = distinct
    interaction days (matches example)
  • frequency_unit added (default 1); accepts int (periodic) and list (edges)
  • recency_unit extended to accept a list (int behavior unchanged; recency_unit=1 identical
    to current)
  • Validation: int ≥ 1; list = ascending positive ints; else ValueError
  • Binning applied as a single-groupby post-step in _recency.py (no extra groupby); works
    across fit(), fit_rolling(), transform()
  • frequency_mode / frequency_unit (and list recency_unit) persisted to save_zip()
    metadata and shown in show()
  • Tests added (builder unit + integration), including list-binning edge cases
  • Docs updated (functional-design.md, glossary.md, product-requirements.md); align
    glossary day freq wording to 接触日数 (currently "閲覧日数"); reference the existing
    day-freq tutorials

概要

頻度(frequency) 軸に関する2つの追加と、recency 軸と共通のリストビン化拡張:

  1. frequency_mode — 頻度を現状の view 粒度(接触回数)に加えて day 粒度(接触日数)でも
    集計する。v0.6.0 の recency_mode の頻度軸版で、{day, view} 語彙を踏襲。
  2. frequency_unit — 頻度の値をビン化する。整数(等幅・周期的ビン、recency_unit と同じ)
    または リスト(非周期的な明示ビン境界)。
  3. recency_unit のリスト対応 — recency_unit もビン境界のリストを受け付けるよう拡張(現状は
    整数のみ)。

Part 1 — frequency_mode

用語整理

用語 定義 mode
view freq(接触回数, 現状) 観測期間内の (user, item) ごとの接触イベント数 frequency_mode="view"(既定)
day freq(接触日数, 新規) (user, item) ごとに接触したユニーク日数 frequency_mode="day"

定義

  • frequency_mode="view"(既定): 頻度 = 接触回数 — 現状の挙動。
  • frequency_mode="day": 頻度 = 接触したユニーク日数 = 日序数(_SEQUENCE_COL)の nunique。

例

あるユーザーが商品 A に接触:

timestamp 商品
2026-06-28 17:00 A
2026-06-28 16:00 A(同日)
2026-06-27 10:00 A(前日)
  • view freq = 3(接触回数)
  • day freq = 2(ユニーク日: 06-28, 06-27)

day freq は同日内の多数の接触を抑え、頻度の上限を観測期間の日数で抑える。既に
examples/tutorial_advanced_day_freq_{en,ja}.ipynb で手動前処理として実演済みで、本 Issue は
これを正式なパラメータにする。

設計メモ

  • 既定は "view" 必須(現状挙動の保持)。recency_mode="day" との既定非対称は意図的(古典的 RF:
    recency は時間ベース・frequency は回数ベース)。
  • recency_mode・高解像度キーと直交: day freq は日序数(_SEQUENCE_COL)から計算でき、両 recency
    モードで常に存在するため高解像度キーは不要。
  • 単一 groupby 切替: _recency.py のビルダーで frequency の named-agg を (seq_col, "count")(view)
    ↔ (seq_col, "nunique")(day)と切り替えるだけ。groupby を増やさない。

Part 2 — frequency_unit / recency_unit のビン化

recency_unit・frequency_unit はともに 整数 または リスト を受け付ける:

整数 u(≥ 1): 等幅・周期的ビン

生の指標を幅 u の等幅ビンに分割(1 起算、最小値 → bin 1)。

  • recency: (ref - last_view) // u + 1(現状の挙動)。
  • frequency: (f - 1) // u + 1(f = 1 が bin 1 に入るよう -1)。
  • u = 1(既定)= 追加のビン化なし。

リスト [e1, e2, …, ek](昇順): 非周期的な明示ビン境界

各 e はその値以下を含む上限。k + 1 個のビンを生成(最終ビンは開区間):

  • 値 ≤ e1 → bin 1
  • e1 < 値 ≤ e2 → bin 2
  • …
  • 値 > ek → bin k + 1

例(frequency): frequency_unit=[1, 3, 10] → 1回→bin 1, 2〜3回→bin 2, 4〜10回→bin 3,
11回以上→bin 4。
例(recency): recency_unit=[7, 30] → 0〜7日→bin 1, 8〜30日→bin 2, 31日以上→bin 3。

想定する使い分け(根拠)

  • recency_unit は整数が中心。曜日・月などの周期性を使うため(例: 7=週、30≈月)。
  • frequency_unit はリストが中心。接触回数は 1回 / 2〜3回 / 4〜10回 のように非周期的に
    区切ることが多いため。

設計・相互作用メモ

  • frequency_unit は frequency_mode と直交。view freq でも day freq でも、得られた頻度値を
    ビン化する。
  • recency_unit(整数・リスト)は recency_mode="view" 時は無視(recency はランク)。
  • ビン化は _recency.py ビルダー内の生値への純粋な後処理。groupby を増やさない。

スコープ外 / 未決事項

  • リスト境界の正確な規約(上限含む方式 等)は design で確定。上記は提案仕様。
  • recency_mode="session" は将来・別扱い。

受け入れ条件

  • frequency_mode: str = "view" を追加。未知値は ValueError
  • frequency_mode="view" で現状結果と一致、frequency_mode="day" で接触ユニーク日数(例と一致)
  • frequency_unit を追加(既定 1)。整数(周期的)・リスト(境界)を受け付ける
  • recency_unit をリスト対応に拡張(整数の挙動は不変。recency_unit=1 は現状と一致)
  • バリデーション: 整数 ≥ 1/リストは昇順の正整数/それ以外は ValueError
  • ビン化は _recency.py の単一 groupby 後処理で実装(groupby を増やさない)。fit() /
    fit_rolling() / transform() で動作
  • frequency_mode / frequency_unit(およびリストの recency_unit)を save_zip() metadata と
    show() に反映
  • テスト追加(ビルダー単体+統合。リストビン化のエッジ含む)
  • docs 更新(functional-design.md / glossary.md / product-requirements.md)。glossary の
    day freq 表記を 接触日数 に揃える(現状「閲覧日数」)。既存 day-freq チュートリアルを参照

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions