provider ratings

This commit is contained in:
Yaroslav Polyakov 2025-04-17 15:49:01 +07:00
parent 00f2322a6a
commit 2bddda00db
8 changed files with 162 additions and 82 deletions

View file

@ -14,7 +14,8 @@ dependencies = [
"python-multipart",
"dramatiq[redis, watch]",
"markdown",
"python-frontmatter"
"python-frontmatter",
"evalidate"
]
requires-python = ">=3.8"
authors = [{ name = "Yaroslav Polyakov", email = "yaroslaff@gmail.com" }]

View file

@ -85,6 +85,40 @@ aliases = {
'4504127921282909': {
'alias': 'sheremetevo',
},
'141265770878134': {
'alias': 'lenta'
},
'141265769737695': {
'alias': 'lenta2'
},
'141265769524556': {
'alias': 'lenta3'
},
'141265769640819': {
'alias': 'auchan'
},
'141265770910298': {
'alias': 'auchan2'
},
'141265770140530': {
'alias': 'auchan3'
},
'70000001021506525': {
'alias': 'hotdogmaster'
},
'70000001051303735': {
'alias': 'hotdogmaster2'
},
'70000001017423547': {
'alias': 'hotdogmaster3'
},
}
def resolve_alias(alias: str):

View file

@ -135,6 +135,102 @@ def handle_dev(args: argparse.Namespace):
print(u.birthday())
def do_provider(args, cl):
provider = args.args[0]
try:
th = int(args.args[1])
except IndexError:
th = 0
processed = 0
provider_ratio = list()
over_th = 0
higher = 0
lower = 0
# max PROVIDER ratio among LO companies
maxlo = 0
all_providers = defaultdict(int)
for c in cl.companies(oid=args.company, name=args.name, town=args.town, report=args.report, noreport=args.noreport):
nprov = 0
total = 0
ratio = 0
pr = list()
r = list()
skipped = 0
c.load_reviews()
for rev in c.reviews():
if rev.age > settings.max_review_age:
skipped += 1
continue
total += 1
all_providers[rev.provider] += 1
if rev.provider == provider:
nprov += 1
pr.append(rev.rating)
else:
r.append(rev.rating)
if nprov:
ratio = int(100*nprov/total)
# avg rating other providers
avg = np.mean(r) if r else 0
# avg rating this provider
avg_prov = np.mean(pr) if pr else 0
if avg_prov > avg:
higher += 1
hl_str = "HI"
if avg_prov > avg + 1:
hl_str = "HI+"
else:
lower += 1
hl_str = "LO"
if ratio > maxlo:
maxlo = ratio
if ratio > th:
over_th += 1
print(f"{processed}: {c.object_id} {c.get_title()} (skip:{skipped}) {hl_str} ({avg:.1f}) {provider}: {nprov} / {total} = {ratio} ({avg_prov:.1f})")
else:
print(f"{processed}: {c.object_id} {c.get_title()} NORATINGS from {provider}")
pass
processed += 1
provider_ratio.append(ratio)
print(f"processed {processed} company providers: {dict(all_providers)}")
if processed:
# calculage mean share of this provider among all companies and amont companies which has at least one review
mean_provider_ratio = np.mean(provider_ratio) if provider_ratio else 0
nz_provider_ratio = list(filter(None, provider_ratio))
nz_mean_provider_ratio = np.mean(nz_provider_ratio) if nz_provider_ratio else 0
print(f"companies with 0 reviews from {provider}: {len(provider_ratio) - len(nz_provider_ratio)}")
print(f"avg ratio of {provider}: {nz_mean_provider_ratio:.1f} ({np.mean(mean_provider_ratio):.1f} overall)")
print(f"over th ({th}): {over_th} ({100*over_th/processed:.1f}%)")
hilorate = higher/lower if lower else 0
print(f"hi: {higher} lo: {lower} hi/lo: {hilorate:.2f}")
print(f"maxlo: {maxlo}")
def get_args():
@ -148,7 +244,7 @@ def get_args():
parser = argparse.ArgumentParser()
parser.add_argument("cmd", choices=['company-users', 'user-reviews', 'queue', 'explore', 'provider', 'sys', 'filldb', 'dev'])
parser.add_argument("cmd", choices=['company-users', 'user-reviews', 'company-reviews', 'queue', 'explore', 'provider', 'sys', 'filldb', 'dev'])
parser.add_argument("-v", "--verbose", default=False, action='store_true')
parser.add_argument("--full", default=False, action='store_true')
parser.add_argument("args", nargs='*', help='extra args')
@ -183,11 +279,18 @@ def main():
print(u)
if cmd == "user-reviews":
u = User(args.args[0])
for r in u.reviews():
print(r)
if cmd == "company-reviews":
c = Company(args.company)
c.load_reviews()
for r in c.reviews():
print(r)
elif cmd == "queue":
r = redis.Redis(decode_responses=True)
@ -269,83 +372,7 @@ def main():
print(f"Done. Inserted {inserted} records, already exists.")
elif cmd == "provider":
provider = args.args[0]
try:
th = int(args.args[1])
except IndexError:
th = 0
processed = 0
provider_ratio = list()
over_th = 0
higher = 0
lower = 0
# max PROVIDER ratio among LO companies
maxlo = 0
all_providers = defaultdict(int)
for c in cl.companies(oid=args.company, name=args.name, town=args.town, report=args.report, noreport=args.noreport):
nprov = 0
total = 0
ratio = 0
pr = list()
r = list()
c.load_reviews()
for rev in c.reviews():
total += 1
all_providers[rev.provider] += 1
if rev.provider == provider:
nprov += 1
pr.append(rev.rating)
else:
r.append(rev.rating)
if nprov:
ratio = int(100*nprov/total)
# avg rating other providers
avg = np.mean(r) if r else 0
# avg rating this provider
avg_prov = np.mean(pr) if pr else 0
if avg_prov > avg:
higher += 1
hl_str = "HI"
if avg_prov > avg + 1:
hl_str = "HI+"
else:
lower += 1
hl_str = "LO"
if ratio > maxlo:
maxlo = ratio
if ratio > th:
over_th += 1
print(f"{c.object_id} {c.get_title()} {hl_str} ({avg:.1f}) {provider}: {nprov} / {total} = {ratio} ({avg_prov:.1f})")
else:
# print(f"{c.object_id} {c.get_title()} no ratings from {provider}")
pass
processed += 1
provider_ratio.append(ratio)
print(f"processed {processed} companies: {dict(all_providers)}")
nz_provider_ratio = list(filter(None, provider_ratio))
print(f"companies with 0 reviews from {provider}: {len(provider_ratio) - len(nz_provider_ratio)}")
print(f"avg ratio of {provider}: {np.mean(nz_provider_ratio):.1f} ({np.mean(provider_ratio):.1f} overall)")
print(f"over th ({th}): {over_th} ({100*over_th/processed:.1f}%)")
hilorate = higher/lower if lower else 0
print(f"hi: {higher} lo: {lower} hi/lo: {hilorate:.2f}")
print(f"maxlo: {maxlo}")
do_provider(args, cl)
elif cmd == "explore":

View file

@ -112,7 +112,12 @@ def main():
compare(c1, c2)
elif args.cmd == "info":
c = Company(args.company)
try:
c = Company(args.company)
except AFNoCompany:
print(f"Company {args.company} not found")
return
basic = json.load(gzip.open(c.basic_path))
print(c)
print_json(data=basic)

View file

@ -20,6 +20,7 @@ from .exceptions import AFNoCompany
from .aliases import resolve_alias
from .statistics import statistics
from .aliases import aliases, resolve_alias
from .db import db
# to avoid circular import
#class RelationDict:
@ -445,6 +446,7 @@ class CompanyList():
for f in self.path.glob('*-basic.json.gz'):
company_oid = f.name.split('-')[0]
c = Company(company_oid)
# print("created c", c.report_path)
if company_match(c, oid=oid, name=name, town=town, detection=detection, report=report, noreport=noreport):

View file

@ -4,6 +4,16 @@ import json
from loguru import logger
"""
class to skip no-users (private users) and no-companies (e.g. geo objects, deleted companies)
no-company examples:
70030076824955120
70000001026994387
70000001052074829
70000001037658506
141373143684631
"""
class MyDB:
def __init__(self, directory=Path("~/.cache").expanduser()):
self.directory = directory

View file

@ -102,4 +102,4 @@ class Review():
else:
title = "<NO TITLE>"
return f'Review({self.created_str} {self.uid} {user_str} (rating:{self.rating} {photo_str}) > {self.oid} {title})'
return f'Review({self.created_str} {self.provider} {self.uid} {user_str} {self.rating}) > {self.oid} {title})'

View file

@ -39,6 +39,7 @@
</div> <!-- company info div -->
<div class="score {{divclass}}">
<p>ID: {{c.object_id}}</p>
{% if score.detections %}
<p>Detections:</p>
<ul>