首页 > 解决方案 > 熊猫组:如何在每个组的多个列中找到N个最大值?

问题描述

我记录一个设备并每 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 的解决方案在我的演示中有效,但在我的最终版本中却没有。它抱怨无法否定的时间戳。调试 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

标签: pandaspandas-groupby

解决方案


我发现更简单的是:

combinedcoltop3 = []
for col in df.columns:
    combinedcoltop3.extend(list(df[col].nlargest(3)))

combinedcoltop3.sort(reverse=True)
top3 = combinedcoltop3[:3]

推荐阅读