シーケンシャルな値の累積和(cumsum)

よく使うのに纏めていないから,とりあえずページ内検索で関連エントリを纏めておく.

行列(2Dアレイ)内の連続する1または0のサブセットのインデックス,開始/終了インデックス,長さを得る

条件を満たす連続した値をカウント

別の配列に基づいて配列値をグルーピングして合計

データフレームの行をループして重複をチェック

同符号の累積値と連続値をカウント

任意の列を条件にしてデータフレームをグルーピングし各グループ毎にソート – Pandas

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

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

任意の範囲ごとに累積和

 
 
 

これらの関数は,結構重宝する(できる)のでちゃんと考え直さないといけない.
最初と最後に0以外の要素が来ると失敗するので不完全.
(とりあえず,前後に0を追加して結果から削除すれば使えるんだけど)

import numpy as np


# シーケンシャルな要素(0以外)をcumsum: 2D array(ただし最初と最後が0の場合のみ有効)
def seq_cumsum_2d(a):
  arr = a.copy()
  rind, cind =np.where(np.diff(arr, 1))
  cind += 1
  arr[rind[1:], cind[1:]] -= np.add.reduceat(arr, cind, 1)[rind, np.arange(len(rind))][:-1]
  return arr.cumsum(1)


# シーケンシャルな値(0以外)をcumsum: 1D array
def seq_cumsum_1d(a):
  arr = a.copy()
  ind = np.concatenate(([0], np.flatnonzero(np.diff(arr))+1))
  arr[ind[1:]] -= np.add.reduceat(arr, ind)[:-1]
  return arr.cumsum(0)


# 任意の範囲でcumsum,範囲はlensで指定
def specified_cumsum(a, lens):
  arr = a.copy()
  ind = np.cumsum([0] + lens)[:-1]
  arr[ind[1:]] -= np.add.reduceat(arr, ind)[:-1]
  return arr.cumsum(0)


a = [
    [0, 1,1,0,0,1,0, 0],
    [0, 1,1,1,0,1,1, 0],
    [0, 0,0,1,0,0,1, 0],
    [0, 1,1,1,0,1,1, 0],
    [0, 0,1,0,1,0,0, 0],
    [0, 1,1,0,1,1,0, 0]
]

arr = np.array(a)
seq_cumsum_2d(arr)
array([[0, 1, 2, 0, 0, 1, 0, 0],
       [0, 1, 2, 3, 0, 1, 2, 0],
       [0, 0, 0, 1, 0, 0, 1, 0],
       [0, 1, 2, 3, 0, 1, 2, 0],
       [0, 0, 1, 0, 1, 0, 0, 0],
       [0, 1, 2, 0, 1, 2, 0, 0]])
a = [
    [1,1,0,0,1,0],
    [1,1,1,0,1,1],
    [0,0,1,0,0,1],
    [1,1,1,0,1,1],
    [0,1,0,1,0,0],
    [1,1,0,1,1,0]
]
arr = np.array(a)
seq_cumsum_2d(arr)
array([[ 1,  2,  2,  2,  3,  2],
       [ 1,  2,  3,  3,  4,  5],
       [ 0,  0,  0, -1, -1,  0],
       [ 1,  2,  3,  2,  3,  4],
       [ 0,  0, -1,  0, -1, -1],
       [ 1,  2,  2,  3,  4,  2]])
def seq_cumsum_1d(a):
  arr = a.copy()
  ind = np.concatenate(([0], np.flatnonzero(np.diff(arr))+1))
  arr[ind[1:]] -= np.add.reduceat(arr, ind)[:-1]
  return arr.cumsum(0)


np.apply_along_axis(seq_cumsum_1d, 1, arr)
array([[1, 2, 0, 0, 1, 0],
       [1, 2, 3, 0, 1, 2],
       [0, 0, 1, 0, 0, 1],
       [1, 2, 3, 0, 1, 2],
       [0, 1, 0, 1, 0, 0],
       [1, 2, 0, 1, 2, 0]])

「np.apply_along_axis」を用いれば,row-wise, column-wise,
どういう形状であっても簡単に適用できて便利だけど.
(後,時間効率は劣るが,空間効率はこの方が良い)

a = [
    [0, 1,1,0,0,1,0, 0],
    [0, 1,1,1,0,1,1, 0],
    [0, 0,0,1,0,0,1, 0],
    [0, 1,1,1,0,1,1, 0],
    [0, 0,1,0,1,0,0, 0],
    [0, 1,1,0,1,1,0, 0]
]

arr = np.array(a)
print(seq_cumsum_2d(arr))
%timeit seq_cumsum_2d(arr)
print(np.apply_along_axis(seq_cumsum_1d, 1, arr))
%timeit np.apply_along_axis(seq_cumsum_1d, 1, arr)
[[0 1 2 0 0 1 0 0]
 [0 1 2 3 0 1 2 0]
 [0 0 0 1 0 0 1 0]
 [0 1 2 3 0 1 2 0]
 [0 0 1 0 1 0 0 0]
 [0 1 2 0 1 2 0 0]]
10000 loops, best of 3: 21.1 µs per loop

[[0 1 2 0 0 1 0 0]
 [0 1 2 3 0 1 2 0]
 [0 0 0 1 0 0 1 0]
 [0 1 2 3 0 1 2 0]
 [0 0 1 0 1 0 0 0]
 [0 1 2 0 1 2 0 0]]
10000 loops, best of 3: 139 µs per loop
広告
カテゴリー: 未分類 パーマリンク

シーケンシャルな値の累積和(cumsum) への10件のフィードバック

  1. ピンバック: pandas.DataFrame内の各列ごとに累積カウントを適用する方法 | 粉末@それは風のように (日記)

  2. ピンバック: あるリストから別のリストの特定のアイテムにアイテムを追加 | 粉末@それは風のように (日記)

  3. ピンバック: indexのリストに基づいて累積和を計算 | 粉末@それは風のように (日記)

  4. ピンバック: ループを用いずに0/1値を持つデータフレーム内で1が出現したインデックスから後の2つを1に置き換える | 粉末@それは風のように (日記)

  5. ピンバック: pandas.DataFrame.applyは(時空間効率の観点からは)使用するべきではない – 使用すべき明確な理由がない限りpandas.DataFrame.applyはリーズナブルチョイスになり得ない | 粉末@それは風のように

  6. ピンバック: pandas.DataFrame.applyは(時空間効率の観点からは)使用するべきではない – 使用すべき明確な理由がない限りpandas.DataFrame.applyはリーズナブルチョイスになり得ない | 粉末@それは風のように

  7. ピンバック: データフレーム各行の連続したゼロをカウント | 粉末@それは風のように (日記)

  8. ピンバック: データフレームの任意列における条件から降順の累積和を求める | 粉末@それは風のように (日記)

  9. ピンバック: pandasデータフレーム列内のNaNに基づいて累積和をリセット – 任意の条件に基づいた範囲で累積和を求める | 粉末@それは風のように (日記)

  10. ピンバック: データフレーム列内の連続した値の和(任意長の範囲で合計) | 粉末@それは風のように (日記)

コメントを残す

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

WordPress.com ロゴ

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

Google フォト

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

Twitter 画像

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

Facebook の写真

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

%s と連携中

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