离散化
2023-03-20 15:01:39 时间
离散化
简介
离散化((discretization))可以理解为一种哈希映射,把无限空间中有限的个体映射到有限的空间中去。
具体来说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。
如下述数据:
原数据 : 20, 9, 1000, 4009
离散化后数据: 2, 1, 3, 4
元组也是同理
原数据 : {29, 49}, {10, 119}, {114514, 2}
离散化后数据: {3, 4}, {2, 5}, {6, 1}
由于离散化需要获取所有的数据后进行判断大小,以此决定每个值的映射
所以离散化不是一个在线算法
在线算法:是指它可以以序列化的方式一个个的处理输入,也就是说在开始时并不需要已经知道所有的输入。
什么时候可以使用离散化
当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。
实现
对于相同元素有两种情况:
- 相同元素离散化后依然相同
- 相同元素离散化后不相同(与原下标有关)
第二种情况的例子如下:
原数据: 9, 9, 8, 100
离散化: 2, 3, 1, 4
对于第二种情况,我们是不能将原数组去重的,因为相同元素之间是有大小关系的(此处的大小关系仅指大于与小于关系)
相同元素离散化后依然相同
实现思路:
- 拷贝数据
- 对拷贝数据进行排序
- 对排序后的数据进行去重
- 遍历原数组,对其数据在拷贝数组中二分查找下标
Java
对有序数组的去重可以通过双指针解决
(Java) 拷贝数组:System.arraycopy(原数组, 起始下标, 拷贝数组, 起始下标, 拷贝个数)
/**
* 有序数组去重
* @param nums 有效数据下标从0开始的数组
* @param n 原数组长度
* @return 去重后数组长度(尾下标+1)
*/
int adjacentRemove(int[] nums, int n) {
int slow = 0;
for (int fast = 1; fast < n; ++fast) {
if (nums[slow] != nums[fast]) {
nums[++slow] = nums[fast];
}
}
return slow + 1;
}
/**
* 离散化, 将原数据映射到0开始
* @param nums 有效数据下标从0开始的数组
* @return 离散化后的最大值+1
*/
int discrete(int[] nums) {
int n = nums.length;
int[] temp = new int[n];
System.arraycopy(nums, 0, temp, 0, n);
Arrays.sort(temp);
int cnt = adjacentRemove(temp, n);
// 下面部分可以删除
// 可以不修改原数组, 当需要时再查找映射后的下标
for (int i = 0; i < n; ++i) {
nums[i] = Arrays.binarySearch(temp, 0, cnt, nums[i]);
}
return cnt;
}
C++
C++ (algorithm) 库中的 (unique) 实现了有序数组的去重
返回去重后的末尾迭代器 unique(起始迭代器, 末尾迭代器)
注意:(unique) 并不是直接删除重复元素,而是将重复元素移动至了尾部
template <typename T>
int discrete(std::vector<T>& arr) {
std::vector<T> copy = arr;
std::sort(copy.begin(), copy.end());
auto end = std::unique(copy.begin(), copy.end());
// 下面部分可以删除
// 可以不修改原数组, 当需要时再查找映射后的下标
for (auto&& v : arr) {
v = std::lower_bound(copy.begin(), end, v) - copy.begin();
}
return end - copy.begin();
}
相同元素离散化后不相同
用处不大
实现思路:
- 用一个元组,将其本来的数据和下标绑定
- 对这个元组排序
- 按照原来的 (id) 赋值(具体看代码部分)
Java
public class Main {
public static void main(String[] args) throws IOException {
int n = 10;
Random rand = new Random();
Pair[] discrete = new Pair[n];
for (int i = 0; i < n; i++) {
discrete[i].val = rand.nextInt();
discrete[i].id = i;
}
Arrays.sort(discrete);
int[] rank = new int[n];
for (int i = 0; i < n; i++) {
// 原来id位置的数映射到 i
rank[discrete[i].id] = i;
}
}
}
class Pair implements Comparable<Pair> {
int val, id;
// 按照val升序排序
@Override
public int compareTo(Pair o) {
if (val != o.val) return val - o.val;
return id - o.id;
}
}
C++
struct node {
T val;
int id;
// 按照val升序排序
bool operator<(const node& o) const {
if (val != o.val) return val < o.val;
return id < o.id;
}
};
signed main() {
int n = 10;
std::vector<node<int>> discrete(n);
for (int i = 0; i < n; ++i) {
discrete[i].val = rand();
discrete[i].id = i;
}
std::sort(discrete.begin(), discrete.end());
std::vector<int> rank(n);
for (int i = 0; i < n; ++i) {
// 原来id位置的数映射到 i
rank[discrete[i].id] = i;
}
}
相关文章
- 从本体论开始说起——运营商关系图谱的构建及应用
- 如何成为一名数据科学家?
- 从未见过的堂兄杀了人,你的DNA是关键证据
- 20个安全可靠的免费数据源,各领域数据任你挑
- 20个安全可靠的免费数据源,各领域数据任你挑
- 阿里云李飞飞:All in Cloud时代,云原生数据库优势明显
- 基于Hadoop生态系统的一高性能数据存储格式CarbonData(性能篇)
- 大数据告诉你:10年漫威,到底有多少角色
- TigerGraph:实时图数据库助力金融风控升级
- Splunk利用Splunk Connected Experiences和Splunk Business Flow 扩大数据访问
- 大数据开发常见的9种数据分析手段
- 以免在景区看人,我爬了5W条全国景点门票数据...
- 【实战解析】基于HBase的大数据存储在京东的应用场景
- 数据科学家告诉你哪些计算机科学书籍是你应该看的
- Kafka作为大数据的核心技术,你了解多少?
- Spring Boot 整合 Redis 实现缓存操作
- 大数据学习必须掌握的五大核心技术有哪些?
- 基于Antlr在Apache Flink中实现监控规则DSL化的探索实践
- 甲骨文再次被Gartner评为分析型数据管理解决方案魔力象限领导者
- 爬取吴亦凡微博102118条转发数据,扒一扒流量的真假