оптимизация сравнения последовательностей файлов в каталоге с похожим, но не одинаковым содержимым с целью дедупликации - PullRequest
0 голосов
/ 27 мая 2019

Это проблема очистки данных.Чтобы использовать генеративный ИИ, вам нужны чистые непредвзятые данные.У меня есть десять тысяч миди-монофонических миди-файлов в одном каталоге, которые выскребаны из Интернета и несут чепуху для имен.Мне нужно идентифицировать похожие, но не идентичные песни (возможно, одну и ту же песню, но стилистически отличающиеся), которые смещают музыкальный генератор путем их дублирования. Поэтому я заменяю все ключевые сигналы на C, а все инструменты на пианино и т. Д. Теперь каждый midi-файлпросто серия последовательностей "note on" и "note off".таким образом, песни с сильным сходством, даже если они воспроизводятся в разных стилях, дают высокий коэффициент SequenceMatcher (difflib).Я сделал некоторый код, и он работает.но это невероятно медленно.Мне бы хотелось либо улучшить подход к открытию и закрытию файлов (возможно, с использованием словаря или двух), либо использовать многопроцессорность, но я не уверен, что делать дальше.

Я использовал рекурсивный подход и испортил двоичное сравнение, но этоПодход, как и md5sum, предназначен для сопоставления идентичных файлов.Я остановился на прогулке по каталогу и чтении в чанке, а затем во вложенном цикле, повторном просмотре каталога и чтении в чанке того же размера из другого файла в каталоге.а затем с помощью коэффициента SequenceMatcher, чтобы получить основу для сравнения.Я провел некоторое тестирование и определил размер фрагмента около 600 работ, чтобы идентифицировать подобную песню, когда установил сходство на что-то более девяноста процентов (см. Мой код).Но это все еще очень медленно, и я уверен, что есть лучший путь.Я усердно смотрел на многопоточность Параллельное сопоставление файлов, Python , но я не уверен в себе в этой области, и поскольку файлы находятся в одном каталоге, разве не стоит рассматривать тупик?Мне бы очень понравился вклад кого-то, кто знает их многопоточность и / или оптимизацию алгоритмов.

import sys
import os
import hashlib
from difflib import SequenceMatcher

def similar(a, b):
    return SequenceMatcher(None, a, b).ratio()

count=0
for dirName, subdirs, fileList in os.walk('path to my directory'):
    print('Scanning %s...' % dirName)
    for filename in fileList:
        path = os.path.join(dirName, filename)
        in_file = open(path, 'rb')  # Provide a path to disk or ISO image
        data = in_file.read(600)
        in_file.close()
        for filename2 in fileList:
            path = os.path.join(dirName, filename2)
            in_file2 = open(path, 'rb')
            data2 = in_file2.read(600)
            in_file2.close()
            if filename==filename2:
                pass
            else:
                s=similar(data,data2)
                if s>0.9:
                    print(filename +filename2+" "+str(s))

Я запустил это за разумное время в каталоге из примерно 1000 файлов (два часа или около того), и это сработало!но в каталоге из 10000 файлов он работал, ну, он работал слишком долго.

ОБНОВЛЕНИЕ : вот где я сейчас с кодом:

import multiprocessing

import sys
import os
import hashlib
from difflib import SequenceMatcher
import itertools
import string
import multiprocessing

def similar(a, b):
    return SequenceMatcher(None, a, b).ratio()

min=4
l=[]
count=0

for dirName, subdirs, fileList in os.walk('/home/dedalous/tensorflow/Music_RNN_RBM/Pop_Music_Midi/'):
  print('Scanning %s...' % dirName)
  for filename in fileList:
    path = os.path.join(dirName, filename)
    in_file = open(path, 'rb')
    s=in_file.read(800)
    in_file.close()
    l.append(s)

def get_filecontents(a,b):
  print("**********************************************************************")
  result=""
  for c in a:
    if c in string.printable:
      result+=c
      continue
    if len(result) >= min :
      print(result+" ")
    result=""
  if len(result) >= min:  # catch result at EOF
    print(result+" ")
  for c in b:
    if c in string.printable:
      result+=c
      continue
    if len(result) >= min :
      print(result+" ")
    result=""
  if len(result) >= min:  # catch result at EOF
      print(result+" ")
  print("**********************************************************************")

def enum_tasks():
  for a, b in itertools.combinations(l, 2):
    yield (a,b)

def comparison(ab):
  a,b = ab
  return (similar(a, b),a,b)

if __name__ == '__main__':
  CHUNK_SIZE = multiprocessing.cpu_count()
  pool = multiprocessing.Pool()
  for result in pool.imap(comparison, enum_tasks(), CHUNK_SIZE):
    if result[0]>.9:
      get_filecontents(result[1],result[2])
      print(result[0])

Я запускаю несколько тестов, чтобы проверить, работает ли это быстрее (должно быть, все четыре процессора работают на 100%. Надеюсь, я правильно понял метод enum_tasks ....

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...