按相似度对数据进行分组的最佳算法(相同 ID)
Posted
技术标签:
【中文标题】按相似度对数据进行分组的最佳算法(相同 ID)【英文标题】:Best algorithm to group data by similarity (same ID) 【发布时间】:2015-08-05 13:42:12 【问题描述】:这里是参考代码:
struct MyData
int ID;
// other members
;
std::vector<MyData> inputData;
std::vector<std::vector<MyData> > outputData = GroupByIDs(inputData);
基本上我想要做的是迭代输入数据并按 ID 将对象分组到一个新的迷你向量中,我将把它推入输出向量。所以最后我会有一个子向量的向量,其中每个子向量都包含具有相同 ID
的对象。
是否有一种 cookie-cutter 最有效的算法可以做到这一点?因为我只能想到复杂度很高的算法。
【问题讨论】:
您有什么顾虑?如何确定组,如何确定相似度?或者如何有效地将数据从 inputData 传输到 outputData? 目前我保留了一个缓冲区来保存已经添加的 ID,并且每次迭代都会进行大量搜索,我需要一种有效的方法来完成它 好的,相似度是如何定义的?利用相似性定义的属性具有很大的优化潜力。 @peterchen 我编辑了这个问题,通过相似性我的意思是相同的 ID 【参考方案1】:您可以通过根据ID
对元素进行排序,然后使用std::upper_bound 查找每个组的结束位置来做到这一点:
例如:
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
struct MyData
int id;
std::string info;
MyData(int id, const std::string& info): id(id), info(info)
// for sorting by id
bool operator<(const MyData& d) const return id < d.id;
;
// function requires sorted data as input
std::vector<std::vector<MyData> > GroupByIDs(const std::vector<MyData>& data)
std::vector<std::vector<MyData> > groups;
decltype(data.end()) upper;
for(auto lower = data.begin(); lower != data.end(); lower = upper)
// get the upper position of all elements with the same ID
upper = std::upper_bound(data.begin(), data.end(), *lower);
// add those elements as a group to the output vector
groups.emplace_back(lower, upper);
return groups;
int main()
std::vector<MyData> data 2, "A", 4, "B", 3, "C", 4, "D", 9, "E", 3, "F";
// function requires sorted data
std::sort(data.begin(), data.end());
std::vector<std::vector<MyData> > groups = GroupByIDs(data);
for(auto const& group: groups)
if(!group.empty())
std::cout << "group: " << group.front().id << '\n';
for(auto const& d: group)
std::cout << " : " << d.info << '\n';
std::cout << '\n';
输出:
group: 2
: A
group: 3
: C
: F
group: 4
: B
: D
group: 9
: E
【讨论】:
【参考方案2】:我编辑了问题,通过相似性我的意思是相同的 ID
实施:
auto MapByIDs(std::vector<MyData> inputData)
std::map<std::vector<MyData>> result;
for(auto &x: inputData)
result[x.ID].emplace_back(std::move(x));
return result;
auto GroupByIDs(std::vector<MyData> inputData)
auto map = MapByIDs(std::move(inputData));
std::vector<std::vector<MyData>> result;
for(auto &x: map)
result.emplace_back(std::move(x.second));
return result;
auto outputData = GroupByIDs(std::move(inputData));
【讨论】:
【参考方案3】:您有点含糊,但我想您可以使用std::sort
或朋友(std::stable_sort
、std::partition
、std::stable_partition
)。然后你使用std::copy
从一个向量的迭代器到另一个向量。
【讨论】:
是的,这可能行得通,只需对它们进行排序,然后它们将每个“相同 ID”段复制到一个新向量中。【参考方案4】:如果您使用哈希表,您可以执行以下操作:
Create a hash table that maps from ID to vector<MyData>
Iterate through the input data:
If the hash table doesn't contain a vector for that ID:
Create a vector<MyData> and add it to the hash table
Push the input item into that vector<MyData>
Iterate through the entry set for the hash table:
Put the vector<MyData> into the vector<vector<MyData>>
Return the vector<vector<MyData>>
这应该类似于O(n)
平均情况。最坏的情况是O(n^2)
,我想,如果散列函数不好的话。
【讨论】:
请注意,point3&4 是使用std::unordered_map<int, std:::vector<MyData>>::operator[]
自动完成的 :-) 所以只需要 map[data.ID].push_back(data)
。
@Jarod42 我不是 C++ 程序员。感谢您的观察。【参考方案5】:
您可以保存 ID 的映射,该映射在 ID 和包含具有 ID 的项目的向量之间进行映射。然后遍历输入,为每个元素检查地图的 ID,如果是新元素,则创建一个新向量。您的复杂度将是 O(NlogM),其中 N 是输入大小和 M 个可能的 ID。
伪代码:
for(Item in inputData)
if(Item.ID in IDMap)
IDVec = IDMap[Item.ID]
IDVec.push(Item)
else
IDVec = new Vector
IDMap.push(IDVec, Item.ID)
OutputVec.push(IDVec)
【讨论】:
if(Item.ID in IDMap)
不需要映射:IDMap[Item.ID].push_back(Item);
就足够了。
确实如此,我只是写的更简单,以便清楚复杂性【参考方案6】:
选项 1:
按 ID 对输入进行排序,然后对排序后的输入进行迭代,累积和复制具有相同 ID 的数据序列,并使用向量的vector(iter, iter)
CTor 将它们复制到目标。
排序需要一个比较器:
bool less_than_by_ID(MyData const & a, MyData const & b)
return a.ID < b.ID;
选项 2:
将项目保存在以 ID 为键的 multiset 或 multimap 中,使用各自容器的 lower_bound
和 upper_bound
获取各个键的范围。 (算法上是一样的)
选项 3: 将输出数据结构更改为
std::map<int, std::vector<MyData> > outputData;
然后将数据扔到容器中:
for(auto data : inputData)
outuptData[data.ID].push_back(data);
【讨论】:
以上是关于按相似度对数据进行分组的最佳算法(相同 ID)的主要内容,如果未能解决你的问题,请参考以下文章
有没有一种根据 Jaccard 相似度对图进行聚类的有效方法?
NLPPython实例:基于文本相似度对申报项目进行查重设计
R语言计算杰卡德相似系数(Jaccard Similarity)实战:自定义函数计算Jaccard相似度对字符串向量计算Jaccard相似度将Jaccard相似度转化为Jaccard距离