Select 行(按可变条件)(即每行中的所需值取决于其他行中的值)

Select rows by variable condition (ie. desired value in each row depends on values in other rows)

我有以下 DataFrame:

    model_year  cylinders   mpg
0   70  4   25.285714
1   70  6   20.500000
2   70  8   14.111111
3   71  4   27.461538
4   71  6   18.000000
5   71  8   13.428571
6   72  3   19.000000
7   72  4   23.428571
8   72  8   13.615385
9   73  3   18.000000
10  73  4   22.727273
11  73  6   19.000000
12  73  8   13.200000
13  74  4   27.800000
14  74  6   17.857143
15  74  8   14.200000
16  75  4   25.250000
17  75  6   17.583333
18  75  8   15.666667
19  76  4   26.766667
20  76  6   20.000000
21  76  8   14.666667
22  77  3   21.500000
23  77  4   29.107143
24  77  6   19.500000
25  77  8   16.000000
26  78  4   29.576471
27  78  5   20.300000
28  78  6   19.066667
29  78  8   19.050000
30  79  4   31.525000
31  79  5   25.400000
32  79  6   22.950000
33  79  8   18.630000
34  80  3   23.700000
35  80  4   34.612000
36  80  5   36.400000
37  80  6   25.900000
38  81  4   32.814286
39  81  6   23.428571
40  81  8   26.600000
41  82  4   32.071429
42  82  6   28.333333

我想要 select 行满足以下条件: 对于每个 model_year select 行,该行具有当年的最小柱面值。

因此,例如,对于模型年份 = 70、71、72 和 73,我想得到:

    model_year  cylinders   mpg
0   70  4   25.285714
3   71  4   27.461538
6   72  3   19.000000
9   73  3   18.000000

我最先进的尝试包括:

  1. 我将 model_yearcylinders 列转换为 DataFrame 的 MultiIndex
  2. 使用(除其他外)groupby 方法我获得了我想要 select.
  3. 的行的 MultiIndex 对象

但是,我找不到使用 MultiIndex 对象 select 行的方法。

作为参考,我获得的 MultiIndex 是:

MultiIndex([(70, 4),
            (71, 4),
            (72, 3),
            (73, 3),
            (74, 4),
            (75, 4),
            (76, 4),
            (77, 3),
            (78, 4),
            (79, 4),
            (80, 3),
            (81, 4),
            (82, 4)],
           names=['model_year', 'cylinders'])

您可以使用 groupby + idxmin 创建遮罩并用它过滤 df:

out = df.loc[df.groupby('model_year')['cylinders'].idxmin()]

输出:

    model_year  cylinders        mpg
0           70          4  25.285714
3           71          4  27.461538
6           72          3  19.000000
9           73          3  18.000000
13          74          4  27.800000
16          75          4  25.250000
19          76          4  26.766667
22          77          3  21.500000
26          78          4  29.576471
30          79          4  31.525000
34          80          3  23.700000
38          81          4  32.814286
41          82          4  32.071429

我认为更简单的解决方案实际上是使用 groupby + transform:

selected = df[df['cylinders'] == df.groupby('model_year')['cylinders'].transform('min')]

输出:

>>> selected
    model_year  cylinders        mpg
0           70          4  25.285714
3           71          4  27.461538
6           72          3  19.000000
9           73          3  18.000000
13          74          4  27.800000
16          75          4  25.250000
19          76          4  26.766667
22          77          3  21.500000
26          78          4  29.576471
30          79          4  31.525000
34          80          3  23.700000
38          81          4  32.814286
41          82          4  32.071429

(请注意,如果一个组有多个最小值(例如,对于 model_year 70,有两个 4 缸行),它们将包含在输出中。)

你可以试试

out = df.sort_values('cylinders',ascending=False).drop_duplicates('model_year')