跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 又来求教 pandas 大拿了
未分類
27 3 月 2021

又来求教 pandas 大拿了

又来求教 pandas 大拿了

資深大佬 : yaleyu 11

如下一个表,想每当 C 列为 False 时候,D 列为 0,为 True 时候,D 列为 B 列的上一次 C 列为 False 到当前列的加总

df = pd.DataFrame([['S1', 1, False], ['S1', 1, True],     ['S2', 2, False], ['S2', 2, True], ['S2', 22, False], ['S2', 22, True],     ['S3', 222, False], ['S3', 222, True]],     columns=list('ABC')) print(df)     A    B      C 0  S1    1  False 1  S1    1   True 2  S2    2  False 3  S2    2   True 4  S2   22  False 5  S2   22   True 6  S3  222  False 7  S3  222   True 

用 for 循环切片每次的 False 到 True 再处理可以得到想要的结果,但是总觉得效率不高。

用了下面的方法,得出来的结果不对,5 行 D 列应该是 44(22+22)而不是 48(2+2+22+22)

df['D'] = np.where(df.C, df.groupby('A')['B'].cumsum(), 0) print(df)     A    B      C    D 0  S1    1  False    0 1  S1    1   True    2 2  S2    2  False    0 3  S2    2   True    4 4  S2   22  False    0 5  S2   22   True   48 6  S3  222  False    0 7  S3  222   True  444 

大佬有話說 (12)

  • 資深大佬 : apake

    为什么要 groubby(‘A’), 问题中没提到与 A 列有关

  • 資深大佬 : shyrock

    df[‘D’] = np.where(df.C, df.groupby(‘B’)[‘B’].cumsum(), 0)
    print(df)

  • 資深大佬 : cassidyhere

    如果 A/B 没规律的话,可以用自定义 window rolling
    from pandas.api.indexers import BaseIndexer
    window_size = df.C.groupby((df.C != df.C.shift(1)).cumsum()).agg(‘sum’).max() # 最大连续次数
    class CustomIndexer(BaseIndexer):
    def get_window_bounds(self, num_values, min_periods, center, closed):
    start = np.empty(num_values, dtype=np.int64)
    end = np.empty(num_values, dtype=np.int64)
    for i in range(num_values):
    end[i] = i + 1
    j = i
    while j > 0 and self.use_expanding[j]:
    j -= 1
    start[i] = j
    return start, end
    indexer = CustomIndexer(window_size=window_size, use_expanding=df.C)
    res = df.B.rolling(indexer, min_periods=2).sum().fillna(0)

  • 主 資深大佬 : yaleyu

    @apake 问题没描述得太清楚,应该是对每个 A 列的数据,当 C 列从 false 变化为 true 时候,加总 false 到 true 对应的行的 B 列

  • 主 資深大佬 : yaleyu

    @shyrock 这个不行,B 列的值是不一样的,不能 groupby(‘B’),这里为了简化写成了 1, 1, 2, 2, 22, 22 等

  • 資深大佬 : necomancer

    df.D = df.groupby(df.C.eq(False).cumsum()).cumsum().D
    df.D[df.D <0]=0

  • 資深大佬 : necomancer

    df = pd.DataFrame([[‘S1’, 1, False], [‘S1’, 1, True],
    [‘S2’, 2, False], [‘S2’, 2, True], [‘S2’, 22, False], [‘S2’, 22, True],
    [‘S3’, 222, False], [‘S3’, 222, True]],
    columns=list(‘ABC’))

    df[‘D’] = np.diff(np.where(df.C, df.groupby(‘A’)[‘B’].cumsum(), 0), axis=0, prepend=0)

    df.D = df.groupby(df.C.eq(False).cumsum()).cumsum().D
    df.D[df.D <0]=0
    df
    A B C D
    0 S1 1 False 0
    1 S1 1 True 2
    2 S2 2 False 0
    3 S2 2 True 2
    4 S2 22 False 0
    5 S2 22 True 44
    6 S3 222 False 0
    7 S3 222 True 396

  • 資深大佬 : necomancer

    ……我是智障

    df[‘D’] = np.where(df.C, df.groupby(df.C.eq(False).cumsum()).B.cumsum(), 0)

    df

    A B C D
    0 S1 1 False 0
    1 S1 1 True 2
    2 S2 2 False 0
    3 S2 2 True 4
    4 S2 22 False 0
    5 S2 22 True 44
    6 S3 222 False 0
    7 S3 222 True 444

  • 資深大佬 : milkpuff

    我选择 for 循环。。
    而且不要频繁对 pandas 切片和赋值,转成 numpy 操作速度提升一个数量级,最后结果再转到 pandas

  • 主 資深大佬 : yaleyu

    @necomancer 这个牛逼,完全实现了需求,谢谢谢谢。

  • 主 資深大佬 : yaleyu

    @cassidyhere 这个好深奥,不过完全实现了需求,万分感谢。

  • 主 資深大佬 : yaleyu

    @necomancer @cassidyhere 哦,不对,把原始数据改一下更接近真实数据,好像就有点问题了,原贴编辑不了了,回复排版会乱,再开一贴求教大家吧
    https://www.v2ex.com/t/760789

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具