yeref 0.24.65__py3-none-any.whl → 0.24.66__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
yeref/yeref.py CHANGED
@@ -16235,77 +16235,11 @@ async def return_unit_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16235
16235
 
16236
16236
  async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16237
16237
  try:
16238
- # Получаем всех пользователей
16239
16238
  sql = 'SELECT USER_TID, USER_VARS, USER_LSTS FROM "USER"'
16240
16239
  data_users = await db_select_pg(sql, (), BASE_P)
16241
16240
 
16242
- # Собираем для каждого пользователя: месяц входа и набор месяцев активности
16243
- cohorts = defaultdict(set) # cohort_month -> set(USER_TID)
16244
- activity_months = defaultdict(set) # USER_TID -> set месяцов, в которые был DAU
16245
-
16246
- months = ["2025-06", "2025-07", "2025-08", "2025-09"]
16247
- data_users = []
16248
- for _ in range(20):
16249
- # дата входа
16250
- entry_month = random.choice(months)
16251
- entry_day = random.randint(1, 28)
16252
- entry_date = f"{entry_month}-{entry_day:02}"
16253
- entry_dt_obj = datetime.strptime(entry_date, '%Y-%m-%d')
16254
- entry_dt = f"{entry_dt_obj.strftime('%d-%m-%Y')}_{datetime.now().strftime('%H-%M-%S')}"
16255
- utm = random.choice(["/start", "/startapp"])
16256
-
16257
- # месяцы от входа и дальше
16258
- valid_months = [m for m in months if datetime.strptime(m + "-01", "%Y-%m-%d") >= entry_dt_obj.replace(day=1)]
16259
- if not valid_months:
16260
- valid_months = [entry_month]
16261
-
16262
- user_mau = sorted(random.sample(valid_months, k=random.randint(1, len(valid_months))))
16263
- user_dau_dates = set()
16264
- txs, payments = [], []
16265
-
16266
- # платеж
16267
- if user_mau:
16268
- pay_month = random.choice(user_mau)
16269
- pay_day = random.randint(1, 28)
16270
- pay_date = f"{pay_month}-{pay_day:02}"
16271
- dt_pay = datetime.strptime(pay_date, "%Y-%m-%d")
16272
- # if dt_pay >= entry_dt_obj:
16273
- payments = [{
16274
- "TYPE": random.choice(["don", "sub", "pst"]),
16275
- "DT_START": f"{dt_pay.strftime('%d-%m-%Y')}_14-00-00",
16276
- "DT_END": "0",
16277
- "AMOUNT": str(random.randint(1, 10))
16278
- }]
16279
- user_dau_dates.add(pay_date)
16280
-
16281
- # вход в приложение
16282
- user_dau_dates.add(entry_date)
16283
- for m in user_mau:
16284
- day = random.randint(1, 28)
16285
- visit = f"{m}-{day:02}"
16286
- dt_visit = datetime.strptime(visit, "%Y-%m-%d")
16287
- if dt_visit >= entry_dt_obj and random.random() < 0.7:
16288
- user_dau_dates.add(visit)
16289
-
16290
- # статусы (отток) с низкой вероятностью
16291
- USER_STATUSES = []
16292
- if random.random() < 0.2: # 10% шанс оттока
16293
- churn_month = random.choice(valid_months)
16294
- churn_day = random.randint(1, 28)
16295
- churn_date = f"{churn_month}-{churn_day:02}"
16296
- churn_ts = datetime.strptime(churn_date, "%Y-%m-%d").strftime("%d-%m-%Y") + "_23-59-59"
16297
- USER_STATUSES = [{random.choice(["left", "kicked"]): churn_ts}]
16298
-
16299
- user_dau = sorted(user_dau_dates)
16300
- wallet = f"wallet{random.randint(1, 100)}" if txs else random.choice([f"wallet{random.randint(1, 100)}", ""])
16301
-
16302
- data_users.append((
16303
- random.randint(100000, 999999),
16304
- json.dumps({"USER_WALLET": wallet, "USER_UTM": utm, "USER_DT": entry_dt}),
16305
- json.dumps({"USER_DAU": user_dau, "USER_MAU": user_mau, "USER_TXS": txs,
16306
- "USER_PAYMENTS": payments, "USER_STATUSES": USER_STATUSES})
16307
- ))
16308
- print(f"gen {data_users=}")
16241
+ cohorts = defaultdict(set)
16242
+ activity_months = defaultdict(set)
16309
16243
 
16310
16244
  for USER_TID, USER_VARS, USER_LSTS in data_users:
16311
16245
  USER_VARS = json.loads(USER_VARS or "{}")
@@ -16313,11 +16247,12 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16313
16247
  USER_DT = USER_VARS.get("USER_DT", "")
16314
16248
  USER_DAU = USER_LSTS.get("USER_DAU", [])
16315
16249
 
16316
- # вычисляем месяц входа
16250
+ if not USER_DT:
16251
+ continue
16252
+
16317
16253
  entry_mo = datetime.strptime(USER_DT, "%d-%m-%Y_%H-%M-%S").strftime("%Y-%m")
16318
16254
  cohorts[entry_mo].add(USER_TID)
16319
16255
 
16320
- # сохраняем месяцы активности
16321
16256
  for day_str in USER_DAU:
16322
16257
  try:
16323
16258
  mo = datetime.strptime(day_str, "%Y-%m-%d").strftime("%Y-%m")
@@ -16325,10 +16260,8 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16325
16260
  except:
16326
16261
  pass
16327
16262
 
16328
- # Список уникальных месяцев cohort, отсортированный
16329
16263
  cohort_months = sorted(cohorts.keys())
16330
16264
 
16331
- # Функция для прибавления месяцев
16332
16265
  def add_months(mo_str, n):
16333
16266
  y, m = map(int, mo_str.split("-"))
16334
16267
  total = m + n
@@ -16337,32 +16270,23 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16337
16270
  return f"{new_y:04d}-{new_m:02d}"
16338
16271
 
16339
16272
  num_cohorts = len(cohort_months)
16340
-
16341
- # Формируем таблицу: строки M1..M{num_cohorts}
16342
16273
  table = []
16343
16274
  header = ["Месяц/Когорта"]
16344
- # Добавляем в заголовок каждый cohort + его размер
16345
16275
  for mo in cohort_months:
16346
16276
  header.append(f"{mo} ({len(cohorts[mo])})")
16347
16277
  header.append("∑")
16348
16278
  table.append(header)
16349
16279
 
16350
- # Для каждой строки-месяца кортаций
16280
+ # Собираем саму таблицу
16351
16281
  for i in range(num_cohorts):
16352
16282
  row = [f"M{i+1}"]
16353
16283
  row_sum = 0
16354
- for j, cohort_mo in enumerate(cohort_months):
16355
- # вычисляем целевой месяц = cohort_mo + i месяцев
16284
+ for cohort_mo in cohort_months:
16356
16285
  target_mo = add_months(cohort_mo, i)
16357
16286
  if i == 0:
16358
- # M1 = размер когорты
16359
16287
  val = len(cohorts[cohort_mo])
16360
16288
  else:
16361
- # считаем, сколько пользователей из когорты были активны в target_mo
16362
- cnt = 0
16363
- for uid in cohorts[cohort_mo]:
16364
- if target_mo in activity_months.get(uid, set()):
16365
- cnt += 1
16289
+ cnt = sum(1 for uid in cohorts[cohort_mo] if target_mo in activity_months.get(uid, set()))
16366
16290
  val = cnt
16367
16291
  if val:
16368
16292
  row.append(str(val))
@@ -16372,14 +16296,39 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16372
16296
  row.append(str(row_sum))
16373
16297
  table.append(row)
16374
16298
 
16299
+ # Считаем общий отток по всем когортам
16300
+ total_lost = 0
16301
+ total_start = 0
16302
+ for cohort_mo in cohort_months:
16303
+ counts = []
16304
+ for i in range(num_cohorts):
16305
+ target_mo = add_months(cohort_mo, i)
16306
+ if i == 0:
16307
+ count = len(cohorts[cohort_mo])
16308
+ else:
16309
+ count = sum(1 for uid in cohorts[cohort_mo] if target_mo in activity_months.get(uid, set()))
16310
+ counts.append(count)
16311
+ for k in range(len(counts) - 1):
16312
+ start_cnt = counts[k]
16313
+ next_cnt = counts[k + 1]
16314
+ if start_cnt > 0:
16315
+ lost = start_cnt - next_cnt
16316
+ total_lost += lost
16317
+ total_start += start_cnt
16318
+
16319
+ avg_churn = (total_lost / total_start * 100) if total_start else 0
16320
+
16375
16321
  path = os.path.join(EXTRA_D, "3_cohort_metrics.csv")
16376
16322
  with open(path, "w", newline="", encoding="utf-8") as f:
16377
16323
  writer = csv.writer(f)
16378
16324
  for r in table:
16379
16325
  writer.writerow(r)
16326
+ writer.writerow([])
16327
+ writer.writerow([f"Avg monthly cohort churn: {avg_churn:.2f}%"])
16380
16328
 
16381
16329
  thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
16382
16330
  await bot.send_document(chat_id=my_tid, document=types.FSInputFile(path), thumbnail=thumb)
16331
+
16383
16332
  except Exception as e:
16384
16333
  logger.info(log_ % str(e))
16385
16334
  await asyncio.sleep(round(random.uniform(0, 1), 2))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yeref
3
- Version: 0.24.65
3
+ Version: 0.24.66
4
4
  Summary: desc-f
5
5
  Author: john smith
6
6
  Dynamic: author
@@ -0,0 +1,8 @@
1
+ yeref/__init__.py,sha256=Qpv3o6Xa78VdLcsSRmctGtpnYE9btpAkCekgGhgJyXM,49
2
+ yeref/l_.py,sha256=LMX_olmJwq-tgoALJCnhV_fGrL_i_43yBLkLIcEVqGo,1176743
3
+ yeref/tonweb.js,sha256=Jf6aFOQ1OIY4q7fINYz-m5LsI3seMus124M5SYYZmtE,443659
4
+ yeref/yeref.py,sha256=jPkWUJXO_GvUGd6SXXRnAhGNr_G0snlu5NoCgvOyI5Q,1049848
5
+ yeref-0.24.66.dist-info/METADATA,sha256=GWW789HTQT4WP3uucPD8e7cSrrUpekFvWNjSqHXdwcg,119
6
+ yeref-0.24.66.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ yeref-0.24.66.dist-info/top_level.txt,sha256=yCQKchWHbfV-3OuQPYRdi2loypD-nmbDJbtt3OuKKkY,6
8
+ yeref-0.24.66.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- yeref/__init__.py,sha256=Qpv3o6Xa78VdLcsSRmctGtpnYE9btpAkCekgGhgJyXM,49
2
- yeref/l_.py,sha256=LMX_olmJwq-tgoALJCnhV_fGrL_i_43yBLkLIcEVqGo,1176743
3
- yeref/tonweb.js,sha256=Jf6aFOQ1OIY4q7fINYz-m5LsI3seMus124M5SYYZmtE,443659
4
- yeref/yeref.py,sha256=fze5I1x5ZD0D4OgYpK1sv-bDgu2RXtMGPhDwjiwBa64,1053049
5
- yeref-0.24.65.dist-info/METADATA,sha256=Q5AZlJwo8T2kw62j1kSn8eFMPG3O6DBs7KoKHmLDWYo,119
6
- yeref-0.24.65.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- yeref-0.24.65.dist-info/top_level.txt,sha256=yCQKchWHbfV-3OuQPYRdi2loypD-nmbDJbtt3OuKKkY,6
8
- yeref-0.24.65.dist-info/RECORD,,