以其他列的组的最大值为条件计算新列

时间:2017-11-01 19:24:24

标签: python pandas numpy

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

每个“实例”都有不同数量的ID。每个ID都有两个因子,Factor1和Factor2。我想要两个新专栏。第一个很简单,100除以实例中的ID数(Count)。这是'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。第二部分是因为如果因子1的最大值发生了两次,那么检查因子2并丢弃它们中的较小者。

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

对于实例1中的所有,dropONE列应为16.66667,除了ID为7的0,其中因子1为99.对于实例2中的所有应该为14.285714,除了ID为6的0,其中因子1为70(F1的最大值) )和因子2是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无法正常工作并出错,我知道这是因为我正在比较不同大小的对象,但不确定如何正确执行此操作。

顺便说一下,群组中的最后一次打印显示了这一点:

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

1 个答案:

答案 0 :(得分: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行)。