【发布时间】:2022-08-14 02:08:41
【问题描述】:
问题
我想从项目列表中选择一个固定大小的子集,以使所选项目的标签最频繁出现的计数最小化。在英语中,我有一个包含 10000 个项目的列表的 DataFrame,生成如下。
import random
import pandas as pd
def RandLet():
alphabet = \"ABCDEFG\"
return alphabet[random.randint(0, len(alphabet) - 1)]
items = pd.DataFrame([{\"ID\": i, \"Label1\": RandLet(), \"Label2\": RandLet(), \"Label3\": RandLet()} for i in range(0, 10000)])
items.head(3)
每个项目有 3 个标签。标签是 ABCDEFG 中的字母,标签的顺序无关紧要。同一个标签可以多次标记一个项目。
[前 3 行示例]
ID Label1 Label2 Label3
0 0 G B D
1 1 C B C
2 2 C A B
从这个列表中,我想选择 1000 个项目,以尽量减少这些项目中出现频率最高的标签的出现次数。
例如,如果我的 DataFrame 只包含上述 3 个项目,而我只想选择 2 个项目,并且我选择了 ID #1 和 #2 的项目,则标签 \'C\' 出现了 3 次,\'B\ ' 出现 2 次,\'A\' 出现 1 次,所有其他标签出现 0 次 - 这些标签的最大值为 3。但是,我可以通过选择项目 #0 和 #2 做得更好,其中标签 \' B\' 出现频率最高,计数为 2。由于 2 小于 3,因此选择项目 #0 和 #2 比选择项目 #1 和 #2 更好。
在有多种方法可以选择 1000 个项目以使最大标签出现次数最小化的情况下,返回这些选择中的任何一个都可以。
我有什么
对我来说,这感觉类似于len(\"ABCDEFG\") = 7 维度中的背包问题。我想在背包里放 1000 件物品,每个物品在相关维度中的大小是该特定物品标签出现次数的总和。在这个程度上,我已经构建了这个函数来将我的项目列表转换为背包的大小列表。
def ReshapeItems(items):
alphabet = \"ABCDEFG\"
item_rebuilder = []
for i, row in items.iterrows():
letter_counter = {}
for letter in alphabet:
letter_count = sum(row[[c for c in items.columns if \"Label\" in c]].apply(lambda x: 1 if x == letter else 0))
letter_counter[letter] = letter_count
letter_counter[\"ID\"] = row[\"ID\"]
item_rebuilder.append(letter_counter)
items2 = pd.DataFrame(item_rebuilder)
return items2
items2 = ReshapeItems(items)
items2.head(3)
[前 3 行 item2 示例]
A B C D E F G ID
0 0 1 0 1 0 0 1 0
1 0 1 2 0 0 0 0 1
2 1 1 1 0 0 0 0 2
不幸的是,在那一点上,我完全被困住了。我认为背包问题的重点是最大化某种价值,同时将所选物品大小的总和保持在某个限制之下 - 但是,这里我的问题是相反的,我想最小化所选大小的总和,使得我的价值至少是一些。
我在寻找什么
尽管接收items 或items2 并返回满足我的规范的这些项目的子集的函数是理想的,但我很乐意接受任何足够详细的答案,为我指明正确的方向。
标签: python pandas dynamic-programming knapsack-problem np-hard