我有以下数据帧,其中包含每小时相应的产品消耗量。我想根据类似的需求以某种方式对这些时间进行分组 但是 小时的分组必须是连续的,以便有意义。例如,有意义的小时分组可以是 10-12 但不是 (10-12、2、4-5)。
1970-01-01 08:00:00 9
1970-01-01 09:00:00 11
1970-01-01 10:00:00 28
1970-01-01 11:00:00 26
1970-01-01 12:00:00 26
1970-01-01 13:00:00 32
1970-01-01 14:00:00 24
1970-01-01 15:00:00 30
1970-01-01 16:00:00 23
1970-01-01 17:00:00 32
1970-01-01 18:00:00 27
1970-01-01 19:00:00 21
1970-01-01 20:00:00 16
1970-01-01 21:00:00 13
1970-01-01 22:00:00 1
1970-01-01 23:00:00 0
import scipy.cluster.hierarchy as hcluster
temp_data = df.values
ndata = [[td, td] for td in temp_data]
data = np.array(ndata)
# clustering
thresh = (15.0 / 100.0) * (
max(temp_data) - min(temp_data)) # Threshold 15% of the total range of data
clusters = hcluster.fclusterdata(data, thresh, criterion="distance")
total_clusters = max(clusters)
clustered_index = []
for i in range(total_clusters):
clustered_index.append([])
for i in range(len(clusters)):
clustered_index[clusters[i] - 1].append(i)
clustered_range = []
for x in clustered_index:
clustered_index_x = [temp_data[y] for y in x]
clustered_range.append((min(clustered_index_x), max(clustered_index_x)))
print(clustered_range)
上面的代码(以及所有无监督的聚类算法)产生了一些聚类值范围,但它不知道小时必须是连续的;它只是对值进行聚类。关于如何解决这个限制并同时强制执行连续的小时组的任何想法?
最佳答案
这是一个非常相似的启发式方法,试图实现您想要的。
本质上,您只需在数组中列出您的需求,并找出最大的连续子数组,其中连续元素的差异绝对值在阈值之内。您可以改变阈值以获得所需的输出。
设置:
import numpy as np, pandas as pd, datetime as dt
date = lambda i: dt.datetime.now()+dt.timedelta(i)
df = pd.DataFrame({"date":[date(i) for i in range(25)], "demand": np.random.randint(0,20,25)})
原始数组:arr = df.demand.tolist()
[7, 11, 11, 4, 6, 6, 8, 10, 18, 11, 2, 12, 16, 0, 12, 8, 11, 15, 16, 14, 18, 14, 19, 3, 15]
(绝对)差异数组:diff = [abs(arr[i]-arr[i-1]) for i in range(1,len(arr))]
[4, 0, 7, 2, 0, 2, 2, 8, 7, 9, 10, 4, 16, 12, 4, 3, 4, 1, 2, 4, 4, 5, 16, 12]
将 T 设置为 5。T 是用于窗口的阈值。这是您愿意在连续日期/小时内接受的需求差异的最大值。如果您想增加或减少可接受的差异值,请调整它。T = 5
当前子数组在每个时间戳小于 T 的间隔长度:counter = 0
intervals = []
for i in range(len(diff)):
if diff[i]<T:
counter += 1
else:
counter = 0
intervals.append(counter)
[1, 2, 0, 1, 2, 3, 4, 0, 0, 0, 0, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0]
满足条件的最大连续区间:max_interval_idx = max(range(len(intervals)), key=lambda i: intervals[i])
max_interval = intervals[max_interval_idx]
验证答案:print(arr[max_interval_idx-max_interval +1: max_interval_idx +2])
[12, 8, 11, 15, 16, 14, 18, 14]
请注意,所有连续差异都小于 5。这是你的答案:
df["date"][max_interval_idx-max_interval +1: max_interval_idx +2]
现在您可以改变 T 以获得不同的分组。
关于python - 无监督地将需求聚类为小时组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65805620/