moonbit-customer

    Explainable customer value analytics for MoonBit event data.

    customer-analytics
    rfm
    cohort
    retention
    attribution
    campaign-roi
    Download zip
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    2 months ago
    Downloads
    31

    No dependencies

    #moonbit-customer

    面向 MoonBit 应用的可解释客户价值分析库。它把有序客户事件转化为可审计的 RFM 指标、cohort 留存、生命周期价值、流失原因、漏斗转化、日趋势和运营策略。

    #核心能力

    • 事件校验:记录空客户标识、非法日期/金额、未来事件和重复事件的索引与原因。
    • RFM、五类可解释分群、可配置流失评分和透明的生命周期价值估计。
    • Cohort 留存、价值留存曲线、客户漏斗、日价值趋势和再激活候选。
    • 渠道归因、营销活动 ROI、预算分配、商品关联、生命周期、预测、实验评估、运营洞察和数据驱动策略目录。
    • 核心包不绑定数据库、CSV 解析器、机器学习运行时或大型框架;调用方自行选择输入适配和日期/金额单位。

    #快速开始

    moon test moon run cmd/main

    ///|
    test "README example" {
    let report = @FineRain-OI/moonbit-customer.analyze(
    [
    @FineRain-OI/moonbit-customer.Event::new("alice", 10, 120),
    @FineRain-OI/moonbit-customer.Event::new("alice", 20, 80),
    ],
    30,
    )
    inspect(report.customers[0].frequency, content="2")
    debug_inspect(report.customers[0].segment, content="Loyal")
    }

    #CLI

    运行 moon run cmd/main 可查看分析示例,并对仓库内固定种子的基准负载执行完整分析管道。

    #架构

    根包拥有公共领域类型和确定性算法;校验与分析分离,确保输入问题可追踪。归因、活动、留存和分配模块把事件转化为可解释的运营证据,insights.mbt 组合底层结果,playbooks.mbt 保存数据驱动的可审阅策略,cmd/main 仅作为轻量可运行示例。

    #基准

    仓库包含 1,200 条固定种子的基准负载,覆盖 240 个客户、365 个日期值、四个渠道标签、零值与接近上限的金额以及重复活动。它是明确标注的合成负载,不冒充生产客户数据。运行 moon run cmd/main 可复现:

    benchmark: cases=1200, customers=240, value=301680, retention_rows=1080 benchmark checksum: 312524015

    #测试

    当前测试套件包含 23 个确定性测试用例;其中两个数据驱动矩阵在运行时覆盖 950 组校验和单次订单洞察组合,并补充基准、质量发现、漏斗、趋势、归因、活动、分配、留存、商品关联、预测、实验评估和策略目录的集成场景。

    moon check --deny-warn moon test --deny-warn moon test --target native --deny-warn

    本地支持的工具链为 MoonBit stable,要求 moonc >= v0.10.9。

    #CI

    GitHub Actions 安装当前 stable MoonBit CLI,检查格式和生成接口,拒绝编译警告,运行 wasm-gc/native 测试,执行 CLI,并校验确定性基准输出。详见 .github/workflows/check.yml。

    #许可证

    Apache-2.0,见 LICENSE。

    AllocationLine

    pub struct AllocationLine {
    campaign : String
    customers : Int
    spend : Int
    expected_value : Int
    expected_roi_percent : Int
    }

    AllocationPlan

    pub struct AllocationPlan {
    lines : Array[AllocationLine]
    customers : Int
    spend : Int
    expected_value : Int
    remaining_budget : Int
    }

    AllocationRequest

    pub struct AllocationRequest {
    campaign : String
    audience : Int
    cost_per_customer : Int
    expected_value_per_customer : Int
    priority : Int
    }

    A bounded audience allocation opportunity.

    AllocationRequest::new

    fn AllocationRequest::new(campaign : String, audience : Int, cost_per_customer : Int, expected_value_per_customer : Int, priority : Int) -> AllocationRequest

    AttributionModel

    pub enum AttributionModel {
    FirstTouch
    LastTouch
    Linear
    TimeWeighted
    } derive(Eq,
    Debug
    )

    Attribution policies trade explainability for recency sensitivity.

    AttributionReport

    pub struct AttributionReport {
    credits : Array[ChannelCredit]
    total_value : Int
    total_cost : Int
    }

    BenchmarkCase

    pub struct BenchmarkCase {
    customer_id : String
    day : Int
    amount : Int
    channel : String
    }

    One deterministic workload row used by the benchmark and examples.

    CampaignExposure

    pub struct CampaignExposure {
    campaign : String
    customer_id : String
    day : Int
    cost : Int
    }

    A customer exposure to a campaign.

    CampaignExposure::new

    fn CampaignExposure::new(campaign : String, customer_id : String, day : Int, cost : Int) -> CampaignExposure

    CampaignOutcome

    pub struct CampaignOutcome {
    customer_id : String
    day : Int
    value : Int
    }

    An observed value event used to evaluate campaign outcomes.

    CampaignOutcome::new

    fn CampaignOutcome::new(customer_id : String, day : Int, value : Int) -> CampaignOutcome

    CampaignResult

    pub struct CampaignResult {
    campaign : String
    exposed_customers : Int
    converted_customers : Int
    conversion_percent : Int
    attributed_value : Int
    cost : Int
    roi_percent : Int
    average_value : Int
    }

    ChannelCredit

    pub struct ChannelCredit {
    channel : String
    touches : Int
    credited_value : Int
    cost : Int
    roi_percent : Int
    }

    ChurnScore

    pub struct ChurnScore {
    score : Int
    reasons : Array[String]
    }

    CleaningSummary

    pub struct CleaningSummary {
    accepted : Array[Event]
    rejected : Int
    }

    CohortRow

    pub struct CohortRow {
    cohort_day : Int
    period : Int
    cohort_size : Int
    active_customers : Int
    retention_percent : Int
    }

    CustomerInsight

    pub struct CustomerInsight {
    customer_id : String
    scores : ScoreVector
    segment : Segment
    churn : ChurnScore
    lifetime : ValueEstimate
    priority : Int
    actions : Array[String]
    }

    CustomerMetrics

    pub struct CustomerMetrics {
    customer_id : String
    first_day : Int
    last_day : Int
    recency : Int
    frequency : Int
    monetary : Int
    r_score : Int
    f_score : Int
    m_score : Int
    segment : Segment
    explanation : String
    }

    DailyValue

    pub struct DailyValue {
    day : Int
    orders : Int
    customers : Int
    value : Int
    average_order : Int
    }

    Daily aggregate used for lightweight operational monitoring.

    Event

    pub struct Event {
    customer_id : String
    day : Int
    amount : Int
    }

    A normalized purchase or value-creating customer event.

    Event::new

    fn Event::new(customer_id : String, day : Int, amount : Int) -> Event

    ExperimentArm

    pub struct ExperimentArm {
    experiment : String
    arm : String
    customers : Int
    conversions : Int
    value : Int
    }

    A controlled experiment arm with a stable audience label.

    ExperimentArm::new

    fn ExperimentArm::new(experiment : String, arm : String, customers : Int, conversions : Int, value : Int) -> ExperimentArm

    ExperimentResult

    pub struct ExperimentResult {
    experiment : String
    arm : String
    conversion_percent : Int
    average_value : Int
    lift_percent : Int
    is_winner : Bool
    }

    ForecastConfig

    pub struct ForecastConfig {
    window : Int
    horizon : Int
    safety_percent : Int
    }

    ForecastConfig::default

    ForecastConfig::new

    fn ForecastConfig::new(window : Int, horizon : Int, safety_percent : Int) -> ForecastConfig

    ForecastPoint

    pub struct ForecastPoint {
    period : Int
    prediction : Int
    lower_bound : Int
    upper_bound : Int
    }

    A bounded integer forecast for a future period.

    ForecastScore

    pub struct ForecastScore {
    mean_absolute_error : Int
    bias : Int
    observations : Int
    }

    FunnelReport

    pub struct FunnelReport {
    rows : Array[FunnelRow]
    overall_conversion_percent : Int
    }

    FunnelRow

    pub struct FunnelRow {
    name : String
    entered : Int
    conversion_percent : Int
    drop_off : Int
    }

    FunnelStep

    pub struct FunnelStep {
    name : String
    customers : Array[String]
    }

    A named customer journey step.

    JourneySnapshot

    pub struct JourneySnapshot {
    customer_id : String
    stage : JourneyStage
    day : Int
    value : Int
    reason : String
    }

    JourneyStage

    pub enum JourneyStage {
    Prospect
    Activated
    Engaged
    Repeat
    AtRiskJourney
    DormantJourney
    } derive(Eq,
    Debug
    )

    Customer lifecycle stages are deterministic and explainable.

    JourneyTransition

    pub struct JourneyTransition {
    from : JourneyStage
    to : JourneyStage
    customers : Int
    }

    NumericSummary

    pub struct NumericSummary {
    count : Int
    total : Int
    minimum : Int
    maximum : Int
    mean : Int
    median : Int
    lower_quartile : Int
    upper_quartile : Int
    }

    Integer-only descriptive statistics for currency and count metrics.

    Playbook

    pub struct Playbook {
    code : String
    priority : Int
    max_recency : Int
    min_frequency : Int
    action : String
    rationale : String
    }

    A concrete, explainable retention action reviewed by operators.

    PortfolioSummary

    pub struct PortfolioSummary {
    total_customers : Int
    repeat_customers : Int
    total_value : Int
    average_value : Int
    segment_counts : Array[(Segment, Int)]
    }

    ProductEvent

    pub struct ProductEvent {
    customer_id : String
    product_id : String
    day : Int
    amount : Int
    quantity : Int
    }

    A product-level value event for basket and affinity analysis.

    ProductEvent::new

    fn ProductEvent::new(customer_id : String, product_id : String, day : Int, amount : Int, quantity : Int) -> ProductEvent

    ProductMetric

    pub struct ProductMetric {
    product_id : String
    customers : Int
    orders : Int
    revenue : Int
    units : Int
    repeat_rate : Int
    average_order : Int
    }

    ProductPair

    pub struct ProductPair {
    left : String
    right : String
    shared_customers : Int
    support_percent : Int
    }

    QualityFinding

    pub struct QualityFinding {
    index : Int
    issue : QualityIssue
    customer_id : String
    message : String
    }

    QualityIssue

    pub enum QualityIssue {
    EmptyCustomerId
    NegativeDay
    NegativeAmount
    FutureEvent
    DuplicateEvent
    } derive(Eq,
    Debug
    )

    Domain-level validation findings for customer event streams.

    QualityReport

    pub struct QualityReport {
    accepted : Array[Event]
    findings : Array[QualityFinding]
    unique_customers : Int
    total_value : Int
    }

    QualityReport::duplicate_count

    fn QualityReport::duplicate_count(report : QualityReport) -> Int

    Convenience counters keep black-box consumers independent of enum constructors.

    QualityReport::empty_customer_count

    fn QualityReport::empty_customer_count(report : QualityReport) -> Int

    QualityReport::future_event_count

    fn QualityReport::future_event_count(report : QualityReport) -> Int

    QualityReport::is_clean

    fn QualityReport::is_clean(report : QualityReport) -> Bool

    QualityReport::issue_count

    fn QualityReport::issue_count(report : QualityReport, issue : QualityIssue) -> Int

    ReactivationCandidate

    pub struct ReactivationCandidate {
    customer_id : String
    recency : Int
    frequency : Int
    monetary : Int
    priority : Int
    reason : String
    }

    Report

    pub struct Report {
    customers : Array[CustomerMetrics]
    }

    RetentionPoint

    pub struct RetentionPoint {
    period : Int
    cohort_size : Int
    active_customers : Int
    retention_percent : Int
    value : Int
    }

    A retention value at a relative period from a cohort start.

    RetentionSummary

    pub struct RetentionSummary {
    points : Array[RetentionPoint]
    starting_value : Int
    ending_value : Int
    value_change_percent : Int
    retained_customers : Int
    }

    ScoreVector

    pub struct ScoreVector {
    recency : Int
    frequency : Int
    monetary : Int
    composite : Int
    }

    A stable score vector used by dashboards and downstream decision rules.

    ScoringConfig

    pub struct ScoringConfig {
    at_risk_days : Int
    dormant_days : Int
    repeat_bonus : Int
    high_value_threshold : Int
    }

    ScoringConfig::default

    fn ScoringConfig::default() -> ScoringConfig

    Segment

    pub enum Segment {
    New
    AtRisk
    Loyal
    Champions
    Dormant
    } derive(Eq,
    Debug
    )

    The explainable customer segment emitted by the default rules.

    Touchpoint

    pub struct Touchpoint {
    customer_id : String
    channel : String
    day : Int
    cost : Int
    }

    A marketing or product touch associated with a customer.

    Touchpoint::new

    fn Touchpoint::new(customer_id : String, channel : String, day : Int, cost : Int) -> Touchpoint

    TrendDirection

    pub enum TrendDirection {
    Rising
    Falling
    Flat
    } derive(Eq,
    Debug
    )

    TrendSummary

    pub struct TrendSummary {
    direction : TrendDirection
    first_value : Int
    last_value : Int
    change_percent : Int
    }

    TrendSummary::is_falling

    fn TrendSummary::is_falling(summary : TrendSummary) -> Bool

    TrendSummary::is_rising

    fn TrendSummary::is_rising(summary : TrendSummary) -> Bool

    Stable predicates for consumers that do not pattern-match the enum.

    ValueChange

    pub struct ValueChange {
    baseline : Int
    current : Int
    absolute : Int
    percent : Int
    direction : TrendDirection
    }

    ValueEstimate

    pub struct ValueEstimate {
    average_order : Int
    repeat_interval : Int
    expected_orders : Int
    estimated_value : Int
    }

    allocate_budget

    fn allocate_budget(requests : Array[AllocationRequest], budget : Int, max_customers : Int) -> AllocationPlan

    Greedily allocate a finite budget to the best positive-return opportunities.

    analyze

    fn analyze(events : Array[Event], as_of : Int) -> Report

    Analyze events with deterministic RFM rules and an explanation for every segment.

    analyze_attribution

    fn analyze_attribution(events : Array[Event], touches : Array[Touchpoint], model : AttributionModel) -> AttributionReport

    Attribute observed customer value to touchpoint channels.

    analyze_funnel

    fn analyze_funnel(steps : Array[FunnelStep]) -> FunnelReport

    Build a monotonic funnel report from arbitrary event-derived customer sets.

    applicable_playbooks

    fn applicable_playbooks(item : CustomerInsight, catalog : Array[Playbook]) -> Array[Playbook]

    Select policies applicable to one customer insight.

    attribution_models

    fn attribution_models() -> Array[AttributionModel]

    Expose the supported models in documentation and examples.

    benchmark_case_count

    fn benchmark_case_count() -> Int

    benchmark_checksum

    fn benchmark_checksum() -> Int

    A cheap correctness checksum used to detect accidental workload changes.

    benchmark_events

    fn benchmark_events() -> Array[Event]

    Materialize the benchmark rows as normal library events.

    best_playbook

    fn best_playbook(item : CustomerInsight, catalog : Array[Playbook]) -> Playbook?

    Choose the highest-priority policy for a customer, if one applies.

    build_insight

    fn build_insight(metrics : CustomerMetrics, config : ScoringConfig) -> CustomerInsight

    Combine existing deterministic analyses into one operational insight.

    clean_events

    fn clean_events(events : Array[Event]) -> CleaningSummary

    Drop malformed records while preserving the input order of valid events.

    cohort_retention

    fn cohort_retention(events : Array[Event], period_width : Int, periods : Int) -> Array[CohortRow]

    Build retention rows for each first-activity cohort and relative period.

    compare_values

    fn compare_values(baseline : Int, current : Int) -> ValueChange

    Compare two periods using integer arithmetic and an explicit zero baseline.

    customers_in_stage

    fn customers_in_stage(snapshots : Array[JourneySnapshot], stage : JourneyStage) -> Array[JourneySnapshot]

    Select customers in a particular lifecycle stage.

    daily_values

    fn daily_values(events : Array[Event]) -> Array[DailyValue]

    dormant_customer_count

    fn dormant_customer_count(snapshots : Array[JourneySnapshot]) -> Int

    estimate_lifetime_value

    fn estimate_lifetime_value(metrics : CustomerMetrics) -> ValueEstimate

    Estimate value using average order value and observed repeat interval.

    evaluate_campaign

    fn evaluate_campaign(campaign : String, exposures : Array[CampaignExposure], outcomes : Array[CampaignOutcome], window : Int) -> CampaignResult

    Evaluate conversion, value and return on investment for one campaign.

    evaluate_campaigns

    fn evaluate_campaigns(campaigns : Array[String], exposures : Array[CampaignExposure], outcomes : Array[CampaignOutcome], window : Int) -> Array[CampaignResult]

    Evaluate all named campaigns in stable input order.

    evaluate_experiment

    fn evaluate_experiment(control : ExperimentArm, treatments : Array[ExperimentArm]) -> Array[ExperimentResult]

    Compare treatment arms with an explicit control conversion rate.

    forecast

    fn forecast(values : Array[Int], config : ForecastConfig) -> Array[ForecastPoint]

    Produce a conservative moving-average forecast with explicit bounds.

    funnel_step

    fn funnel_step(name : String, customers : Array[String]) -> FunnelStep

    insights

    fn insights(report : Report, config : ScoringConfig) -> Array[CustomerInsight]

    iqr_outliers

    fn iqr_outliers(values : Array[Int]) -> Array[Int]

    Return values outside a robust interquartile fence.

    journey_snapshots

    fn journey_snapshots(report : Report, as_of : Int) -> Array[JourneySnapshot]

    Convert report metrics into a lifecycle snapshot for dashboards.

    journey_transitions

    fn journey_transitions(before : Array[JourneySnapshot], after : Array[JourneySnapshot]) -> Array[JourneyTransition]

    Count changes between two snapshots with the same customer population.

    percentile

    fn percentile(values : Array[Int], percent : Int) -> Int

    Return a nearest-rank percentile without floating-point or hidden rounding.

    product_affinity

    fn product_affinity(events : Array[ProductEvent]) -> Array[ProductPair]

    Find product pairs purchased by the same customer in the same observed basket.

    product_metrics

    fn product_metrics(events : Array[ProductEvent]) -> Array[ProductMetric]

    Aggregate product revenue, units, repeat behavior and customer reach.

    rank_campaigns

    fn rank_campaigns(results : Array[CampaignResult]) -> Array[CampaignResult]

    Rank campaigns by return and then by conversion.

    rank_channel_credit

    fn rank_channel_credit(report : AttributionReport) -> Array[ChannelCredit]

    Return channel credits from highest attributed value to lowest.

    rank_experiment_results

    fn rank_experiment_results(results : Array[ExperimentResult]) -> Array[ExperimentResult]

    Rank experiment treatments by lift, then average customer value.

    rank_insights

    fn rank_insights(items : Array[CustomerInsight]) -> Array[CustomerInsight]

    reactivation_candidates

    fn reactivation_candidates(report : Report, as_of : Int, minimum_recency : Int) -> Array[ReactivationCandidate]

    Identify repeat customers whose inactivity exceeds the configured window.

    repeat_customer_count

    fn repeat_customer_count(snapshots : Array[JourneySnapshot]) -> Int

    Stable convenience counts for dashboard consumers.

    retention_playbooks

    fn retention_playbooks() -> Array[Playbook]

    The policy catalog is data-driven so adding a policy does not duplicate code.

    rolling_mean

    fn rolling_mean(values : Array[Int], window : Int) -> Array[Int]

    Compute a rolling mean for dashboard trend lines.

    run_benchmark_workload

    fn run_benchmark_workload() -> (Int, Int, Int, Int)

    Run every principal analysis path on the fixed workload.

    score_churn

    fn score_churn(metrics : CustomerMetrics, config : ScoringConfig) -> ChurnScore

    Score churn risk from observable behavior and retain human-readable reasons.

    score_forecast

    fn score_forecast(actual : Array[Int], predicted : Array[Int]) -> ForecastScore

    Score forecasts without floating point or hidden division by zero.

    select_priority

    fn select_priority(items : Array[CustomerInsight], minimum : Int) -> Array[CustomerInsight]

    summarize

    fn summarize(report : Report) -> PortfolioSummary

    Summarize a report for dashboards without hiding the underlying customers.

    summarize_trend

    fn summarize_trend(values : Array[DailyValue]) -> TrendSummary

    summarize_values

    fn summarize_values(values : Array[Int]) -> NumericSummary

    Summarize a finite integer population with stable boundary behavior.

    top_products

    fn top_products(metrics : Array[ProductMetric], limit : Int) -> Array[ProductMetric]

    Return the top products by a selected metric without changing source order.

    validate_events

    fn validate_events(events : Array[Event], as_of : Int) -> QualityReport

    Validate events, preserving valid order and reporting every rejected row.

    value_retention_curve

    fn value_retention_curve(events : Array[Event], cohort_day : Int, period_width : Int, periods : Int) -> RetentionSummary

    Build a value-aware retention curve for one cohort.