Уведомления

Группа в Telegram: @pythonsu

#1 Март 26, 2017 16:40:09

Student777
Зарегистрирован: 2017-03-26
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

Я в python'e не силен, так как только не давно его изучаю. Нужна Ваша помоoь по оптимизации кода, так каr моя программа считает около 11 минут, а по хорошему должна около 1-2 минут. Принимаю все возможные варианты, и очень прошу Вас помочь пожалуйста! Заранее спасибо.

 from itertools import groupby
from collections import Counter
import sqlite3
db = sqlite3.connect("D:\providers.db")
#---------------------------------Все записи-----------------------------------
cursor1 = db.cursor()
cursor1.execute("SELECT provider, geography FROM incomes")
#------------------------------------------------------------------------------
print("Выполняется составление транзакций, подождите...")
#--------------------------------ТРАНЗАКЦИИ------------------------------------
def CompilationTransaction():
    database = cursor1.fetchall()
    result = list()
    for i, j in groupby(sorted(database, key = lambda x: x[0]), lambda x: x[0]):
        result.append(list(j))
    return result
def CompilationTransactionGeography():
    result = list()
    for ElemTrans in CompilationTransaction(): 
        result.append(list(map(lambda x: x[1], ElemTrans)))
    return result
#------------------------------------------------------------------------------
class Occurrences:
    def __init__ (self, Clusters, Transaction):
        self.C = Clusters
        self.t = Transaction
#--------------Вхождение некоторого объекта в кластер(Вариант 2)---------------
    def Occ(self):
        ind = 0
        for ElemC in self.C:    
            if ElemC.count(self.t):
                ind = (self.C).index(ElemC)
                break
        self.resO = ind
#------------------------------------------------------------------------------
class SizeOrWidthCluster:
    def __init__ (self, Cluster):
        self.C = Cluster
#-------------------------------Размер кластера--------------------------------
    def SizeC(self):
        var = 0
        for ElemC in self.C:
            var += len(ElemC)
        self.resS = var
#-----Подсчет уникальных элементов в заданном кластере(Ширина кластера)--------
    def WidthC(self):     
        var = 0
        j = 0
        for ElemC in self.C:
            var = Counter(ElemC)
            j += len(var.keys())
        self.resW = j
#------------------------------------------------------------------------------
class TransactionAddOrRemov:
    def __init__(self, Clusters, Transaction, r):
        self.C = Clusters
        self.t = Transaction
        self.r = r
#-----------------------------Добавление транзакции----------------------------
    def TransactionAdd(self):
        k = 0
        S = SizeOrWidthCluster(self.C)  #размер кластера
        S.SizeC()
        N = len(self.C)   #Количество транзакций в кластере
        W = SizeOrWidthCluster(self.C) #Количество уникальных элементов География(Ширина кластера)
        W.WidthC()
        Snew = S.resS + len(self.t)
        Nnew = N + 1
        Wnew = W.resW
        for ElemC in self.C:
            k += len(list(set(self.t) & set(ElemC)))
        if (len(self.t) >= k):
            Wnew = Wnew + (len(self.t) - k)    
        self.Tadd = (Snew * Nnew / (Wnew ** self.r)) - (S.resS * N / (W.resW ** self.r))
#-----------------------------Удаление транзакции------------------------------           
    def TransactionRemov(self):
        k = 0
        l = 0
        S = SizeOrWidthCluster(self.C)  #размер кластера
        S.SizeC()
        N = len(self.C)   #Количество транзакций в кластере
        W = SizeOrWidthCluster(self.C) #Количество уникальных элементов География(Ширина кластера)
        W.WidthC()
        Snew = S.resS - len(self.t)
        Nnew = N - 1
        Wnew = W.resW
        if (len(self.C) <= 1):
            self.Trem = -(S.resS * N / (W.resW ** self.r))
        else:
            for ElemC in self.C:            
                if (ElemC != self.t):
                    k += len(list(set(self.t) & set(ElemC)))
                    l += 1
            if (len(self.t) >= k) and (l != 0):
                Wnew = Wnew - (len(self.t) - k)
            self.Trem = (Snew * Nnew / (Wnew ** self.r)) - (S.resS * N / (W.resW ** self.r))
class Clope:
    def __init__ (self, Clusters, Transactions, r):
        self.C = Clusters
        self.t = Transactions
        self.r = r
    def Algoritm(self):
#-----------------------------ЧАСТЬ 1 - ИНИЦИАЛИЗАЦИЯ--------------------------
        AddSpisok = list()
        TransactionCopy = list()
        TransactionCopy = self.t.copy()
        AddSpisok.append(TransactionCopy[0]) #Добавляем 1-ую транзакцию в не основной, пустой кластер
        (self.C).append(list(AddSpisok)) #Добавляем не основной(не пустой) кластер в основной кластер
        TransactionCopy.pop(0)
        for ElemTC in TransactionCopy: #Пробегаем по всем транзакциям
            max_TC = 0
            AddSpisok.clear()
            for ElemC in self.C: #Пробегаем по всем класерам из мн-ва С
                tadd = TransactionAddOrRemov(ElemC, ElemTC, self.r)
                tadd.TransactionAdd()
                if (tadd.Tadd > float(max_TC)):
                    max_TC = tadd.Tadd
                    NC = (self.C).index(ElemC)
            if max_TC == 0:
                AddSpisok.append(ElemTC)
                (self.C).append(list(AddSpisok))
            else:
                self.C[NC].append(ElemTC)
        f = open('Otchet1.txt', 'w')
        for ElemC in self.C:
            f.write(str(len(ElemC))+'\n')
            f.write(str(ElemC)+'\n'+'\n')
        f.close()
#-------------------------------ЧАСТЬ 2 - ИТЕРАЦИИ-----------------------------    
        print("-> Выполнена первая часть алгоритма: ИНИЦИАЛИЗАЦИЯ!")        
        for ElemT in self.t:
            max_T = 0
            ent_T = Occurrences(self.C, ElemT) #Индекс кластера, в кот. лежит данная транзакция
            ent_T.Occ()
            tr = TransactionAddOrRemov(self.C[ent_T.resO], ElemT, self.r) 
            tr.TransactionRemov()
            for ElemC in self.C: 
                tadd = TransactionAddOrRemov(ElemC, ElemT, self.r)
                tadd.TransactionAdd()
                if (ElemC != self.C[ent_T.resO]) and (tadd.Tadd + tr.Trem > float(max_T)): 
                    max_T = tadd.Tadd + tr.Trem
                    NC = (self.C).index(ElemC)
            if max_T > 0:
                self.C[NC].append(ElemT)
                for ElemCent in self.C[ent_T.resO]:
                    if ElemCent == ElemT:
                        self.C[ent_T.resO].pop(self.C[ent_T.resO].index(ElemCent))
                        break
                if len(self.C[ent_T.resO]) == 0:
                    self.C.pop(self.C.index(self.C[ent_T.resO])) #удалить пустой кластер
#------------------------------------------------------------------------------
def main():
    Cluster = list()
    Transactions = list()
    Transactions = CompilationTransactionGeography()
    r = int(input("Введите коэффициент отталкивания (целое число) r > 1: "))
    print("Производятся вычисления, подождите...")
    res = Clope(Cluster, Transactions, r)
    res.Algoritm()
    f = open('Otchet2.txt', 'w')
    for ElemC in Cluster:
        f.write(str(len(ElemC))+'\n')
        f.write(str(ElemC)+'\n'+'\n')
    f.close()
    print("Вычисления окончены!")
    return res
main()
db.close()

Офлайн

#2 Март 26, 2017 17:42:39

vic57
Зарегистрирован: 2015-07-07
Сообщения: 893
Репутация: +  126  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

в sqlite есть сортировки, лучше их применяйте
http://zametkinapolyah.ru/zametki-o-mysql/chast-12-5-sortirovka-vyborki-dannyx-v-bazax-dannyx-order-by-i-select-v-sqlite.html
если обьем выборки велик, лучше работать с записями последовательно

 db = sqlite.connect('test.db')
c = db.cursor()
c.execute('select * from users')
while True:
    data = c.fetchone()
    if not data: break
    print data #тут действия с записью
db.close()
или чтоб не дергать БД, сохранить c.fetchall() в файл, и работать с файлом построчно
родные sql методы - SELECT/WHERE/ORDER BY будут работать быстрее чем питон

Отредактировано vic57 (Март 26, 2017 17:53:05)

Офлайн

#3 Март 26, 2017 19:03:16

Student777
Зарегистрирован: 2017-03-26
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

Попробую, спасибо! Еще какие варианты, предлагайте, все во внимание возьму!

Офлайн

#4 Март 26, 2017 19:16:30

vic57
Зарегистрирован: 2015-07-07
Сообщения: 893
Репутация: +  126  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

чтобы дать конкретный совет надо видеть структуру данных
можно в csv файл перегнать, с ним работа быстрее чем с БД

  
db = sqlite.connect('test.db')
c = db.cursor()
c.execute('select * from users')
f = open('data.csv','w')
while True:
    data = c.fetchone()
    if not data: break
    l = [unicode(i) for i in data]
    f.write(';'.join(l).encode('utf-8') + '\n') #формат Excel
db.close()
f.close()

Офлайн

#5 Март 26, 2017 22:37:24

sander
Зарегистрирован: 2015-02-19
Сообщения: 317
Репутация: +  53  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

Student777
сначала сделай профайлинг, потом оптимизируй

Офлайн

#6 Март 26, 2017 22:49:57

Student777
Зарегистрирован: 2017-03-26
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

Что такое профайлинг? и как это сделать?

Офлайн

#7 Март 27, 2017 09:25:42

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9715
Репутация: +  842  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

Student777
Что такое профайлинг?
В программу запускаешь код, и она измеряет, сколько времени каждая строка выполняется. Профилировщики эти программы называются.



Офлайн

#8 Март 27, 2017 10:19:46

Student777
Зарегистрирован: 2017-03-26
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

Есть несколько вопросов и утверждений:
1) Какую библиотеку нужно подключить, чтобы заработал unicode?
2) Я понял, что мою программу замедляют двойные циклы в Часть1 и Часть2, так как они обращаются в функции, где еще один цикл, и того, если в нашей базе 50000 записей, будет очень долго считать циклы! Помогите, как избавиться от циклов, какими функциями или методам?(Если можно с примером)
И еще, до этого, где у меня считаются транзакции сначала тоже был двойной цикл, но я его убрал функцией map и заработало гораздо быстрее! но я как не пытался ее не могу использовать в главной программе! Подскажите может ее все-таки как-то можно использовать или есть другие инструменты?

Офлайн

#9 Март 27, 2017 14:54:35

vic57
Зарегистрирован: 2015-07-07
Сообщения: 893
Репутация: +  126  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

непонятно что у тебя за данные такие, обычно все в один проход делается
зайди в каталог БД, создай файл my.sqlite типа

 .mode csv
SELECT sql FROM sqlite_master;
SELECT provider, geography FROM incomes;
выполни в консоли
sqlite3 providers.db <my.sqlite  >db.txt
сколько времени займет?
в db.txt будет выборка в csv-формате, покажи несколько записей

Офлайн

#10 Март 27, 2017 22:27:42

Student777
Зарегистрирован: 2017-03-26
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Увеличить скорость (оптимизация) обработки большого файла

Данные типа Продавец и покупатель, с соответствующим номером, то есть один покупатель может взаимодействовать с многими продавцами, и один продавец с несколькими покупателями! А данные такие, что provider - это столбец в таблице продавца, а второй столбец geography - покупатель строк 50000 а столбцов всего 2.

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version