データフレーム列内の連続した値の累積和-任意の範囲でcumsum

How to calculate running total and reset when value change with Python? – StackOverflow

Pandasのやり方も別にもうちょっと分り易いやり方があった気がしたんだけど。

import pandas as pd

strings = """
index    Id        Date  Promo  Running_Total
0   19  2015-07-09      0              0
1   18  2015-07-10      0              0
2   17  2015-07-11      0              0
3   16  2015-07-13      1              1
4   15  2015-07-14      1              2
5   14  2015-07-15      1              3
6   13  2015-07-16      1              4
7   12  2015-07-17      1              5
8   11  2015-07-18      0              0
9   10  2015-07-20      0              0
10   9  2015-07-21      0              0
11   8  2015-07-22      0              0
12   7  2015-07-23      0              0
13   6  2015-07-24      0              0
14   5  2015-07-25      0              0
15   4  2015-07-27      1              1
16   3  2015-07-28      1              2
17   2  2015-07-29      1              3
18   1  2015-07-30      1              4
19   0  2015-07-31      1              5
""".splitlines()
s = [line.split()[1:-1] for line in strings if line]
df = pd.DataFrame(s[1:], columns=s[0])
df['Promo'] = df['Promo'].astype(int)
df['Running_Total'] = df['Promo'].groupby(df['Promo'].diff().ne(0).cumsum()).cumsum()
df
    Id  Date    Promo   Running_Total
0   19  2015-07-09  0   0
1   18  2015-07-10  0   0
2   17  2015-07-11  0   0
3   16  2015-07-13  1   1
4   15  2015-07-14  1   2
5   14  2015-07-15  1   3
6   13  2015-07-16  1   4
7   12  2015-07-17  1   5
8   11  2015-07-18  0   0
9   10  2015-07-20  0   0
10  9   2015-07-21  0   0
11  8   2015-07-22  0   0
12  7   2015-07-23  0   0
13  6   2015-07-24  0   0
14  5   2015-07-25  0   0
15  4   2015-07-27  1   1
16  3   2015-07-28  1   2
17  2   2015-07-29  1   3
18  1   2015-07-30  1   4
19  0   2015-07-31  1   5

 
 

時間効率マックスパフォーマンス……かは分からないけど、
かなり効率が良いと思うnumpy solutionとしては、
もうどれだけ使い回すのかっていう「任意の範囲の累積和」を取る方法。

関連:
任意の範囲ごとに累積和

任意の条件でクロス集計を行う

インパルスから鋸歯の様なリストの値の操作

 
 

import numpy as np
import pandas as pd

def specified_cumsum(a, ind):
  arr = a.copy()
  arr[ind[1:]] -= np.add.reduceat(arr, ind)[:-1]
  idx = np.concatenate((ind[1:], [ind.max()+1])) - 1
  return arr.cumsum(0)


strings = """
index    Id        Date  Promo  Running_Total
0   19  2015-07-09      0              0
1   18  2015-07-10      0              0
2   17  2015-07-11      0              0
3   16  2015-07-13      1              1
4   15  2015-07-14      1              2
5   14  2015-07-15      1              3
6   13  2015-07-16      1              4
7   12  2015-07-17      1              5
8   11  2015-07-18      0              0
9   10  2015-07-20      0              0
10   9  2015-07-21      0              0
11   8  2015-07-22      0              0
12   7  2015-07-23      0              0
13   6  2015-07-24      0              0
14   5  2015-07-25      0              0
15   4  2015-07-27      1              1
16   3  2015-07-28      1              2
17   2  2015-07-29      1              3
18   1  2015-07-30      1              4
19   0  2015-07-31      1              5
""".splitlines()
s = [line.split()[1:-1] for line in strings if line]
df = pd.DataFrame(s[1:], columns=s[0])
df['Promo'] = df['Promo'].astype(int)
arr = df['Promo'].values
ind =np.where(np.diff(arr))[0] + 1
df['Running_Total'] = specified_cumsum(arr, ind)
df
    Id  Date    Promo   Running_Total
0   19  2015-07-09  0   0
1   18  2015-07-10  0   0
2   17  2015-07-11  0   0
3   16  2015-07-13  1   1
4   15  2015-07-14  1   2
5   14  2015-07-15  1   3
6   13  2015-07-16  1   4
7   12  2015-07-17  1   5
8   11  2015-07-18  0   0
9   10  2015-07-20  0   0
10  9   2015-07-21  0   0
11  8   2015-07-22  0   0
12  7   2015-07-23  0   0
13  6   2015-07-24  0   0
14  5   2015-07-25  0   0
15  4   2015-07-27  1   1
16  3   2015-07-28  1   2
17  2   2015-07-29  1   3
18  1   2015-07-30  1   4
19  0   2015-07-31  1   5

 
 
・パフォーマンステスト

%timeit df['Running_Total'] = df['Promo'].groupby(df['Promo'].diff().ne(0).cumsum()).cumsum()
%timeit df['Running_Total'] = specified_cumsum(arr, ind)
%timeit arr = df['Promo'].values
%timeit ind =np.where(np.diff(arr))[0] + 1
1000 loops, best of 3: 1.62 ms per loop
10000 loops, best of 3: 83.3 µs per loop
100000 loops, best of 3: 3.04 µs per loop
100000 loops, best of 3: 5.62 µs per loop

諸々の時間を足しても1.6 ms vs 91 us

広告
カテゴリー: 未分類 パーマリンク

データフレーム列内の連続した値の累積和-任意の範囲でcumsum への6件のフィードバック

  1. ピンバック: 任意の列を条件にしてデータフレームをグルーピングし各グループ毎にソート – Pandas | 粉末@それは風のように (日記)

  2. ピンバック: 同符号の累積値と連続値をカウント | 粉末@それは風のように (日記)

  3. ピンバック: シーケンシャルな値の累積和(cumsum) | 粉末@それは風のように (日記)

  4. 匿名 より:

    プライバシーと Cookies:このサイトは Cookies を使用しています。このサイトの使用を続けると、Cookie の使用に同意したとみなされます。
    Cookie の管理方法を含め、詳細についてはこちらをご覧ください: Cookie ポリシー

    とあるがコレはウイルスなのか

  5. 匿名 より:

    プライバシーと Cookies:このサイトは Cookies を使用しています。このサイトの使用を続けると、Cookie の使用に同意したとみなされます。
    Cookie の管理方法を含め、詳細についてはこちらをご覧ください: Cookie ポリシー

    とあるがこれはウイルスなのか?

    • Funmatu より:

      ウイルスでは無いです.詳しくは以下をご参照下さい.

      Cookie とは? – Microsoft
      https://www.microsoft.com/ja-jp/safety/terms/cookie.aspx

      クッキー(Cookie)ポリシー – NTTDATA
      https://www.nttdata.com/jp/ja/info/cookie_policy/

      このブログはフリーブログで,広告/アクセス解析等は僕の管理する所ではないので,詳しくは分からないですが,おそらくは広告/アクセス解析等にCookieを使用しているんだと思います.その際,最近ではプライバシー保護の観点から,「Cookieの使用」について明示的に確認(オプトイン)が行われる様になりました.

      EUの「一般データ保護規則(GDPR)」によりこれが義務付けられたので,グローバルにサービスを展開しているところは(例えば,Google Adsense/Google Analytics),絶対にこれが出る様になった様ですね.

      まあ,こんなものは「確認のための確認」に過ぎ無くて,はっきり言って無駄だと個人的には思いますけどね.

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください