pandas - 熊猫组:如何在每个组的多个列中找到N个最大值?
问题描述
我记录一个设备并每 15 分钟读取 3 个值 ( W1
, W2
, )。W3
它们可以重复。
我需要每小时查找在该时间间隔内读取的 12 个值中的最大 3 个值是多少。我不想知道它们是什么时候发生的,只知道它们的价值。
目前我的算法远非高效和快速:
- 循环遍历每个组:
- 将 W1、W2 和 W3 转换为列表
- 将 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 的解决方案在我的演示中有效,但在我的最终版本中却没有。它抱怨无法否定的时间戳。调试 pandas 组非常困难,所以我使用了@GeorgeLPerkins 的。这(对我来说)更容易理解。
最大的问题是grouped.apply()
返回一系列列表。
从每个列表中提取每个元素是使用str
: 完成的,顾名思义,我认为它只涉及字符串,并没有考虑到它......
现在避免了每个直接循环,结果gdf
是一个数据帧,可以通过一次写入操作保存到数据库中。
我是熊猫的新手,唉,我认为这可以高度优化。
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
解决方案
我发现更简单的是:
combinedcoltop3 = []
for col in df.columns:
combinedcoltop3.extend(list(df[col].nlargest(3)))
combinedcoltop3.sort(reverse=True)
top3 = combinedcoltop3[:3]
推荐阅读
- svn - TortoiseSVN 搁置上传数据
- javascript - Ajax 发布失败并带有 php 文件
- kotlin - 如何提高此 Kotlin 代码的可读性?
- facebook - 如何按照 Facebook 应用验证流程的要求签署 Facebook 的技术提供商修正案?
- python - 如何使用opencv圈出移动的物体?
- hyperledger-fabric - Hyperledger Fabric go sdk - 交易未提交
- javascript - 如何将大量随机字节写入文件
- java - 在Java中处理请求后放置中间件
- r - 如何根据函数返回可能的变量对?
- hyperledger-fabric - Can a user1 from Org1 ensure the request from user2 from Org2 is valid by checking with the corresponding CA?