Как стать автором
Поиск
Написать публикацию
Обновить

Комментарии 42

если бы еще структуру csv описали…
Так название comma separated values говорит само за себя, это простой текстовый файл, где значения разделены запятой (comma), а в данном случае точкой с запятой. Причем порядок полей не регламентирован, поэтому только глазами можно определить, где и что. Вот пример:
XXX.XXX.XXX.11;COMPANY1;992927233890;2008-06-01 19:31:35;;9;780a890bddce4248b839040046464636;16;
Вот пятое по счету поле — длительность звонка в секундах. Шестое — тот самый CallID
Пардон, шестое и седьмое, там одно поле пустое, но все равно считается.
да всё просто, в COMPANY2.csv больше записей (строк).

простой скрипт:
file1 = open("COMPANY1.csv")
file2 = open("COMPANY2.csv")
seconds1 = 0
seconds2 = 0
n1 = 0
n2 = 0
rows1 = []
rows2 = []
for row in file1.read().split("\n")[:-1]:
    rows1.append(row.split(';'))
for row in file2.read().split("\n")[:-1]:
    rows2.append(row.split(';'))
for i in range(10):
    print rows1[i][5], rows2[i][4]


выдаёт:
$ python script.py
9 10
10 10
4 5
5 5
10 11
13 14
2 3
2 3
12 13
3 5
т.е. почти в каждой записи в COMPANY2.csv больше продолжительность.
к тому же самих записей в COMPANY2 больше.
в чуть более понятном виде:

for key in rows2.keys():
    try:
        s1 += int(rows1[key])
        s2 += int(rows2[key])
     except:
        pass


получаем:
s1: 1277515
s2: 1323482
т.е. у одинаковых ключей разные значения.
ну и соответственно ключи, в которых есть разница:
for key in rows2.keys():
    try:
        if rows1[key] != rows2[key]:
            print key, rows1[key], rows2[key]
    except:
        pass

получаем:
780a0220997f43484eba250046464636 9 10
780ae213949c434816ef250046464636 33 34
780a0606a65343482c50050046464636 25 26
780a071f721c4448b85b230046464636 3 4
780a70345e8c434887aa210046464636 3 4
780a060886d0424883c8070046464636 4 5

могу предоставить полный список, если надо :)
Вот так взяли и всё испортили :-) Действительно, ларчик просто открывался, длительности одних и тех же звонков не совпадали, это в сумме и дало ту разницу. Я изначально даже и не подумал в эту сторону, настолько очевидным всё казалось, думал, ошибка в реализации подсчёта. А ошибка оказалась более фундаментальная.
А то, что количество записей разное и так было ясно из услових задачи, мы же их и искали :-)
все-равно спасибо за задачку :)
теперь можно идти спать…
И, кстати, получается, что к консенсусу нам не придти никогда с оператором, придётся использовать или наши данные или его для расчётов, т.к. такие погрешности присутствуют в каждом звонке. Жаль, что в протоколе не предусмотрена однозначная фиксация длительности сессии и только потом уже завершение звонка. Хотя опять же, её нужно реализовывать на всем участке, между каждой парой узлов и, соответственно, в каждом протоколе этого участка. Интересно, что в GSM на эту тему предусмотрено. Надо будет почитать.
ну, об этом нужно было догадаться сразу после разговора о миллионах долларов :)
а приз какой? :)
Поздно, задачка простая, первый же дядя в комментариях и решил. А я что-то совсем старый стал, соображаю туго, решал долго. Придется к врачу идти, непорядок.
решать такие здачи на баше… мисье знает тольк в извращениях =)
Ну как раз на bash-е такое и решают на коленке, очень быстро и просто. Весь набор необходимых утилит существует. А если уже нужно долгосрочное, гибкое решение, да еще и с интерфейсом, то начинают расчехлять perl и т.п.
Ну я расчехлял Perl для сверки месячной статистики. Очень удобно, весь парсинг формата CDR выполняется одним регулярным выражением )
ага, как же. у тебя кода в три раза больше, чем на питоне — это о простоте. могу поспорить код на питоне ещё и сильно быстрее был написан ввиду его объектной, а не файловой ориентации.
при этом, обрати внимание, человек не остановился на достигнутом и простыми модификациями переделывал скрипт, чтобы получить какие угодно данные. а сколько подобные переделки заняли бы на баше?
Не надо мне про питон рассказывать, это мой основной язык программирования в последнее время. А в баше именно наколенная ерунда пишется на раз, когда не знаешь, что точно нужно и как это лучше получить, на ходу меняются инструменты (изначально там две другие утилиты было внутри) и т.п. Конвейеры (pipes) «решают». А вот после этого я себе уже допишу модуль в местную утилиту на Питоне для анализа таких CDR, уже зная подводные камни и алгоритм.
Работает скрипт достаточно быстро, в основном из-за join, если городить цикл, то часами будет работать :-) Кому-то удобнее такое вот «системное» программирование делать на Питоне, реально же для этого лучше подходит shell. Некоторые еще perl любят для этих целей использовать. И оно даже работает :-)
пойду заклеивать моск, ато треснул!)
excel понимает csv, кстати. со всеми вытекающими. хотя свои скрипты это конечно увлекательнее, и есть повод для поста :)
Excel понимает CSV гораздо хуже OpenOffice Calc, если уж на то пошло. Но там есть ограничение по количеству строк, например, ну и медленно считать что-то. Ни я, ни другие не могли сходу вьехать, почему разница получается, вроде бы считаем на основе второго файла, а данные не совпадают с ним же.
по сравнению с башем выбор между опенофисом и экселем кажется мне несущественным. и, судя по данным, приведенным в посте, в ограничение по количеству строк вы влезали. и единоразовый расчет может позволить себе занять несколько секунд против миллисекунд в случае потоковой башовой обработки, если на этом он сэкономит минуты, требующиеся на написание скрипта, и десятки минут, требующиеся на недоуменное почесывание головы над результатами и отладкой тех скриптов.

но в общем это конечно дело каждого, использовать готовые инструменты или расти как специалисту на подручных задачах.
Очень мне интересно, как в Excel-е проделать эту задачу быстрее, расскажите. Проделать-то нужно ровно те же операции. Использовать встроенные функции? Писать на VB?
да, использовать встроенные функции. та же сумма минут там вообще считается парой кликов мыши. все остальное — не сильно сложнее. писать на VB — не стоит, потому что опять придется отлаживать и почесывать, чего мы стремимся избежать.
Сумма минут парой кликов и считается, никто не спорит. Изначально мне нужно было найти отсутствующие в первом файле звонки. И как это сделать?
функция MATCH
Возможно. Покажите пример, я попробую на будущее. Мне проще вот так вот выдрать и сравнить, чем искать в документации правильное использование функции на массивах, вывод этого и т.п. Суть-то в том, что сравнивая и так и так и используя данные второго файла для недостающих звонков у вас все равно получится расхождение. Сейчас это кажется очевидным мне и другим, но когда я пытался найти причину, почти никто не сообразил из тех, кто обычно соображает :-)
— сводная таблица
— vlookup
— countif
— простая сортировка
вообщем вариантов мильен :)

и это, хочу заметить, вам еще повезло — увас есть уникальные id звонков — это большая удача;)

мне же приходится по тому же направлению и с теми же целями сравнивать сдры ориентируясь на время звонка, номер а, номер б и продолжительность, по причине нефиксации терминатором id звонка… и минут там на два порядка больше :)
Как мне кажется, уровень «вхождения» в электронные таблицы значительно выше для администратора, чем для пользователя. Я там ну очень редко что-то делаю, поэтому проще и привычнее это сделать в shell. Не говоря уж о гибкости.
А так да, согласен, вариантов масса, хоть на asm ;-)
Вообще странный терминатор. На самом этот и этот оригинатор очень долго отнекивался, мол, нет у него никакого CallID. Но я его убедил, что есть :-)
А вот искать по номеру А и Б уже значительно сложнее, особенно на большом количестве звонков, там уже закон больших чисел работает, на один и тот же номер идут звонки с примерной одинаковой длительностью и черта с два там определишь.
Собственно, это не весь наш диспут был, осовная задача — убедиться, что ошибаемся мы или они и в ту сторону уже отработать диспут :-)
1. По одинаковым gid`ам у нас с ними разница в 766 минут

[minutes on identical gids]
we they delta = we — they
22058 21292 766

2. А именно: разница в секундах, число раз и сумма разниц в секундах
[delta sec on identical gids]
delta count result
1 44012 44012
2 855 1710
3 16 48
4 7 28
169 1 169

3. Т.е. получаем: сумма сумм разниц в секундах и дает в итоге те самые 766 минут.
А также мы выясняем, что в среднем чье-то оборудование стабильно обманывает
другое на 1,02 секунды
[total delta in seconds and minutes]
seconds minutes averageDeltaInSeconds
45967 766 1,02396916976677

Время: 3 часа
Инструмент: SQL (access)
Все правильно. А я изначально неправильную аксиому взял за основу и, соответственно, искал ошибку не там.
А вот про обманывание тут вопрос неоднозначный. Это, скорее, погрешность округления и задержка передачи в сети.
Именно обман, ибо стабильное значение более менее и примерно около секунды.

Скорее это настройки, которые каждый выставил, как ему выгоднее (или на заводе так выставляют?).

Вам выгоднее, чтобы больше, а им меньше. Поэтому ваш трафик считается методом ceil, а ихний — floor.

Но точно не round`ом.

Сеть здесь точно не виновата — я чувствую, правда докуазать пока не могу, вернее не знаю как.
Вам еще повезло: на самом деле в csv файлах значение в одной колонке может содержать переводы строк.
Парсить csv файлы с переводами строк — вот это задача для умных.
"… что он отправили на нас меньше минут.." 0_o
идея для следующего поста — написать как работают операторы IP телефонии, чем живут, как гоняют трафик, какое ПО используют и пр.
Посмотрите доклад Кирилла Сюзева: Архитектурные особенности высоконагруженных систем в телекоме, на последнем HighLoad++
НЛО прилетело и опубликовало эту надпись здесь
Получается, что друг друга. Собственно, в протоколе это не предусмотрено, насколько я знаю (H.323 и SIP как минимум), поэтому они спокойно записывают 5 секунд, а мы 6, т.к. у нас уже 6 насчиталось. А потом финансисты это как-то разруливают, честно говоря, технически мы ничего не делаем.
А чем собственно они регулирут такие споры? Как там можно решить спор на пару миллионов?
НЛО прилетело и опубликовало эту надпись здесь
вспомнилась другая загадка:
Три солдата пришли на рынок покупать гуся. Бабуля объявила цену — 30 рублей. Солдаты скинулись по 10 рублей, взяли гуся и пошли довольные. У бабули вдруг проснулась совесть, она вспомнила, что её внучок сейчас тоже служит в армии и решила вернуть солдатам 5 рублей. Подозвала мальчёнку-помощника, дала ему 5 рублей и сказала, чтобы он догнал солдат и вернул им эти 5 рублей. Мальчёнка побежал, а сам думает: «Их трое, рублей пять. Дам ка я им по рублю, а два себе оставлю». Догнал, отдал им по рублю. В итого для солдат гусь обошелся по 9 рублей, то есть 9*3=27. Два рубля у мальченка. 27+2=29. Куда подевался 1 рубль?
Ха, прикольно. Я на пару минут впал в ступор пока не понял, что солдаты отдали 27 рублей, а мальчик получил 2 рубля.
примерно так 25 + 2 = 27
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации