Groupbyでいくつかの行といくつかの列を合計

sum up some rows and some columns with Groupby – StackOverflow

条件が明示されていないけど,2行ずつ集計したいと捉える.

import io
import pandas as pd


strings = """  Name  c1  c2  c3  c4
0   a1   1   2   2   3
1   a2   2   1   1   2
2   a3   3   1   2   1
3   a4   2   3   3   4
4   b1   1   2   2   3
5   b2   3   1   2   1
6   b3   2   1   2   1
7   b4   1   3   4   1"""

f = """
c1_c2=c1+c2
c3_c4=c3+c4
"""
df = (
    pd.read_csv(io.StringIO(strings), sep='\s+')
    .eval(f)[['Name', 'c1_c2', 'c3_c4']]
    .groupby(lambda i: i//2)
    .agg({'Name': '+'.join, 'c1_c2': 'sum', 'c3_c4': 'sum'})
)
df
    Name    c1_c2   c3_c4
0   a1+a2   6   8
1   a3+a4   9   10
2   b1+b2   7   8
3   b3+b4   7   8
広告
カテゴリー: 未分類 | コメントをどうぞ

範囲ルックアップの様な処理

Pandas lookup value in a range from another table – StackOverflow

enter image description here

の様な処理を考える.Pandasで処理する場合,コメントの様にintervalindexとget_indexerで処理するのがリーズナブル.個人的には,Numpyでブロードキャストを用いる方がシンプルかなと.

import pandas as pd
import numpy as np


df1 = pd.DataFrame({'Date': {0: '06-01', 1: '06-02', 2: '06-03', 3: '06-04'},
                   'Value': {0: 3, 1: 7, 2: 9, 3: 16}, })

df2 = pd.DataFrame({'Start': {0: 1, 1: 6, 2: 11, 3: 16},
                    'Stop': {0: 5, 1: 10, 2: 15, 3: 20},
                    'Fruit': {0: 'Apple', 1: 'Orange', 2: 'Pear', 3: 'Mango'},})

v = df1['Value'].to_numpy()
m = (df2['Start'].to_numpy()<=v[:, None]) & (v[:, None]<=df2['Stop'].to_numpy())
df1.assign(Fruit=df2['Fruit'].to_numpy()[m.nonzero()[1]])
    Date    Value   Fruit
0   06-01   3   Apple
1   06-02   7   Orange
2   06-03   9   Orange
3   06-04   16  Mango
カテゴリー: 未分類 | コメントをどうぞ

与えられた時系列から任意の日までの営業日数の計算

How to get the number of business days between two dates in pandas – StackOverflow

Pandasに標準機能としてありそうなものだが,改めて調べてそれらしいものはなさそう.「numpy.busday_count」を用いるしか無いっぽい.numpy.datetime64は余り好きじゃないんだけど.

回答の方法では,オブジェクト型を処理しているので効率が悪い.numpyとして処理する為には,numpy.ndarrayにして「datetime64[D]」に型変換するべき.

import io
import pandas as pd
import numpy as np


strings = """Date
2019-6-21
2019-6-20
2019-6-14"""

df = (
    pd.read_csv(io.StringIO(strings), parse_dates=['Date'])
    .assign(
        bdays=lambda df: np.busday_count(
            df['Date'].to_numpy().astype('datetime64[D]'), 
            np.datetime64('today')
        )
    )
)
df
    Date        bdays
0   2019-06-21  2
1   2019-06-20  3
2   2019-06-14  7

参考:
Pandas number of business days between a DatetimeIndex and a Timestamp – StackOverflow

カテゴリー: 未分類 | コメントをどうぞ

リストが含まれるデータフレームのフラット化

Numpy array as element of pandas dataframe management – StackOverflow

import pandas as pd
import numpy as np


d = {'A4': [[1, 2, 3, 4]], 'B': [12,], 'B4': [[5, 6, 7, 8]]} 
df = pd.DataFrame(d)
print(df, end='\n\n')

g = (pd.DataFrame(df[c].tolist()).add_prefix(c[:-1]) 
     if c.endswith('4') else df[c] for c in df)
res = pd.concat(g, 1)
print(res, end='\n\n')
             A4   B            B4
0  [1, 2, 3, 4]  12  [5, 6, 7, 8]

   A0  A1  A2  A3   B  B0  B1  B2  B3
0   1   2   3   4  12   5   6   7   8
カテゴリー: 未分類 | コメントをどうぞ

良い感じ

ドル円112.23円ショートを107.33で利確.直近,108円の壁が余りにも厚く,心が折れかけて手仕舞いしてしまおうかと悩んだが,久しぶりに綺麗に刺さったので気持ち良い.メインシナリオ通りの展開で,107円を割るとは思えず,ここからは107-110円を想定.リスクシナリオでは106-103円まで円高が進行する事を想定するが,とにかく値幅的には一旦は下げは終了とみて,日柄的には06/22-07/01に底値をとって,7月にかけて109.3アラウンドまで反発する事を予想し,107.06でロングポジションを仕込んでおいた.107円割れの予想指標としては,ビットコインや金が良い感じ.直近は株価と為替の相関が弱く,他通貨(ユーロ,ポンド,豪ドル,カナダドル)の強弱からドルインデックスも相関が弱いので(直近,2週間の動きで云えば,ドル安円高→他通貨高→ドル安円安,ドル高円高,原油高→コモディティ通貨高→円安バイアス,ドル安円高の流れ),リスクセンチメントは金でみる方が良いし,ビットコインは地政学的リスクと合わせてドルの強さをよく表している.ビットコインは1万ドル超えが注目されているが,株式市場が総崩れとなり,ビットコインが1万ドルを超えてくる様な展開になると,リスクシナリオを十分に想定する必要がありそう.

カテゴリー: 未分類 | コメントをどうぞ

任意列から条件を満たす行を順序を維持して選択

How to maintain order when selecting rows in pandas dataframe? – StackOverflow

pandas.Index.get_indexerを用いた方法は一見エレガントにみえるが,重複があるとInvalidIndexErrorになる.numpy.argsort+numpy.searchsortedは,時間効率は良いが,重複を処理できないので,条件と比較したい任意列をset_indexしてpandas.DataFrame.locでアクセスする方がリーズナブル.

import pandas as pd


lst = [
    ['car', 1], 
    ['bike', 3],
    ['jewel', 2], 
    ['tv', 5], 
    ['phone', 6]
]
m = ['tv', 'car', 'phone']

df = pd.DataFrame(lst, columns=['items','quantity'])
display(df.query('items in @m'))
display(df.set_index('items').loc[m])
    items   quantity
0   car 1
3   tv  5
4   phone   6

    quantity
items   
tv  5
car 1
phone   6
カテゴリー: 未分類 | コメントをどうぞ

連続した数のカウント

Counting number of consecutive occurences of numbers in a series – StackOverflow

Numpyがリーズナブルチョイス.これを高速化しようと思うと,粒度は悪いし面倒(というか失敗).

%%cython
import cython
import numpy as np
import pandas as pd
cimport numpy as np


@cython.ccall
@cython.returns(np.ndarray)
@cython.locals(a=np.ndarray, idx=np.ndarray)
def groupby_count_cython(a):
    idx = np.flatnonzero(np.concatenate(([True], a[:-1]!=a[1:], [True])))
    return np.column_stack((a[idx[:-1]], np.diff(idx)))


def groupby_count(a):
    idx = np.flatnonzero(np.concatenate(([True], a[:-1]!=a[1:], [True])))
    return np.column_stack((a[idx[:-1]], np.diff(idx)))


def groupby_count_pandas(a):
    df = pd.DataFrame(a)
    g = df[0].ne(df[0].shift()).cumsum()
    return df.groupby(g).agg(['first', 'count']).to_numpy()
from numba import jit


@jit
def groupby_count_numba(a):
    idx = np.flatnonzero(np.concatenate(([True], a[:-1]!=a[1:], [True])))
    return np.column_stack((a[idx[:-1]], np.diff(idx)))
a = np.array([0, 0, 1, 1, 1, 0, 1, 1, 1, 1])
groupby_count_cython(a), groupby_count_numba(a)
(array([[0, 2],
        [1, 3],
        [0, 1],
        [1, 4]]), array([[0, 2],
        [1, 3],
        [0, 1],
        [1, 4]]))
%%cython
import numpy as np
cimport numpy as np


DTYPE_INT = np.uint64
ctypedef np.uint64_t DTYPE_INT_t
DTYPE_BOOL = np.bool
ctypedef np.npy_bool DTYPE_BOOL_t


cdef np.ndarray[DTYPE_INT_t, ndim=2] _groupby_count_c(np.ndarray a):
    cdef unsigned int n = len(a)
    cdef unsigned int cnt = 0
    cdef unsigned int b = 0
    cdef unsigned int i
    cdef np.ndarray[DTYPE_INT_t, ndim=2] out = np.zeros((n, 2), dtype=DTYPE_INT)
    for i in range(n-1):
        if a[i+1] != a[i]:
            out[cnt, 1] = i + 1 - b
            b = i + 1
            if a[i]:
                out[cnt, 0] = a[i]
            cnt += 1
    if a[b] == a[i+1]:
        out[cnt, 1] = i + 2 - b
        if a[b]:
            out[cnt, 0] = a[b]
        cnt += 1
    return out[:cnt]


cpdef np.ndarray groupby_count_c(np.ndarray a):
    return _groupby_count_c(a)
a = np.array([0, 0, 1, 1, 1, 0, 1, 1, 1, 1])
groupby_count_c(a)
array([[0, 2],
       [1, 3],
       [0, 1],
       [1, 4]], dtype=uint64)
np.random.seed(a)
a = np.random.choice([0,1], 10000000)
%timeit groupby_count(a)
%timeit groupby_count_cython(a)
%timeit groupby_count_numba(a)
%timeit groupby_count_c(a)
%timeit groupby_count_pandas(a)
10 loops, best of 3: 139 ms per loop
10 loops, best of 3: 138 ms per loop
10 loops, best of 3: 138 ms per loop
1 loop, best of 3: 2.44 s per loop
1 loop, best of 3: 3.48 s per loop
カテゴリー: 未分類 | コメントをどうぞ