2016-08-17 3 views
-2

Я пытаюсь сформировать оптимизированный подход к разбиению списка имен файлов (вкратце примеров) в соотношении x: y на основе имен файлов. Этот список файлов был приобретен с использованием os.scandir (лучшая производительность vs os.listdir, src: Python Docs scandir).Разделение списка имен файлов в предопределенном соотношении

Пример -

файлов (расширение пренебрегаем) -

A_1, A_2, ... A_10 (здесь А имя файла и 1 является образцом номер файла)

B_1 , B_2 ... B_10

и так далее

Скажем х: у соотношение 7: 3 так Я бы хотел, чтобы 70% имен файлов (A_1..A7, B_1..B_7) и 30% (A_8 - A_10, B_8..B_10) в разных списках, не имеет значения, что первый список должен быть в таком порядке что файлы могут быть A_1, A_9, A_5 и т. д., пока они разделены на 7 файлов в списке от 1 до 3 файлов в списке 2.

Теперь необходимо отметить, что этот каталог является огромным (файлы ~ 150 тыс.) и выборки каждого типа файлов различаются, то есть, возможно, файлы с именем файла A имеют 1000 файлов или могут иметь только 5. Также имеется около 400 уникальных имен файлов.

Это текущее решение не следует называть решением вообще, поскольку оно не соответствует цели точного соотношения для каждого имени файла. В настоящее время он разбивает список fileObjects (в основном - имя типа A, число, подобное 1, данные в файле A_1 и т. Д.) В целом по соотношению x: y и пользуется тем преимуществом, что записи приводятся в произвольном порядке при использовании os.scandir.

ratio_number = int(len(list_of_fileObjects) *.7) 
list_70 = list_of_fileObjects[:ratio_number] 
list_30 = list_of_fileObjects[ratio_number:] 

Мой второй подход, который, по крайней мере, быть верным решением было создать список отдельно для каждого файла (включает в себя сортировку весь список файлов), разделить его в соотношении и сделать это для каждого файла. Я ищу более pythonic/элегантное решение этой проблемы. Любые предложения или помощь будут оценены с особой осторожностью, учитывая размер обрабатываемых данных.

+0

Что было бы полезно знать, почему downvotes? Я новичок в форуме и задаю вопросы, особенно с некоторыми исследованиями и объясняющими подходами. Это огорчает меня, а что хуже, это люди, которые отказались от комментариев. –

ответ

0

Если я правильно понимаю ситуацию, вы пытаетесь разделить одну и ту же пропорцию файлов файлов префикса. Ваш текущий метод выбирает правильную пропорцию из всего набора файлов, но он не учитывает разные префиксы имен файлов, поэтому он может не получить их в правильной пропорции (хотя в большинстве случаев это будет несколько близко).

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

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

ratio = 0.7 
prefix_dict = {} # values are lists: [number_selected_for_first_list, total_number_seen] 
first_sample = [] # gets a proportion of the files equal to ratio (for each prefix) 
second_sample = [] # gets the rest of the files 

for filename in list_of_files: 
    prefix = filename.split("_", 1)[0] 
    selected_seen = prefix_dict.setdefault(prefix, [0, 0]) 
    selected_seen[1] += 1 

    if selected_seen[0] < round(ratio * selected_seen[1]): 
     first_sample.append(filename) 
     selected_seen[0] += 1 
    else: 
     second_sample.append(filename) 

Единственная сложная часть для этого кода является использование dict.setdefault для извлечения selected_seen списка.Он, если запрошенный prefix еще не существует в словаре, в словарь под этим ключом (и возвращается) будет добавлено новое значение ([0, 0]). Более поздний код изменяет список на месте.

В зависимости от того, как именно вы хотите обрабатывать неточные пропорции, вы можете немного изменить состояние if. Я положил вызов round (который, я думаю, будет разбиваться наиболее точно), но код будет работать без него (смещение выбора по второму образцу) или с selected_seen[0] <= int(ratio * selected_seen[1]) (смещение в сторону первого образца).

Обратите внимание, что независимо от способа выбора раунда при разбиении каждого префикса существует вероятность того, что отдельные префиксы будут в конечном итоге неуравновешенными в одном направлении, что приведет к тому, что общие выборки будут неуравновешенными больше, чем вы обычно ожидаете. Например, если у вас было десять префиксов с десятью файлами (всего 100 файлов), отношение 7.5 приведет к окончательным спискам выборки из 80 и 20 файлов, а не к 75 и 25. Это происходит, поскольку каждый из префиксов получает секционированный 8 и 2 (7,5 раундов). Если у каждого файла был уникальный префикс, вы получите все в первом примере! Если очень важно, чтобы все образцы были правильными, вам может потребоваться немного вымыть выборку элементов, основываясь на общих размерах выборки.

+0

Спасибо @Blckknght Я обязательно проверю этот подход и дам вам знать результаты, ценю вашу помощь, но пока не хватает очков, чтобы проголосовать за свой ответ. –

0

Я нашел хорошее решение этой проблемы.

all_file_names = {} 

# ObjList is a list of objects but we only need 
# file_name from that object for our solution 

for x in ObjList: 
    if x.file_name not in all_file_names: 
     all_file_names[x.file_name] = 1 
    else: 
     all_file_names[x.file_name] += 1 

trainingData = [] 
testData = [] 
temp_dict = {} 

for x in ObjList: 
    ratio = int(0.7*all_file_names[x.file_name])+1 
    if x.file_name not in temp_dict: 
     temp_dict[x.file_name] = 1 
     trainingData.append(x) 
    else: 
     temp_dict[x.file_name] += 1 
     if(temp_dict[x.file_name] < ratio): 
      trainingData.append(x) 
     else: 
      testData.append(x) 
Смежные вопросы