识别一行的 N 个最大值,丢弃 table 行中剩余的底部值

Identify N maxes of a row, discarding the remaining bottom values from table rows

我遇到了以下问题,希望得到一些帮助。我已经尝试了一些东西并使用了在 Stack Overflow 上找到的一些信息(例如 this/How to apply max function for each row in KDB? and this/Iterate over current row values in kdb query, and flipping then sliding windows as ),并再次浏览了我的 Q for Mortals 但由于某种原因我遇到了障碍。

在我的table中,第一列是日期列,其余是数字。由此,我试图生成一个 table ,它只剩下 n 行的最大数量,其余设置为零或 0N (或者,如果你愿意, m 底部值已被丢弃)。

示例:

开始 table:

q)t:([] td:2001.01.01 2001.01.02 2001.01.03 2001.01.04 2001.01.05 2001.01.06; 
AA:121.5 125.0 127.0 126.0 129.2 130.0; BB:111.0 115.3 117.0 116.0 119.2
120.0; CC:120.0 126.0 125.5 128.8 135.0 130.0; DD:120.1 123.3 128.4 128.3 
127.5 126.0; NN:122.0 125.5 126.0 116.0 109.0 100.5)

td         AA    BB    CC    DD    NN   
----------------------------------------
2001.01.01 121.5 111   120   120.1 122  
2001.01.02 125   115.3 126   123.3 125.5
2001.01.03 127   117   125.5 128.4 126  
2001.01.04 126   116   128.8 128.3 116  
2001.01.05 129.2 119.2 135   127.5 109  
2001.01.06 130   120   130   126   100.5

确定每行 2 个最大值并消隐其余部分(使用 0 或 0n)时所需的最终结果:

td         AA    BB CC    DD    NN   
-------------------------------------
2001.01.01 121.5                122  
2001.01.02          126         125.5
2001.01.03 127            128.4      
2001.01.04          128.8 128.3      
2001.01.05 129.2    135              
2001.01.06 130      130              

以第1行为例,该行AA和NN中的前2个值已被保留,而BB和CC中的其他两个值已被消隐。

要仅获取最大值,即最高值,我可以执行以下操作并在后续 update 语句中使用新添加的列。但是,这里的问题是我需要找到 n 个最大值并丢弃其余的。

q)update maxes:max(AA;BB;CC;DD;NN) from t

不确定它是否有任何意义,但作为我尝试过的示例:如果我使用来自另一个堆栈溢出的提示 post 并且我在值本身上执行它我可以得到在那里,但不是 table 格式:

q)nthMax:{x (idesc x)[y-1]}
{x (idesc x)[y-1]}
q)nthMax[(121.5 111 120 120.1   122);1]
122f
q)nthMax[(121.5 111 120 120.1   122);2]
121.5

然而,当我尝试将其用作更新的一部分时或 select 然后它不起作用;我也觉得它是一种非 q 方法,所以对人们对解决上述问题的看法很感兴趣。

另一个例子是我尝试翻转 table 然后使用 MMAX,但是由于日期在顶部,所以它们 "survive"。此外,这似乎有点笨拙,因为如果我对 n 最大值感兴趣,或者删除构成底部值的 x 数字,我必须每列执行此操作 n 次,留下 n 个最大数量。

亲切的问候, 斯文

如果您不需要各列保持相同的顺序,以下将为您提供正确的结果:

key[kt]!(uj/) value {enlist (2#idesc x)#x}each kt:1!t

结果:

td        | NN    AA    CC    DD      
----------| -----------------------   
2001.01.01| 122   121.5               
2001.01.02| 125.5       126           
2001.01.03|       127         128.4   
2001.01.04|             128.8 128.3   
2001.01.05|       129.2 135           
2001.01.06|       130   130           

如果这对你很重要,你可以在之后用 "xcols" 修复顺序,或者这样做(这会稍微长一点,但保留永远不在前 n 列中的列)

q)key[kt]!(uj/) value {enlist (key[x]!count[x]#0n),(2#idesc x)#x}each kt:1!t

td        | AA    BB CC    DD    NN                                         
----------| --------------------------                                      
2001.01.01| 121.5                122                                        
2001.01.02|          126         125.5                                      
2001.01.03| 127            128.4                                            
2001.01.04|          128.8 128.3                                            
2001.01.05| 129.2    135                                                    
2001.01.06| 130      130       

下面是一段丑陋的代码,应该适用于您的示例:

{x,'flip y!flip{?[x>idesc y;y;0N]}[z]each flip x y}[t;`AA`BB`CC`DD`NN;2]
td         AA    BB CC    DD    NN
-------------------------------------
2001.01.01 121.5                122
2001.01.02          126         125.5
2001.01.03 127            128.4
2001.01.04          128.8 128.3
2001.01.05 129.2    135
2001.01.06 130      130

该函数允许您指定应包含哪些列以及每行中的值。

这是另一个选项,可能更简洁:

q)0!{key[x]#(2#idesc x)#x}'[1!t]
td         AA    BB CC    DD    NN
-------------------------------------
2001.01.01 121.5                122
2001.01.02          126         125.5
2001.01.03 127            128.4
2001.01.04          128.8 128.3
2001.01.05 129.2    135
2001.01.06 130      130

这是假设第一列是您不想考虑最大值的唯一一列。它在使用 idesc 方面与其他两个答案相似。这里要注意的一个部分是 key[x]# ,它实质上是将空条目添加到字典中以确保所有键都存在。例如:

q)`a`b`c#`a`c!1 2
a| 1
b|
c| 2

注意 b 在生成的字典中而不在原始字典中的方式。这用于确保为每一行生成的字典与其他行一致,从而产生 table(毕竟,这只是一个符合条件的字典列表)。