我记录设备并每15分钟读取3个值(W1
,W2
,W3
)。它们可以重复。
我需要每小时查找在该时间间隔内已读取的12个值中最大的3个值。我不知道何时发生,只有它们的价值。
目前,我的算法还远远不够高效和快速:
我想删除循环,并使用本机pandas / numpy方法。可能吗?
编辑:在本文结尾处提出了一个可行的解决方案
这是代码:
from datetime import *
import pandas as pd
import numpy as np
df = pd.DataFrame()
date_ref = datetime(2017,12,8,0,0,0)
days = pd.date_range(date_ref, date_ref + timedelta(0.11), freq='15min')
np.random.seed(seed=1111)
data1 = np.random.randint(1, high=100, size=len(days))
data2 = data1 - np.random.randint(3, high=13, size=len(days))
data3 = data2 - np.random.randint(3, high=13, size=len(days))
df = pd.DataFrame({'TIME': days, 'W1': data1, 'W2': data2, 'W3': data3 })
df = df.set_index('TIME')
print("Original data")
print("-------------")
print(df)
print("**********************************************")
# groupby
grouped = df.groupby(pd.Grouper(freq='1H'))
print("Grouped data")
print("------------")
print list(grouped)
print("**********************************************")
print("3 largest values")
print("----------------")
for dtime, group in grouped:
w = list(group["W1"])
w2 = list(group["W2"])
w3 = list(group["W3"])
w.extend(w2)
w.extend(w3)
w = sorted(w)
max1 = w[-1]
max2 = w[-2]
max3 = w[-3]
print(dtime, max1, max2, max3)
返回:
Original data
-------------
W1 W2 W3
TIME
2017-12-08 00:00:00 78 67 57
2017-12-08 00:15:00 73 64 59
2017-12-08 00:30:00 55 50 47
2017-12-08 00:45:00 67 58 51
2017-12-08 01:00:00 62 51 40
2017-12-08 01:15:00 52 40 32
2017-12-08 01:30:00 70 64 56
2017-12-08 01:45:00 74 67 63
2017-12-08 02:00:00 72 61 56
2017-12-08 02:15:00 70 58 55
2017-12-08 02:30:00 61 49 39
**********************************************
Grouped data
------------
[(Timestamp('2017-12-08 00:00:00', freq='H'), W1 W2 W3
TIME
2017-12-08 00:00:00 78 67 57
2017-12-08 00:15:00 73 64 59
2017-12-08 00:30:00 55 50 47
2017-12-08 00:45:00 67 58 51), (Timestamp('2017-12-08 01:00:00', freq='H'), W1 W2 W3
TIME
2017-12-08 01:00:00 62 51 40
2017-12-08 01:15:00 52 40 32
2017-12-08 01:30:00 70 64 56
2017-12-08 01:45:00 74 67 63), (Timestamp('2017-12-08 02:00:00', freq='H'), W1 W2 W3
TIME
2017-12-08 02:00:00 72 61 56
2017-12-08 02:15:00 70 58 55
2017-12-08 02:30:00 61 49 39)]
**********************************************
3 largest values
----------------
(Timestamp('2017-12-08 00:00:00', freq='H'), 78, 73, 67)
(Timestamp('2017-12-08 01:00:00', freq='H'), 74, 70, 67)
(Timestamp('2017-12-08 02:00:00', freq='H'), 72, 70, 61)
解决方案
在我的代码中实现该解决方案时遇到了一些麻烦,因此在此保留后代的最终版本。也许对某人有用。
即使@jezrael的解决方案可以在我的演示中使用,也不能在我的最终版本中使用。它抱怨不可否认的时间戳。调试熊猫组非常困难,因此我使用了@GeorgeLPerkins。 (对我来说)更容易理解。
最大的问题是grouped.apply()
返回一系列列表。
使用str
从每个列表中提取每个元素:顾名思义,我认为它只与字符串有关,而没有考虑...
现在,避免了每个直接循环,结果gdf
是一个数据框,可以通过一次写入操作将其保存到数据库中。
我是熊猫的新手,bie,我认为这可以进行高度优化。
from datetime import *
import pandas as pd
import numpy as np
df = pd.DataFrame()
date_ref = datetime(2017,12,8,0,0,0)
days = pd.date_range(date_ref, date_ref + timedelta(0.11), freq='15min')
np.random.seed(seed=1111)
data1 = np.random.randint(50, high=80, size=len(days))
data2 = data1 - np.random.randint(3, high=13, size=len(days))
data3 = data2 - np.random.randint(3, high=13, size=len(days))
df = pd.DataFrame({'TIME': days, 'W1': data1, 'W2': data2, 'W3': data3 })
df = df.set_index('TIME')
#print("Original data")
#print("-------------")
#print(df)
#print("**********************************************")
# groupby
grouped = df.groupby(pd.Grouper(freq='1H'))
print("Grouped data")
print("------------")
print list(grouped)
print("**********************************************")
print("3 largest values")
print("----------------")
def operation(x):
combinedcoltop3 = []
combinedcoltop3.extend(list(x.nlargest(3, "W1")["W1"])) # reads the 3 largest W1 and return W1 only
combinedcoltop3.extend(list(x.nlargest(3, "W2")["W2"]))
combinedcoltop3.extend(list(x.nlargest(3, "W3")["W3"]))
combinedcoltop3.sort(reverse=True)
return combinedcoltop3[:3] # returns a list!
df1 = grouped.apply(operation)
gdf = pd.DataFrame()
gdf["W1"] = df1.str[0] # reads each element of the list for each row of df1
gdf["W2"] = df1.str[1]
gdf["W3"] = df1.str[2]
print(gdf)
# now gdf can be saved with a single write into the database
答案 0 :(得分:1)
您可以先通过numpy.ravel
,sort it in descending order将所有值展平到1d
数组,然后通过建立索引返回顶部3
个值:
df1 = df.groupby(pd.Grouper(freq='1H')).apply(lambda x: -np.sort(-np.ravel(x))[:3])
print (df1)
TIME
2017-12-08 00:00:00 [78, 73, 67]
2017-12-08 01:00:00 [74, 70, 67]
2017-12-08 02:00:00 [72, 70, 61]
Freq: H, dtype: object
如果需要列:
i = ['top1','top2','top3']
df1 = (df.groupby(pd.Grouper(freq='1H'))
.apply(lambda x: pd.Series(-np.sort(-np.ravel(x))[:3], index=i)))
print (df1)
top1 top2 top3
TIME
2017-12-08 00:00:00 78 73 67
2017-12-08 01:00:00 74 70 67
2017-12-08 02:00:00 72 70 61
答案 1 :(得分:1)
我发现更简单的是:
combinedcoltop3 = []
for col in df.columns:
combinedcoltop3.extend(list(df[col].nlargest(3)))
combinedcoltop3.sort(reverse=True)
top3 = combinedcoltop3[:3]