这是场景。我有一个未分类的数组(非常大),称为Gallery,其中包含成对的模板(std::vector<uint8_t>
)及其关联的ID(std::string
)。
我有一个向我提供模板的函数,并且必须返回我画廊中最相似的k
模板的ID(我使用余弦相似度在模板之间生成相似度得分)。
我考虑使用this post中讨论的堆。
但是,问题在于图库可以包含属于一个ID的多个不同模板。在我的函数中,我必须返回k
唯一 ID。
对于上下文,我正在做一个面部识别应用程序。我可以在画廊中拥有属于一个人的多个不同模板(该人使用多个不同的图像注册了画廊,因此,多个模板属于他们的ID)。搜索功能应将k
个最相似的人返回给提供的模板(因此,一次返回相同的ID不得超过一次)。
将赞赏使用C ++的高效算法。
编辑:为我建议的带有堆的解决方案剪掉了代码(无法正确处理重复项)
std::priority_queue<std::pair<double, std::string>, std::vector<std::pair<double, std::string> >, std::greater<> > queue;
for(const auto& templPair : m_gallery) {
try{
double similairty = computeSimilarityScore(templPair.templ, idTemplateDeserial);
if (queue.size() < candidateListLength) {
queue.push(std::pair<double, std::string>(similairty, templPair.id));
} else if (queue.top().first < similairty) {
queue.pop();
queue.push(std::pair<double, std::string>(similairty, templPair.id));
}
} catch(...) {
std::cout << "Unable to compute similarity\n";
continue;
}
}
// CandidateListLength number of IDs with the highest scores will be in queue
这里是一个希望有所帮助的例子。为了简单起见,我将假定已经为模板计算了相似度得分。
模板1:相似性得分:0.4,ID:赛勒斯
模板2:相似度得分:0.5,ID:詹姆斯
模板3:相似性得分:0.9,ID:鲍勃
模板4:相似度评分:0.8,ID:赛勒斯
模板5:相似度评分:0.7,ID:Vanessa
模板6:相似度评分:0.3,ID:Ariana
获取前3个得分模板的ID将返回[Bob,Cyrus,Vanessa]
答案 0 :(得分:2)
使用std :: set结构(平衡的BST)代替堆。它还可以按顺序排列元素,让您找到插入的最大和最小元素。此外,使用插入功能时,它会自动检测到重复项并将其忽略,因此内部的每个元素将始终是唯一的。复杂度是完全一样的(尽管由于常数较大,所以速度稍慢)。
编辑:我可能不正确地理解了这个问题。据我所知,您可以具有多个具有不同值的元素,这些元素应被视为重复项。
我会做什么:
制作一个地图,其中键是ID,值是集合中当前模板的模板值。
如果要添加新模板:
答案 1 :(得分:1)
实施了Maras的答案纲要。 似乎可以完成工作。
#include <iostream>
#include <vector>
#include <map>
#include <utility>
#include <string>
#include <set>
int main() {
int K = 3;
std::vector<std::pair<double, std::string>> data {
{0.4, "Cyrus"},
{0.5, "James"},
{0.9, "Bob"},
{0.8, "Cyrus"},
{0.7, "Vanessa"},
{0.3, "Ariana"},
};
std::set<std::pair<double, std::string>> mySet;
std::map<std::string, double> myMap;
for (const auto& pair: data) {
if (myMap.find( pair.second ) == myMap.end()) {
// The ID is unique
if (mySet.size() < K) {
// The size of the set is less than the size of search candidates
// Add the result to the map and the set
mySet.insert(pair);
myMap[pair.second] = pair.first;
} else {
// Check to see if the current score is larger than the worst performer in the set
auto worstPairPtr = mySet.begin();
if (pair.first > (*worstPairPtr).first) {
// The contender performed better than the worst in the set
// Remove the worst item from the set, and add the contender
// Remove the corresponding item from the map, and add the new contender
mySet.erase(worstPairPtr);
myMap.erase((*worstPairPtr).second);
mySet.insert(pair);
myMap[pair.second] = pair.first;
}
}
} else {
// The ID already exists
// Compare the contender score to the score of the existing ID.
// If the contender score is better, replace the existing item score with the new score
// Remove the old item from the set
if (pair.first > myMap[pair.second]) {
mySet.erase({myMap[pair.second], pair.second});
mySet.insert(pair);
myMap[pair.second] = pair.first;
}
}
}
for (auto it = mySet.rbegin(); it != mySet.rend(); ++it) {
std::cout << (*it).second << std::endl;
}
}
输出为
Bob
Cyrus
Vanessa