2016-08-17 45 views
-2

我想要形成一个优化的方法来根据文件名在x:y比率中分割文件名列表(很快举例)。这个文件列表是使用os.scandir获得的(更好的性能vs os.listdir,src:Python Docs scandir)。以预定义的比例分割文件名列表

实施例 -

文件(扩展名忽略) -

A_1,A_2,... A_10(这里A是文件名和1是该文件的样本数)

B_1 ,B_2,... B_10

比方说,X:Y的比例为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等,只要它们将列表1中的7个文件分割成列表2中的3个文件即可。

现在必须注意的是,该目录很大(约150k个文件)每种文件类型的样本都不尽相同,也就是说,文件名A的文件可能有1000个文件,也可能只有5个文件。另外还有大约400个独特的文件名。

这个当前的解决方案根本不应该被称为解决方案,因为它违背了每个文件名的准确比率的目的。目前,它正在以x:y比率分割fileObjects列表(基本上名称像A,数字1,文件A_1内的数据等),并利用这样一个事实,即使用条目时以任意顺序生成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])(偏向第一个样本),代码就可以正常工作。

请注意,无论选择哪种方式来划分每个前缀时,都有可能单独的前缀在相同方向上最终不平衡,从而导致整体样本不平衡的数量比您通常预期的要多。例如,如果您有10个带有10个文件的前缀(对于总共100个文件),则7.5的比率将导致80和20个文件的最终样本列表,而不是75和25.因为每个前缀分区8和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)