Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> как максимально быстро сравнить два списка 
V
    Опции темы
kulibinka
Дата 8.12.2006, 02:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 191
Регистрация: 20.11.2006

Репутация: 2
Всего: 4



Как максимально быстро сравнить два спискаКак максимально быстро сравнить два списка.

Суть задачи в следующем: у меня есть список (spisok) длинны n. Он состоит из списков некоторых слов.
Например [[a, b, c], [c, k], [3, i, l, d, k], ...]
Мне нужно сравнить между собой все елементы spisok - сравнить значит подсчитать какие слова в каждых из двух елементов совпадают ((n*n + n)/2 операций).
Загвоздка в том что n у меня очень большое (десятки тысяч), и потому очень важно найти максимально быструю ф-ю сравнения двух списков из слов.

У меня есть 2 версии этой ф-ии (см. код), которые приблизительно равные по быстродействию.
Список длинны n = 300 они обрабатывают за 200 и 203 секунды соответственно (у меня 600 пентиум и 512 оперативной памяти), но это чересчур медленно для моей задачи.

Подскажите пожалуйста ф-ю с быстродействием повыше чем мои.
Код


# -*- coding: windows-1251 -*-
#    сравниваю еффективность разных ф-й для подсчета схожести всех елементов 2-х списков

import time, random
from sets import Set

def list_similarity1 (list1, list2):
    s1 = Set(list1)
    s2 = Set(list2)
    return list(s1 & s2)

def list_similarity2 (list1, list2):
    return [i for i in list1 if i in list2]

def check_similarity (check_function, spisok, message):
    """получаем ф-ю и список, возвращаем время проверки"""
    print '\n', message
    spisok_size = len(spisok)
    t = time.time()
    for i in range(spisok_size):
        for j in range(i+1, spisok_size):
            list_similarity1(spisok[i], spisok[j])
    print time.time() - t, ' seconds'


#генерация списков
print 'generation test set'
spisok = []
spisok_size = 300
all_values = [random.randint(0, 1000000) for i in range(1000000)]
for i in range(spisok_size):
    spisok.append(random.sample(all_values, 1000))

#тестирую ф-ии
print 'testing'
print (spisok_size * spisok_size + spisok_size)/2, ' operations'
check_similarity(list_similarity1, spisok, 'function with sets')
check_similarity(list_similarity2, spisok, 'function with lists')

PM MAIL   Вверх
Artemios
Дата 8.12.2006, 09:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 18
Всего: 50



Вопрос: список рассматривается как упорядоченный набор, или как неупорядоченное множество?
То есть равны ли в твоей задаче списки [a,b,c] и [b,c,a]?


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Mkdir
Дата 8.12.2006, 09:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 8.12.2006

Репутация: нет
Всего: нет



Для начала давайте исправим ошибки в коде =)

строки 20-22:
Код

for i in range(spisok_size):
    for j in range(i+1, spisok_size):
        list_similarity1(spisok[i], spisok[j])


а по идее программы предполагается следующее:
Код

for i in range(spisok_size):
    for j in range(i+1, spisok_size):
        check_function(spisok[i], spisok[j])


но после правки я так и не дождался второго результата... =)

Когда я внимательнее вник в исходник, то мне либо показалось что Вы сделали все слишком сложно, либо я плохо понял задачу.
В любом случае, вот мой вариант:

Код

import time, random

def fill_list(list, length):
    """Fill list like [[132367, 62145, 83239, 54543], [1355, 33546], ...]"""
    for i in xrange(length):
        list.append([])
        for j in xrange(random.randint(2, 10)):
            list[i].append(random.randint(0, 100000))

def list_similarity1(list1, list2):
    return list1 == list2

def check_similarity (check_function, list1, list2, message):
    print '\n', message
    t = time.time()
    res = check_function(list1, list2)
    print time.time() - t, ' seconds'
    if res:
        print "Result: True"
    else:
        print "Result: False"


lists_size = 300

print 'generation test list #1...',
list1 = []
fill_list(list1, lists_size)
print 'ok'

print 'generation test list #2...',
list2 = []
fill_list(list2, lists_size)
print 'ok'

print 'testing...'
check_similarity(list_similarity1, list1, list2, 'different lists')
check_similarity(list_similarity1, list1, list1, 'similar lists')


Если я правильно понял задачу, то моя "реализация" превзойдёт все ваши ожидания =)

Это сообщение отредактировал(а) Mkdir - 8.12.2006, 09:33
PM MAIL   Вверх
Artemios
Дата 8.12.2006, 09:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 18
Всего: 50



В случае упорядоченного набора попробуй функцию:
Код

def cmp_lists(l1,l2):
    return len(l1)==len(l2) and reduce(lambda x,y: x and not cmp(y[0],y[1]), zip(l1,l2), 1)

(хотя скорость особо гарантировать не буду smile )

Это сообщение отредактировал(а) Artemios - 8.12.2006, 09:42


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Mkdir
Дата 8.12.2006, 09:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 8.12.2006

Репутация: нет
Всего: нет



Я еще раз перечитал тему и понял, что все-таки неправильно понял =)
PM MAIL   Вверх
Artemios
Дата 8.12.2006, 10:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 18
Всего: 50



Цитата(kulibinka @  8.12.2006,  02:22 Найти цитируемый пост)
Мне нужно сравнить между собой все елементы spisok - сравнить значит подсчитать какие слова в каждых из двух елементов совпадают ((n*n + n)/2 операций).

Цитата(Artemios @  8.12.2006,  09:37 Найти цитируемый пост)
В случае упорядоченного набора попробуй функцию:

Цитата(Mkdir @  8.12.2006,  09:38 Найти цитируемый пост)
Я еще раз перечитал тему и понял, что все-таки неправильно понял =) 


Угу, я тоже неправильно. Все-таки неупорядоченные множества smile 


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
FunnyFalcon
Дата 8.12.2006, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 27.3.2006

Репутация: 4
Всего: 7



Попробуйте это. Не уверен, но может оказаться быстрее.
Код

def list_similarity1 (list1, list2):
    s2 = dict.fromkeys(list2)
    return [s for s in list1 if s in s2]

Или даже усложнить:
Код

def list_similarity1 (list1, list2):
    if len(list1)<=len(list2):
        s2 = dict.fromkeys(list2)
        return [s for s in list1 if s in s2]
    else:
        s1 = dict.fromkeys(list1)
        return [s for s in list2 if s in s1]

PM MAIL   Вверх
Artemios
Дата 8.12.2006, 11:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 18
Всего: 50



Для неупорядоченных наборов еще вопросы:
Могут ли в списках встречаться повторяющиеся элементы, и если да, то зависит ли сравнение от количества повторений, то есть равны ли списки 
[a,b,c] и [a,a,b,c], а также списки [a,a,b,c] и [a,b,b,c] ?
Распределение (вероятность) совпадающих и несовпадающих элементов в основной задаче?



--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
albertn
Дата 8.12.2006, 11:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 368
Регистрация: 17.7.2006
Где: г. Ставрополь

Репутация: 30
Всего: 34



kulibinka, приведи пример с использованием полученных сравнений, тогда будет всем более понятно
PM WWW ICQ   Вверх
Artemios
Дата 8.12.2006, 11:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 18
Всего: 50



И еще
Цитата(kulibinka @  8.12.2006,  02:22 Найти цитируемый пост)
Загвоздка в том что n у меня очень большое (десятки тысяч), и потому очень важно найти максимально быструю ф-ю сравнения двух списков из слов.

если время критично, может имеет смысл написать сравнение на Си, а потом откомпилировать, как расширение для Питона?


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
albertn
Дата 8.12.2006, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 368
Регистрация: 17.7.2006
Где: г. Ставрополь

Репутация: 30
Всего: 34



Вот кстати функция, которая возвращает матрицу смежности, и треугольную ее версию.
Код

map(lambda x:map(lambda y:Set(x)&Set(y),spisok),spisok)
map(lambda x:map(lambda y:Set(spisok[x])&Set(spisok[y]),xrange(x,len(spisok))),xrange(len(spisok)))

Работает медленнее т.к. генерирует сам список. Но если бы твоя функция генерировала подобный список возможно работала бы медленнее.

PM WWW ICQ   Вверх
Mkdir
Дата 8.12.2006, 11:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 8.12.2006

Репутация: нет
Всего: нет



Цитата(albertn @ 8.12.2006,  11:21)
kulibinka, приведи пример с использованием полученных сравнений, тогда будет всем более понятно

+1. Вполне возможно, что задачу можно совсем по-другому решать =)
PM MAIL   Вверх
kulibinka
Дата 8.12.2006, 22:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 191
Регистрация: 20.11.2006

Репутация: 2
Всего: 4



За исправление ф-ии сравнения еффективности ф-й спасибо smile

Насчет того Зачем мне это надо: Все это для вычесления того насколько похожи между собой 2 текста.
Пока я знаю только один метод - метод шинглов (http://company.yandex.ru/articles/article10.html и http://company.yandex.ru/articles/spamooborona.html).
Вкратце: вот нужно мне например сравнить 2 текста. Тогда я для каждого из них создаю список шинглов, а потом сравниваю эти 2 списка.

Из самой идеи шинглов видно что списки неупорядочены.

"Равны ли [a,b,c] и [a,a,b,c]"
это значит что первый текст на 100% лежи во втором (на 100% похож на второй), а второй на 75% похож на первый (3 из 4-х елементов полностью совпали).

"Равны ли [a,a,b,c] и [a,b,b,c]"
Аналогично - не равны. Но на 75% похожи друг на друга.

Добавлено @ 22:25 
Цитата

Распределение (вероятность) совпадающих и несовпадающих элементов в основной задаче?

совершенно неизвестные. И о длинне списков ничего неизвестно.

Цитата

если время критично, может имеет смысл написать сравнение на Си, а потом откомпилировать, как расширение для Питона? 

ох... хорошо бы попробовать, но о Си я ничегошеньки не знаю smile
PM MAIL   Вверх
kulibinka
Дата 8.12.2006, 23:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 191
Регистрация: 20.11.2006

Репутация: 2
Всего: 4



Дополнительно попробовал ф-ии от FunnyFalcon и модуль psyco.

Код

# -*- coding: windows-1251 -*-
#    сравниваю еффективность разных ф-й для подсчета схожести всех елементов 2-х списков

import time, random, psyco
from sets import Set

def check_similarity (check_function, spisok, message):
    """получаем ф-ю и список, возвращаем время проверки"""
    print '\n', message
    spisok_size = len(spisok)
    t = time.time()
    for i in range(spisok_size):
        for j in range(i+1, spisok_size):
            check_function(spisok[i], spisok[j])
    print time.time() - t, ' seconds'

def list_similarity1 (list1, list2):
    s1 = Set(list1)
    s2 = Set(list2)
    return list(s1 & s2)

def list_similarity2 (list1, list2):
    return [i for i in list1 if i in list2]

def list_similarity3 (list1, list2):
    s2 = dict.fromkeys(list2)
    return [s for s in list1 if s in s2]

def list_similarity4 (list1, list2):
    if len(list1)<=len(list2):
        s2 = dict.fromkeys(list2)
        return [s for s in list1 if s in s2]
    else:
        s1 = dict.fromkeys(list1)
        return [s for s in list2 if s in s1]

def list_similarity5 (list1, list2): 
    s1 = Set(list1) 
    return [i for i in list1 if i in s1]

list_similarity11 = psyco.proxy(list_similarity1)
list_similarity21 = psyco.proxy(list_similarity2)
list_similarity31 = psyco.proxy(list_similarity3)
list_similarity41 = psyco.proxy(list_similarity4)
list_similarity51 = psyco.proxy(list_similarity5)

#генерация списков
print 'generation test set'
spisok = []
spisok_size = 100
all_values = [random.randint(0, 1000000) for i in range(1000000)]
for i in range(spisok_size):
    spisok.append(random.sample(all_values, 1000))

#тестирую ф-ии
print 'testing'
print (spisok_size * spisok_size + spisok_size)/2, ' operations'
check_similarity(list_similarity1, spisok, '1')
check_similarity(list_similarity2, spisok, '2')
check_similarity(list_similarity3, spisok, '3')
check_similarity(list_similarity4, spisok, '4')
check_similarity(list_similarity5, spisok, '5')

check_similarity(list_similarity11, spisok, '11')
check_similarity(list_similarity21, spisok, '21')
check_similarity(list_similarity31, spisok, '31')
check_similarity(list_similarity41, spisok, '41')
check_similarity(list_similarity51, spisok, '51')


Результат тестов:

Цитата

1
20.1790001392  seconds

2
1036.97099996  seconds

3
9.59299993515  seconds

4
9.54400014877  seconds

5
36.1019999981  seconds

11
14.6410000324  seconds

21
1032.13399982  seconds

31
7.02999997139  seconds

41
7.06100010872  seconds

51
30.0729999542  seconds


FunnyFalcon*psyco работает в 3 раза быстрее чем моя самая быстрая ф-я! И это уже что-то smile
PM MAIL   Вверх
Artemios
Дата 9.12.2006, 00:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 18
Всего: 50



Цитата(kulibinka @  8.12.2006,  22:18 Найти цитируемый пост)
Все это для вычесления того насколько похожи между собой 2 текста.
Пока я знаю только один метод - метод шинглов

Здесь:
http://forum.vingrad.ru/topic-121705/view/all/index.html
над той же задачей думают.

Это сообщение отредактировал(а) Artemios - 9.12.2006, 00:51


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Python: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0921 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.