【问题标题】:Apply one groupby value back to all group将一个 groupby 值应用回所有组
【发布时间】:2018-09-04 01:41:25
【问题描述】:

我有一张桌子

 id    valid
 1      book
 1      unknown
 1      unknown
 2      unknown
 2      book
 2      unknown
 3      unknown
 3      unknown
 3      book
 4      unknown
 4      picture

我挑选了一些id 并测试该项目是否有效。如果它已经过验证,valid 列将是“book”。但是某些项目的valid 列仍然“未知”。我希望他们成为“书”。由于它们并非都出现在每个组的第一位,因此我不能使用groupby.first() 之类的东西。而且由于unknown的位置不固定,所以我不能使用apply(pd.DataFrame.last_valid_index)之类的东西。

而且由于我的原始表格很大,我不喜欢循环。

所需的列应如下所示:

 id    valid
 1      book
 1      book
 1      book
 2      book
 2      book
 2      book
 3      book
 3      book
 3      book
 4      unknown
 4      picture

【问题讨论】:

  • 抱歉,为了更通用,我已将 1 和 0 更改为字符串。
  • 我更新了 id '4'。

标签: python pandas group-by apply


【解决方案1】:

使用transform 并根据您的需要在lambda 函数中返回一个标量或系列:

df['valid'] = df.valid.groupby(df.id).transform(lambda g: 'book' if g.eq('book').any() else g)

df
#    id    valid
#0    1     book
#1    1     book
#2    1     book
#3    2     book
#4    2     book
#5    2     book
#6    3     book
#7    3     book
#8    3     book
#9    4  unknown
#10   4  picture

【讨论】:

  • 这仅适用于 0 或 1 之类的数字吗?我的表包含一些字符串。
  • 你能展示一些真实的数据吗?我的猜测是你需要做类似transform(lambda g: ...) 但在lambda 函数中返回一个标量。
  • 我会修改问题,请稍后查看。
  • 你的答案很好,但是如果有两个以上的字符串呢?我可以改变 else 部分并让它们保持原来的样子吗?查看我的更新。抱歉一直问...
  • 干杯我应该看看那个功能。我已经弄清楚了。感谢您的耐心等待。
【解决方案2】:

您可以将 0 替换为 np.nan ,然后使用 ffillbfill

df.valid=df.valid.replace(0,np.nan)
df.valid=df.groupby('id').valid.apply(lambda x : x.ffill().bfill()).fillna(0)
df
Out[1078]: 
    id  valid
0    1    1.0
1    1    1.0
2    1    1.0
3    2    1.0
4    2    1.0
5    2    1.0
6    3    1.0
7    3    1.0
8    3    1.0
9    4    0.0
10   4    0.0

更新......操作,因为改变问题

s=df.loc[df.valid=='book','id']
pd.concat([df[df.id.isin(s)].replace('unknown','book'),df[~df.id.isin(s)]])
Out[1126]: 
    id    valid
0    1     book
1    1     book
2    1     book
3    2     book
4    2     book
5    2     book
6    3     book
7    3     book
8    3     book
9    4  unknown
10   4  picture

【讨论】:

  • 看起来 OP 改变了他们的问题 >:(
  • @cᴏʟᴅsᴘᴇᴇᴅ 这没有意义......完全改变他的问题......
  • 现在看起来很棒,伙计:)
【解决方案3】:

一种方法是使用Categorical Data 重新排序“有效”列。

然后在删除重复项后生成一个映射系列并将其应用于您的原始数据框。

df['valid'] = df['valid'].astype('category')

df['valid'] = df['valid'].cat.set_categories(\
                 list(set(df['valid'])-{'Unknown'})+['Unknown'], ordered=True)

s = df.sort_values('valid').drop_duplicates('id').set_index('id')['valid']

df['valid'] = df['id'].map(s)

作为副作用,您可能会看到其他好处,例如检查“有效”列中的适当项目、节省内存、提高性能。

结果

    id    valid
0    1     book
1    1     book
2    1     book
3    2     book
4    2     book
5    2     book
6    3     book
7    3     book
8    3     book
9    4  unknown
10   4  unknown

【讨论】:

    【解决方案4】:

    这是一个使用groupby + transform + any 的非lambda 解决方案:

    m = df.set_index('id').valid.eq('book').groupby(level=0).transform('any')
    df['valid'] = np.where(m, 'book', df.valid) 
    
    df
        id    valid
    0    1     book
    1    1     book
    2    1     book
    3    2     book
    4    2     book
    5    2     book
    6    3     book
    7    3     book
    8    3     book
    9    4  unknown
    10   4  picture
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-02
      • 2017-12-06
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多