如何简化 data.table 逻辑并使其在 pandas 中可行?

How to simplify data.table logic and make it doable in pandas?

我有一个包含多列数值的数据框。我想要新的列来比较其他列的值并将其列名指定为标签。我已经在 r 中理解了它的逻辑,但想知道我应该如何在 python 中轻松地做到这一点。当我们尝试在需要比较多列值的地方添加新列并分配具有最大值的列名时,任何人都可以指出如何在 python 中完成此操作吗?有什么想法吗?

可重现的例子

这是 R 中 100% 可重现的示例:

library(data.table)

df <- data.frame(a = sample(seq(1:10), size=10), b = sample(LETTERS[1:10], size=10), cnt=sample(seq(1:100), size=5),
                 RECENT_MOV= sample(seq(1:1000), size = 10),
                 RETIRED= sample(seq(1:200), size = 10),
                 SERV_EMPL= sample(seq(1:500), size = 10),
                 SUB_BUS=sample(seq(1:2000), size = 10),
                 WORK_HOME=sample(seq(1:1200), size = 10)
                 )

dt <- as.data.table(df)
write.csv(dt, "sample.csv")
label = c("RECENT_MOV", "RETIRED", "SERV_EMPL", "SUB_BUS","WORK_HOME")
df$category <- NA_character_
df[, row_ind:= 1:nrow(df)]
df[cnt > 2, category := names(which.max(.SD[, label, with = FALSE])), by = row_ind]

当前输出为:

> dput(dt)
structure(list(a = c(5L, 10L, 1L, 6L, 7L, 3L, 2L, 8L, 4L, 9L), 
    b = c("E", "A", "D", "H", "J", "F", "G", "I", "C", "B"), 
    cnt = c(13L, 88L, 45L, 92L, 70L, 13L, 88L, 45L, 92L, 70L), 
    RECENT_MOV = c(70L, 195L, 620L, 572L, 354L, 648L, 798L, 657L, 
    233L, 672L), RETIRED = c(189L, 195L, 191L, 88L, 148L, 186L, 
    39L, 78L, 158L, 55L), SERV_EMPL = c(65L, 151L, 415L, 383L, 
    255L, 207L, 210L, 470L, 181L, 188L), SUB_BUS = c(894L, 829L, 
    1798L, 502L, 897L, 1461L, 744L, 1991L, 260L, 1697L), WORK_HOME = c(553L, 
    739L, 454L, 137L, 435L, 1042L, 316L, 697L, 517L, 1158L), 
    category = c("SUB_BUS", "SUB_BUS", "SUB_BUS", "RECENT_MOV", 
    "SUB_BUS", "SUB_BUS", "RECENT_MOV", "SUB_BUS", "WORK_HOME", 
    "SUB_BUS"), row_ind = 1:10), row.names = c(NA, -10L), class = c("data.table", 
"data.frame"), .internal.selfref = <pointer: 0x0000015a64b61ef0>)

我目前的 python 尝试

import pandas as pd

df=pd.read_csv("sample.csv", index_col=None, header=0)

label = ["RECENT_MOV", "RETIRED", "SERV_EMPL", "SUB_BUS","WORK_HOME"]
df['category'] = pd.NA
df['row_ind'] = range(1,len(df))

然而,我无法以 pythonic 方式制作此行:

df[cnt > 2, category := names(which.max(.SD[, label, with = FALSE])), by = row_ind]

基本上,这行说创建名为类别的新列变量,其中比较标签中具有最大值的列,其列名将被分配为类别列中的值。在 python 中我应该如何轻松做到这一点?

逻辑翻译:

df[cnt > 2, category := names(which.max(.SD[, label, with = FALSE])), by = row_ind]

这一行告诉我们首先按 cnt > 2 所在的 cnt 列进行过滤,然后比较 df[["RECENT_MOV", "RETIRED", "SERV_EMPL", "SUB_BUS","WORK_HOME"]] 的列值并按行选择具有最高值的列并分配该列的名称列作为 df['category']=col_name_with_highest_value_in_each_row.

的值

理想产出

这是我想要在 python 中产生的理想输出:

    a b cnt RECENT_MOV RETIRED SERV_EMPL SUB_BUS WORK_HOME   category row_ind
1   5 E  13         70     189        65     894       553    SUB_BUS       1
2  10 A  88        195     195       151     829       739    SUB_BUS       2
3   1 D  45        620     191       415    1798       454    SUB_BUS       3
4   6 H  92        572      88       383     502       137 RECENT_MOV       4
5   7 J  70        354     148       255     897       435    SUB_BUS       5
6   3 F  13        648     186       207    1461      1042    SUB_BUS       6
7   2 G  88        798      39       210     744       316 RECENT_MOV       7
8   8 I  45        657      78       470    1991       697    SUB_BUS       8
9   4 C  92        233     158       181     260       517  WORK_HOME       9
10  9 B  70        672      55       188    1697      1158    SUB_BUS      10

pandas 这其实很简单。列出要搜索的列,然后使用 idxmaxaxis=1:

# Filter out rows where `cnt` is less than or equal to 2
df = df[df['cnt'] > 2]

# Determine category for each row
search_cols = ['RECENT_MOV', 'RETIRED', 'SERV_EMPL', 'SUB_BUS', 'WORK_HOME']
df['category'] = df[search_cols].idxmax(axis=1)

# Assign row indexes
df['row_ind'] = df.index

输出:

>>> df
     a  b  cnt  RECENT_MOV  RETIRED  SERV_EMPL  SUB_BUS  WORK_HOME    category  row_ind
1    1  C   76         452       62         55      115        247  RECENT_MOV        1
2    7  E   14          50      165        337     1165        810     SUB_BUS        2
3    2  A   46         523      167        423      784        707     SUB_BUS        3
4    3  H    3          38      144        473      745        437     SUB_BUS        4
5    5  I   59         743      127        261      351        190  RECENT_MOV        5
6    8  J   76         143       49        470     1612        935     SUB_BUS        6
7    4  D   14         818      101        418     1919        314     SUB_BUS        7
8    6  F   46         714        9        446     1432        938     SUB_BUS        8
9   10  B    3         585      160         14      107        489  RECENT_MOV        9
10   9  G   59         814       73        449      937        287     SUB_BUS       10