当前位置: 首页 > 知识库问答 >
问题:

熊猫组:如何在每组的多个列中找到N个最大值?

郗唯
2023-03-14

我记录一个设备,每15分钟读取3个值(W1W2W3)。它们可以重复。

我需要找出每小时在该间隔内读取的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。它(对我来说)更容易理解。

最大的问题是分组。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

共有2个答案

钦景胜
2023-03-14

我发现更简单的是:

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

combinedcoltop3.sort(reverse=True)
top3 = combinedcoltop3[:3]
袁翔
2023-03-14

您可以首先通过numpy将所有值展平到1d数组。ravel,按降序排序,并通过索引返回top3值:

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
 类似资料:
  • 我有下面的数据框- 我需要一个全新的数据帧,,有3列:1.0、2.0(结合2.0和4.0)和3.0(结合3.0和5.0)。 结果将是- 您可以预期合并列中不会有重叠的值;如果一行中的一列具有有效值,那么其他列将具有NaN值。 我试过了- 而且它并没有按预期的那样工作。有没有简单有效的方法来做到这一点?

  • 问题内容: 我有以下数据框: 我需要以某种方式重塑数据框,以使每个id的前3列具有最高的值。结果将是这样的: 它显示了每本广告的前三名最畅销书。我已经使用R中的包完成了此操作,但是我正在寻找等效的pandas。 问题答案: 您可以用来查找每一行的 n个 最大项的索引: 产量

  • 问题内容: 在 pandas groupby上发布了一个新的更通用的问题:每个组中的前3个值并存储在DataFrame中,并且在那里已经找到了可行的解决方案。 在此示例中,我创建了一个数据帧,其中的一些随机数据间隔为5分钟。我想创建一个数据框( df分组 ),其中列出了每小时的 3个最高值 。 即:从这一系列价值 我非常接近解决方案,但我找不到最后一步的正确语法。我到现在为止()的结果是: 我想从

  • 问题内容: 我有两个Series,并且索引相同(非连续)。如何合并并成为DataFrame中的两列,并将其中一个索引保留为第三列? 问题答案: 我认为这是个不错的方法。如果存在它们,则使用“系列”的名称属性作为列(否则,将它们简单地编号): 注意:这扩展到2个以上的系列。

  • 我有一个数组,我需要三个数中最大的一个数和各自的索引值。我有一个这样的数组: 如何找到最大的数字及其索引值?

  • 我有一个名为的,它有4列,如下所示: 我想要的是找到关于类的每一列的最小值和最大值。换句话说,我希望得到一个类似于下面的结果: