程序员老鬼

腾讯一员工在同事圈吐槽称,自己惹到了公司嫡系了,要混不下去了。

刚看到个贴子,说腾讯一员工惹到嫡系了,现在特别尴尬。网友有人支招让他主动低头道歉,结果人家压根不理,搞得他纠结是赶紧走人还是等明年拿完期权再走。

Image

我觉得这事吧,职场上“嫡系”就像公司里的防火墙,你撞上了,基本没什么好果子吃。网友说的低头认错,有时候真管用,但也得看对方愿不愿意接招。对方不回,那说明人家根本没打算给你留台阶。

换个角度想,其实核心不是面子问题,而是成本问题:现在走,损失期权;留下忍,心气憋屈。很多网友会劝“拿了钱再走”,我也倾向于这个思路。因为说到底,职场就是个交易场,能忍一忍,至少把该拿的补偿拿到手。

总的来说,别把自己陷进无谓的情绪里。能拿钱的就先忍,实在忍不住的,提前规划跳槽。毕竟,职场再复杂,也挡不住咱自己走出去的那一步。【备注:文末可领最新资料】

算法题:查找库存不平衡的店铺

昨晚十一点半,我在公司楼下拿着奶茶吹风,手机那头小李又说他们仓库有店铺一边缺货一边堆成山,我脑子里当时就“欸等等…这不是典型库存不平衡嘛”。你们懂的,老板要的是“给我一串店铺ID,越快越好”,不是长篇大论。我就边上楼边想了个简单好落地的算法,别太玄学,能跑就行。

就是每家店它有一堆 SKU,对吧。真正的“不平衡”直觉上有两种味道:一是有的 SKU 0 库存,有的 SKU 又爆仓;二是整体库存分布特别散,像泼出去的豆子。那我就给每个店打一个“失衡分”。怎么打?三个小量拼起来: 1)离散度:用变异系数 CV = 标准差 / 平均库存。平均不为 0 才有意义,不然就别算。 2)缺货率:SKU 库存等于 0 的比例。 3)过量率:SKU 库存明显偏高的比例,比如超过该店所有 SKU 库存的 90 分位,或者超过某个安全库存阈值的两倍。 最后失衡分 = αCV + β缺货率 + γ*过量率。阈值你自己定,或者就取分数 TopK 的店铺给运营盯。不要问为啥不用更复杂的那个…昨天太困了,先上能解释清楚的。

有人问实现复杂不?不复杂,线性一遍扫,算均值、标准差、分位数,哦分位数要么走近似(P² 算法、t-digest),要么偷个懒用排序,SKU 不多的话也就 logM。我这边先写个易懂版,用排序,明天你们再把分位那块换成流式的就行。

再说一个小坑,别被全 0 店铺搞炸。平均为 0 的时候,CV 别算,直接把缺货率当 1,过量率 0,然后分数就挺高了,合理——因为这家是“全缺”的极端不平衡。

我先把代码甩了,你们跑一下数据看看味道对不对,不对我们再调 αβγ 和阈值,别死磕理论。

import java.util.*;
import java.util.stream.*;

/** 输入一把店铺-SKU-库存的快照,输出不平衡店铺 TopK */
publicclassImbalanceDetector{

// 一条库存记录
publicstaticclassStockRec{
publicfinal String shopId;
publicfinal String skuId;
publicfinalint stock;
publicStockRec(String shopId, String skuId, int stock){
this.shopId = shopId; this.skuId = skuId; this.stock = stock;
        }
    }

// 输出项
publicstaticclassShopScore{
publicfinal String shopId;
publicfinaldouble score;
publicfinaldouble cv;
publicfinaldouble oosRate;
publicfinaldouble overRate;
publicShopScore(String shopId, double score, double cv, double oosRate, double overRate){
this.shopId = shopId; this.score = score; this.cv = cv; this.oosRate = oosRate; this.overRate = overRate;
        }
@Overridepublic String toString(){
return String.format(Locale.ROOT,
"shop=%s score=%.4f (cv=%.4f, oos=%.2f%%, over=%.2f%%)",
                    shopId, score, cv, oosRate*100, overRate*100);
        }
    }

/** 主逻辑:alpha/beta/gamma 为三个分量的权重,topK 取前多少家 */
publicstatic List<ShopScore> findImbalancedShops(List<StockRec> recs,
double alpha, double beta, double gamma,
int topK)
{
// 分组到店
        Map<String, List<StockRec>> byShop = recs.stream()
                .collect(Collectors.groupingBy(r -> r.shopId));

        List<ShopScore> scored = new ArrayList<>(byShop.size());

for (Map.Entry<String, List<StockRec>> e : byShop.entrySet()) {
            String shop = e.getKey();
            List<StockRec> list = e.getValue();
if (list.isEmpty()) continue;

int n = list.size();
// 库存数组
int[] arr = list.stream().mapToInt(r -> Math.max(r.stock, 0)).toArray();

// 缺货率
long zeroCnt = Arrays.stream(arr).filter(x -> x == 0).count();
double oosRate = n == 0 ? 0 : (zeroCnt * 1.0 / n);

// 平均 & 标准差(无偏不必较真)
double mean = Arrays.stream(arr).average().orElse(0);
double variance = Arrays.stream(arr)
                    .mapToDouble(x -> (x - mean)*(x - mean))
                    .sum() / (n == 0 ? 1 : n);
double std = Math.sqrt(variance);
double cv = (mean > 0) ? (std / mean) : 0;

// 过量阈值:用 90 分位(也可以换安全库存倍数)
int[] sorted = Arrays.copyOf(arr, arr.length);
            Arrays.sort(sorted);
int idx90 = (int)Math.floor(0.9 * Math.max(sorted.length - 1, 0));
int p90 = sorted[idx90];
long overCnt = Arrays.stream(arr).filter(x -> x > p90).count();
double overRate = n == 0 ? 0 : (overCnt * 1.0 / n);

// 全 0 特判:认为极端不平衡
if (mean == 0) {
                cv = 0; overRate = 0; oosRate = 1.0;
            }

double score = alpha * cv + beta * oosRate + gamma * overRate;
            scored.add(new ShopScore(shop, score, cv, oosRate, overRate));
        }

// 排序取 TopK
return scored.stream()
                .sorted(Comparator.comparingDouble((ShopScore s) -> -s.score))
                .limit(topK)
                .collect(Collectors.toList());
    }

// 小跑一把
publicstaticvoidmain(String[] args){
        List<StockRec> demo = Arrays.asList(
new StockRec("A","s1",0),
new StockRec("A","s2",200),
new StockRec("A","s3",300),
new StockRec("B","s1",10),
new StockRec("B","s2",12),
new StockRec("B","s3",11),
new StockRec("C","s1",0),
new StockRec("C","s2",0)
        );
        List<ShopScore> top = findImbalancedShops(demo, 0.6, 0.3, 0.1, 5);
        top.forEach(System.out::println);
    }
}

你看思路很直白:CV 管“散”,缺货率管“缺”,过量率管“堆”。三个量一拧绞,分高的就是“这家不太行”。复杂度基本 O(N log M)(M 是单店 SKU 数),数据巨大的话把 90 分位那步换成近似分位算法,或者直接用“均值的两倍/三倍”当过量阈值,能省排序。

还有两句碎嘴:阈值别拍脑袋,先拿近 30 天的事故店当正样本,随便做个 PR 曲线把 αβγ 调一下,别把全低库存的小店误杀了…行了不说了,我去泡面,等会儿有人要我看下 Redis 的那个…哎又来了电话我先接一下。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

最后给大家分享一份不错的副业资料,点击下方公众号,回复关键字: 副业 领取,也可以链接我领取,微信:hls404