Python на страже кошелька

в 18:58, , рубрики: python, мобильная связь, Программирование, тарифы, метки: ,
Python на страже кошелька

Однажды забрел я на сайт мобильного оператора в поисках чего-нибудь интересного. Интересным оказалось только наличие большого количества разнообразных тарифных планов на любой вкус и цвет. Тут — низкий тариф внутри сети, там — тарификация по длительности звонка, а вот и фиксированная плата за звонок. В общем, маркетологи подзаработали на славу. На сайтах других операторов картина была похожая. Мне стало интересно, насколько мои расходы на мобильную связь изменились бы в зависимости от выбранного тарифа. Но одной только силы мысли оказалось недостаточно, чтобы проанализировать статистику звонков за последние месяцы и сопоставить их со всеми тарифами. Решив отложить это дело до лучших времен, нажимаю Alt+Tab и попадаю — правильно, в консоль с заголовком Python 2.7.5+ и манящим приглашением >>>

Сразу уточню, что на местном рынке всего 3 основных оператора мобильной связи, поэтому составить таблицу наиболее привлекательных для меня тарифных планов не составило особого труда. Таковых оказалось аж целых 10:

Python на страже кошелька

Следующим шагом было получение истории звонков за последние 3 месяца. Эта функция была доступна прямо с сайта, за что спасибо моему оператору. Скачав PDF, превратил его в текстовый файл с помощью PDFMiner (кстати, тоже написан на python). Результат получился неплохой, но все же пара ошибок в тексте была замечена, поэтому вместо танцов с бубном вокруг этой утилиты данные были переведены в текстовый файл с помощью банального copy-paste прямо из PDF файла. Этот файл и был скормлен нашему питону:

#!/usr/bin/python

import MySQLdb as mysql

con = mysql.connect('localhost', 'mobile', 'mobile', 'mobile')
cur = con.cursor()
 
with open('calls.log') as f:
    for line in f:
        if 'MOC' in line:
            tokens = line.split()
            if len(tokens) == 11:
                cur.execute("INSERT INTO calls (operator, amount) VALUES('" + tokens[1] + "','" + tokens[6] + "')")
con.commit()

Учитывая, что SMS я практически не использую, выборка была сделана только по исходящим звонкам (mobile-originated call, MOC). В результате лог звонков был сохранен в MySQL базе для дальнейших манипуляций.

Дальнейшие манипуляции

Следующий шаг достаточно предсказуем — подсчитать, сколько кровно нажитых непосильным трудом денег было бы потрачено с каждого из тарифных планов. Данные по звонкам и по тарифам уже в базе. И снова немного python кода:

cur.execute("SELECT operator,plan,call_init,first_min_int,first_min_ext,min_int,min_ext FROM tariffs")
rows = cur.fetchall()
 
for row in rows:
    operator, plan, call_init, first_min_int, first_min_ext, min_int, min_ext = row
     
    # цена соединения
    cur.execute("SELECT COUNT(*) FROM calls") 
    total = call_init*cur.fetchone()[0] 
    
    # первая минута внутри сети 
    cur.execute("SELECT COALESCE(SUM(LEAST(amount,60)),0) FROM calls WHERE operator='" + operator + "'") 
    total += cur.fetchone()[0]/60*first_min_int
    
    # внутри сети, без учета первой минуты 
    cur.execute("SELECT COALESCE(SUM(amount-60),0) FROM calls WHERE operator='" + operator + "' AND amount > 60") 
    total += cur.fetchone()[0]/60*min_int
     
    # первая минута вне сети
    cur.execute("SELECT COALESCE(SUM(LEAST(amount,60)),0) FROM calls WHERE operator<>'" + operator + "'") 
    total += cur.fetchone()[0]/60*first_min_ext
     
    # вне сети, без учета первой минуты
    cur.execute("SELECT COALESCE(SUM(amount-60),0) FROM calls WHERE operator<>'" + operator + "' AND amount > 60") 
    total += cur.fetchone()[0]/60*min_ext
     
    print plan + " : " + str(round(total/100, 2)) + " у.е."

Вот что имеем на выходе:

Magti Standard : 47.1 y.e.
Magti I Alternative : 56.5 y.e.
Bani Standard : 29.72 y.e.
Bani Zero+ : 26.67 y.e.
Geocell 000 : 49.94 y.e.
Geocell 1-10 : 35.86 y.e.
Geocell 12 : 35.66 y.e.
Beeline 007 : 37.69 y.e.
Beeline Non Stop : 40.7 y.e.
Bani Universal : 39.21 y.e.

Эти же данные в виде диаграммы, для большей наглядности:

Python на страже кошелька

Выводы

Таким образом, если не рассматривать крайние значения, то среднеквадратичное отклонение получилось достаточно маленьким, в том числе и среди разных операторов связи. Однако, даже такой простой анализ может способствовать экономии более чем в 2 раза при выборе наиболее выгодного тарифного плана по сравнению с наименее выгодным, учитывая специфику конкретного пользователя.

Автор: ssha

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js