【问题标题】:Computing new column conditional on max of group of other column以其他列组的最大值为条件计算新列
【发布时间】:2017-11-02 11:30:05
【问题描述】:

我有一个多索引数据框,我在这里重新创建了一小部分。

每个“实例”都有不同数量的 ID。每个 ID 有两个因子,Factor1 和 Factor2。我想要两个新专栏。第一个很简单,它是 100 除以实例中的 ID 数(计数)。这是“evenSpread”列。

                         Factor1  Factor2  evenSpread    dropONE
Place Instance Count ID                                         
Home  1        7     1        20       18   14.285714  16.666667
                     2        22       19   14.285714  16.666667
                     4        36       40   14.285714  16.666667
                     5        32       30   14.285714  16.666667
                     6         1        7   14.285714  16.666667
                     7        99       90   14.285714  16.666667
                     8         5        9   14.285714  16.666667
      2        8     1        10        8   12.500000  14.285714
                     3        20       19   12.500000  14.285714
                     4        30       35   12.500000  14.285714
                     5        40       55   12.500000  14.285714
                     6        70       50   12.500000  14.285714
                     7        50       60   12.500000  14.285714
                     8        60       52   12.500000  14.285714
                     9        70       88   12.500000  14.285714

第二个('dropONE')更难,我确信我缺少一些概念来正确完成这项工作。我想删除 Factor1 中具有最高值的 ID 之一,如果包含,则使用 100/(count-1) 填充列,如果不包含,则填充 0。第二部分是如果 Factor1 的最大值发生两次,然后检查 Factor2 并删除它们中的较小值。

我不知道这是否可以在一项作业中完成而无需创建任何其他列,但我很难过。

除 ID 7 的 0 之外的所有实例 1 中的 dropONE 列应为 16.66667,其中 Factor1 为 99。除 ID 6 的 0 之外,实例 2 中的所有实例的 dropONE 列应为 14.285714,其中因子 1 为 70(F1 的最大值) 和 Factor2 为 50(50 低于 88)。这是我想看到的:

                         Factor1  Factor2  evenSpread    dropONE
Place Instance Count ID                                         
Home  1        7     1        20       18   14.285714  16.666667
                     2        22       19   14.285714  16.666667
                     4        36       40   14.285714  16.666667
                     5        32       30   14.285714  16.666667
                     6         1        7   14.285714  16.666667
                     7        99       90   14.285714  0
                     8         5        9   14.285714  16.666667
      2        8     1        10        8   12.500000  14.285714
                     3        20       19   12.500000  14.285714
                     4        30       35   12.500000  14.285714
                     5        40       55   12.500000  14.285714
                     6        70       50   12.500000  0
                     7        50       60   12.500000  14.285714
                     8        60       52   12.500000  14.285714
                     9        70       88   12.500000  14.285714

我什至无法让第一个条件起作用,更不用说第二个了。到目前为止,这是我的代码。

import numpy as np
import pandas as pd

my_data = {'Place': ['Home', 'Home', 'Home', 'Home', 'Home', 'Home', 'Home',
                     'Home', 'Home', 'Home', 'Home', 'Home', 'Home', 'Home', 'Home'],
           'Instance': [1, 1, 1, 1, 1, 1, 1,
                        2, 2, 2, 2, 2, 2, 2, 2],
           'Count': [7, 7, 7, 7, 7, 7, 7,
                     8, 8, 8, 8, 8, 8, 8, 8],
           'ID': [1, 2, 4, 5, 6, 7, 8,
                  1, 3, 4, 5, 6, 7, 8, 9],
           'Factor1': [20, 22, 36, 32, 1, 99, 5,
                       10, 20, 30, 40, 70, 50, 60, 70],
           'Factor2': [18, 19, 40, 30, 7, 90, 9,
                       8, 19, 35, 55, 50, 60, 52, 88],
           }

df = pd.DataFrame(my_data)
df = df[['Place', 'Instance', 'Count', 'ID', 'Factor1', 'Factor2']]
df.set_index(['Place', 'Instance', 'Count', 'ID'], inplace=True)

print(df)

df['evenSpread'] = 100 / df.index.get_level_values('Count')
df['dropONE'] = 100 / (df.index.get_level_values('Count') - 1)  # WRONG AS WRITTEN
print(df)

# df['dropONE'] = np.where(df['Factor1'] == df.groupby(level=[0, 1, 2])['Factor1'].max(), 0, 1)
print(df)

print(df.groupby(level=[0, 1, 2])['Factor1'].max())

np.where 中的 groupby 不起作用并出错,我知道这是因为我正在比较不同大小的对象,但不确定如何正确执行此操作。

顺便说一下,最后打印出的 groupby 显示:

Place  Instance  Count
Home   1         7        99
       2         8        70
Name: Factor1, dtype: int64

非常感谢各位。

编辑#1

不确定这是否有帮助,但我使用以下内容对每个组进行了排序。那么也许有一种方法可以根据每个组的顺序创建一个 True/False 标志列?同样,组将是实例中的所有内容。

print(df.sort_values(by=['Factor1', 'Factor2'], ascending=[True, False]).sort_index(
    level='Instance', sort_remaining=False))

这给出了:

                         Factor1  Factor2  evenSpread    dropONE
Place Instance Count ID                                         
Home  1        7     6         1        7   14.285714  16.666667
                     8         5        9   14.285714  16.666667
                     1        20       18   14.285714  16.666667
                     2        22       19   14.285714  16.666667
                     5        32       30   14.285714  16.666667
                     4        36       40   14.285714  16.666667
                     7        99       90   14.285714  16.666667
      2        8     1        10        8   12.500000  14.285714
                     3        20       19   12.500000  14.285714
                     4        30       35   12.500000  14.285714
                     5        40       55   12.500000  14.285714
                     7        50       60   12.500000  14.285714
                     8        60       52   12.500000  14.285714
                     6        70       88   12.500000  14.285714
                     9        70       50   12.500000  14.285714

【问题讨论】:

  • 我说第一个条件有效? 100/7 和 100/8 如果我没记错的话
  • Paula,是的,'evenSpread' 正在工作。它是'dropONE' ... 有 2 个条件 - 最大因子 1,如果有平局,则因子 2 的最小值。我已尽力使这一点尽可能清楚,如果造成混淆,请见谅。
  • 当您说“如果包含则用 100/(count-1) 填充列,如果不包含则填充 0”,“它”是什么?
  • 如果 'Factor1' 是其组的最大值,我希望 'dropONE' 为 0。如果有两个“Factor1”最大值(实例 2 中的 ID 6 和 9),我想删除具有较低“Factor2”的那个。

标签: python pandas numpy


【解决方案1】:

经过数小时的搜索和反复试验,我学到了一些东西。排序是关键。以下内容改编自This question

def replace_first_x(group):
    group.iloc[-1, -1:] = 0
    return group

df = df.groupby(level=[0, 1, 2]).apply(replace_first_x)
print(df)

还有我的输出!

                         Factor1  Factor2  evenSpread    dropONE
Place Instance Count ID                                         
Home  1        7     6         1        7   14.285714  16.666667
                     8         5        9   14.285714  16.666667
                     1        20       18   14.285714  16.666667
                     2        22       19   14.285714  16.666667
                     5        32       30   14.285714  16.666667
                     4        36       40   14.285714  16.666667
                     7        99       90   14.285714   0.000000
      2        8     1        10        8   12.500000  14.285714
                     3        20       19   12.500000  14.285714
                     4        30       35   12.500000  14.285714
                     5        40       55   12.500000  14.285714
                     7        50       60   12.500000  14.285714
                     8        60       52   12.500000  14.285714
                     9        70       88   12.500000  14.285714
                     6        70       50   12.500000   0.000000

我很好奇是否有任何内置函数或更好的方法来做到这一点。这可行,但有点慢(df 超过 500k 行)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多