【问题标题】:np.where index is greater than a certain valuenp.where 索引大于某个值
【发布时间】:2018-12-08 05:13:57
【问题描述】:

我认为这将是相当简单的,但显然我在这里遗漏了一些东西。

我希望能够利用np.wheredf.groupby('Name').apply()df 中创建一个新列(称为'New'),其中列的值是1,如果相应的索引组(对应于原始df 的索引)大于或等于(>=)特定值,否则0

对于背景,我将df'Name' 列分组,并且我有一个dict(),其中包含用于groupby() 中每个名称的相应值。我希望这很清楚,如有必要,我可以提供进一步的澄清。

这是我目前所拥有的,给定示例df

df = pd.DataFrame([['William', 1, 0, 0, 0, 1],['James', 0, 1, 1, 1, 1],['James', 1, 0, 0, 0, 0],
                ['James', 1, 0, 1, 1, 0],['William', 0, 1, 1, 0, 1],['William', 0, 0, 0, 0, 0],
                ['William', 1, 0, 1, 1, 0],['James', 0, 1, 1, 0, 1],['James', 0, 0, 0, 0, 0]],
                columns=['Name','x1','x2','x3','x4','Interest'])

       Name  x1  x2  x3  x4  Interest
0  William   1   0   0   0         1
1    James   0   1   1   1         1
2    James   1   0   0   0         0
3    James   1   0   1   1         0
4  William   0   1   1   0         1
5  William   0   0   0   0         0
6  William   1   0   1   1         0
7    James   0   1   1   0         1
8    James   0   0   0   0         0

然后我在df 中找到'Interest' 列具有1 的每个组的最后一行,使用:

mydict = df[df['Interest']==1].groupby('Name').apply(lambda x: x.index[-1]).to_dict()

{'James': 7, 'William': 4}

注意:这是一个简化的示例。对于我的实际应用程序,我将第三行的索引拉到最后一行(即.apply(lambda x: x.index[-3]).to_dict()),但是下一部分是我问题的根源所在。

现在,我想创建一个新列'Name',如果行索引为>=,则该列的值为1,该组的值为mydict,否则为0。我尝试了一些方法:

for key, val in mydict.items():
    df['New'] = np.where((df['Name']==key) & (df.index>=val), 1, 0)

这显然会覆盖为'James' 所做的任何事情,并为'William' 返回正确的列。我怎样才能有效地做到这一点?

为了彻底,这是我的预期输出:

      Name  x1  x2  x3  x4  Interest  New
0  William   1   0   0   0         1    0
1    James   0   1   1   1         1    0
2    James   1   0   0   0         0    0
3    James   1   0   1   1         0    0
4  William   0   1   1   0         1    1
5  William   0   0   0   0         0    1
6  William   1   0   1   1         0    1
7    James   0   1   1   0         1    1
8    James   0   0   0   0         0    1

【问题讨论】:

    标签: python pandas numpy pandas-groupby


    【解决方案1】:

    对所有掩码使用列表推导,然后将 reduce 它们合二为一,最后将其转换为整数 - Trues 是 1s:

    m = [((df['Name']==key) & (df.index>=val)) for key, val in mydict.items()]
    print (m)
    [0    False
    1    False
    2    False
    3    False
    4    False
    5    False
    6    False
    7     True
    8     True
    Name: Name, dtype: bool, 0    False
    1    False
    2    False
    3    False
    4     True
    5     True
    6     True
    7    False
    8    False
    Name: Name, dtype: bool]
    
    df['New'] = np.logical_or.reduce(m).astype(int)
    print (df)
          Name  x1  x2  x3  x4  Interest  New
    0  William   1   0   0   0         1    0
    1    James   0   1   1   1         1    0
    2    James   1   0   0   0         0    0
    3    James   1   0   1   1         0    0
    4  William   0   1   1   0         1    1
    5  William   0   0   0   0         0    1
    6  William   1   0   1   1         0    1
    7    James   0   1   1   0         1    1
    8    James   0   0   0   0         0    1
    

    编辑:

    这个问题的另一种解决方案:

    df = pd.concat([df] * 2, ignore_index=True)
    

    根据条件获取第一个 True 值的索引 - 从后面计算第三个值

    idx = df[df['Interest']==1].groupby('Name').cumcount(ascending=False).eq(2).idxmax()
    

    将 idx 到 end 的值设置为 1:

    df['New'] = 0
    df.loc[idx:, 'New'] = 1
    print (df)
           Name  x1  x2  x3  x4  Interest  New
    0   William   1   0   0   0         1    0
    1     James   0   1   1   1         1    0
    2     James   1   0   0   0         0    0
    3     James   1   0   1   1         0    0
    4   William   0   1   1   0         1    1
    5   William   0   0   0   0         0    1
    6   William   1   0   1   1         0    1
    7     James   0   1   1   0         1    1
    8     James   0   0   0   0         0    1
    9   William   1   0   0   0         1    1
    10    James   0   1   1   1         1    1
    11    James   1   0   0   0         0    1
    12    James   1   0   1   1         0    1
    13  William   0   1   1   0         1    1
    14  William   0   0   0   0         0    1
    15  William   1   0   1   1         0    1
    16    James   0   1   1   0         1    1
    17    James   0   0   0   0         0    1
    

    详情

    print (df[df['Interest']==1].groupby('Name').cumcount(ascending=False))
    0     3
    1     3
    4     2
    7     2
    9     1
    10    1
    13    0
    16    0
    dtype: int64
    

    【讨论】:

    • 这个解决方案就像我需要的那样工作,但是来自@piRSquared 的解决方案避免了对列表理解的需要。非常感谢您的回答,谢谢!
    • @rahlf23 - 我找到了更好的解决方案,请检查编辑后的答案。只需要第一个 True 值的索引。
    【解决方案2】:

    使用map

    df.assign(New=(df.index >= df.Name.map(mydict)).astype(int))
    
          Name  x1  x2  x3  x4  Interest  New
    0  William   1   0   0   0         1    0
    1    James   0   1   1   1         1    0
    2    James   1   0   0   0         0    0
    3    James   1   0   1   1         0    0
    4  William   0   1   1   0         1    1
    5  William   0   0   0   0         0    1
    6  William   1   0   1   1         0    1
    7    James   0   1   1   0         1    1
    8    James   0   0   0   0         0    1
    

    【讨论】:

      猜你喜欢
      • 2020-04-29
      • 2013-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多