時系列データの補間と年ごとの合計

sum by year and insert missing entries with 0 – StackOverflow

%%writefile file
201703 5
201708 10
201709 20
201710 40
201711 80
201712 100
201802 0
201803 25
201804 50
201805 50
201806 150
201807 300
201808 200
201902 10 

というファイルがあった時,欠けている月のインデックスを補間して欠損値は0埋めしたい.そして,年ごとの合計を求めて,各年の末尾に結果が挿入された形のデータフレームを作成したい.メソッドチェーンを用いると,意外に楽に処理できる(処理するのが楽なのであって,他人がみた時に一見して分かり易いかどうかは分からないけど).

import pandas as pd
import numpy as np
from datetime import datetime


def d_parser(x):  return datetime.strptime(x, '%Y%m')


df = (
    pd.read_csv('file', sep='\s+', header=None, 
                index_col=0, parse_dates=[0], date_parser=d_parser)
    .asfreq('MS', fill_value=0)
    .pipe(lambda df: 
          df.set_index(df.index.strftime('%Y%m'))
            .append(df.groupby(df.index.year.astype(str)+'13').sum())
            .assign(index=lambda res: res.index.str.replace('13', ''))
            .sort_index()
            .set_index('index')
    )
)
df
    1
index   
201703  5
201704  0
201705  0
201706  0
201707  0
201708  10
201709  20
201710  40
201711  80
201712  100
2017    255
201801  0
201802  0
201803  25
201804  50
201805  50
201806  150
201807  300
201808  200
201809  0
201810  0
201811  0
201812  0
2018    775
201901  0
201902  10
2019    10

 
 
Awkの場合:

%%bash
time {
awk '
{a[$1]=$2;yy=substr($1,1,4);mm=substr($1,5,2)+0;sum[yy]+=$2} NR==1{b=yy}
b!=yy{for(m=min;mmm ? mm : min);max=(!max||max<mm ? mm : max)}
END{for(m=1;m<=mm;m++){k=sprintf("%s%02d",b,m);print k,(k in a ? a[k] : 0)}print b,sum[b]}
' file
}
201703 5
201704 0
201705 0
201706 0
201707 0
201708 10
201709 20
201710 40
201711 80
201712 100
2017 255
201801 0
201802 0
201803 25
201804 50
201805 50
201806 150
201807 300
201808 200
201809 0
201810 0
201811 0
201812 0
2018 775
201901 0
201902 10
2019 10

real    0m0.005s
user    0m0.001s
sys 0m0.003s
広告
カテゴリー: 未分類 | コメントをどうぞ

How can I perform a value dependent pivot table/Groupby in Pandas?

How can I perform a value dependent pivot table/Groupby in Pandas? – StackOverflow

import io
import pandas as pd


strings = """      Tran ID    Category    Quantity 
   0   001          A           5
   1   001          B           2 
   2   001          C           3
   3   002          A           4
   4   002          C           2
   5   003          D           6 """

df = pd.read_csv(io.StringIO(strings), sep='\s{2,}', dtype={'Tran ID': str}, engine='python')
display(df)

res = pd.concat((pd.get_dummies(df['Category']).astype(bool), df['Quantity']), 1).groupby(df['Tran ID']).sum()
display(res)


pd.read_csv(
    io.StringIO(strings), 
    sep='\s{2,}', 
    dtype={'Tran ID': str}, 
    engine='python'
).pipe(lambda df: 
       df['Category'].pipe(pd.get_dummies)
                     .groupby(df['Tran ID']).sum().astype(bool)
                     .join(df['Quantity'].groupby(df['Tran ID']).sum())
)
Tran ID Category    Quantity
0   001 A   5
1   001 B   2
2   001 C   3
3   002 A   4
4   002 C   2
5   003 D   6
A   B   C   D   Quantity
Tran ID                 
001 True    True    True    False   10
002 True    False   True    False   6
003 False   False   False   True    6
A   B   C   D   Quantity
Tran ID                 
001 True    True    True    False   10
002 True    False   True    False   6
003 False   False   False   True    6
カテゴリー: 未分類 | コメントをどうぞ

データフレーム内リストの値に基づいて要素を複製

Pandas correct values in lists – StackOverflow

結局,Pandasの皮を被ったただのリストなので,ピュアに処理すれば良い.

import pandas as pd


def splitmax(df):
    d = {'pos': [], 'value': []}
    v = df['value'].values.tolist()
    p = df['pos'].values.tolist()
    t = sum(max(v)) // 1000
    T = t * 2 + 2 - t
    for vlst, plst in zip(v, p):
        res, N = [], []
        for x in vlst:
            if x >= 1000:
                res.extend((x/2, x/2))
                N.append(2)
            else:
                res.append(x)
                N.append(1)

        n = sum(N)
        if n < T: res.extend([0]*(T-n))
        d['value'].append(res)

        res = []
        for s, c in zip(plst, N):
            res.extend([s]*c)
        if n < T: res.extend(['nan']*(T-n))
        d['pos'].append(res)
    return pd.DataFrame(d)


data = {"pos":[["A1","A2"],
               ["B1","B2"]],
        "value"  :[[20,1000],
                 [20,50]]}
df = pd.DataFrame(data)
print(df, end='\n\n')

print(splitmax(df), end='\n\n')

data = {"pos":[["A1","A2"],
               ["B1","B2"],
               ["C1","C2"]],
        "value"  :[[20,1000],
                   [20,50],
                   [1000,1000]]}
df = pd.DataFrame(data)
print(df, end='\n\n')

print(splitmax(df), end='\n\n')
        pos       value
0  [A1, A2]  [20, 1000]
1  [B1, B2]    [20, 50]

             pos               value
0   [A1, A2, A2]  [20, 500.0, 500.0]
1  [B1, B2, nan]         [20, 50, 0]

        pos         value
0  [A1, A2]    [20, 1000]
1  [B1, B2]      [20, 50]
2  [C1, C2]  [1000, 1000]

                  pos                         value
0   [A1, A2, A2, nan]         [20, 500.0, 500.0, 0]
1  [B1, B2, nan, nan]                [20, 50, 0, 0]
2    [C1, C1, C2, C2]  [500.0, 500.0, 500.0, 500.0]
カテゴリー: 未分類 | コメントをどうぞ

リストを等しい長さに分割

Splitting an array in equal parts – StackOverflow

アレイ(numpy.ndarray)を等しい長さに分割と云えば,

import numpy as np


np.array_split([1, 2, 3, 4, 5, 6, 7], 3)
[array([1, 2, 3]), array([4, 5]), array([6, 7])]

ここでは,リストを等しい長さのサブリストに分割する事を考えたい.
まあ,やる事は一緒な訳だけども.

from itertools import accumulate


def array_split(lst, n=3):
    N = len(lst)
    v, m = divmod(N, n)
    p = [0] + m*[v+1] + (n-m)*[v]
    dp = list(accumulate(p))

    res = []
    for i in range(n):
        s, e = dp[i], dp[i+1]
        res.append(lst[s:e])
    return res


array_split([1, 2, 3, 4, 5, 6, 7])
[[1, 2, 3], [4, 5], [6, 7]]
カテゴリー: 未分類 | コメントをどうぞ

pandas.DataFrame.replaceを使用して列内の2つの文字列/値を入れ替えると一貫した挙動を示さない

How to swap two (string) values in a column using pandas – StackOverflow

これは,既に解決されているバグ.

import pandas as pd
print(pd.__version__)


df = pd.DataFrame({'Col': ['X','Y','X','Y','X']})
display(df)

res1 = df.replace({'X': 'Y', 'Y': 'X'})
display(res1)

res2 = df.assign(Col=lambda df: df['Col'].map({'X': 'Y', 'Y': 'X'}))
res2
0.22.0
Col
0   X
1   Y
2   X
3   Y
4   X
Col
0   X
1   X
2   X
3   X
4   X
Col
0   Y
1   X
2   Y
3   X
4   Y
import pandas as pd
print(pd.__version__)


df = pd.DataFrame({'Col': ['X','Y','X','Y','X']})
display(df)

res1 = df.replace({'X': 'Y', 'Y': 'X'})
display(res1)

res2 = df.assign(Col=lambda df: df['Col'].map({'X': 'Y', 'Y': 'X'}))
res2
0.24.2
Col
0   X
1   Y
2   X
3   Y
4   X
Col
0   Y
1   X
2   Y
3   X
4   Y
Col
0   Y
1   X
2   Y
3   X
4   Y
カテゴリー: 未分類 | コメントをどうぞ

各行に異なる3次元回転行列を乗算

Multiply each row by different rotation matrix – StackOverflow

def transform(ref, pose):
    # Setup 3D rotation matrix
    cs = np.empty((n,2,2))
    cs[:,0,0] = c
    cs[:,1,1] = c
    cs[:,0,1] = s
    cs[:,1,0] = -s
    
    # Perform 3D matrix multiplications with einsum
    p_out = ref[:, :d].copy()
    p_out[:,:2] += np.einsum('ij,ijk->ik',pose[:,:2],cs)
    return p_out

numpy.einsumを用いたこのトリックはまだまだ自分のものにできていないので,勉強しないとなあ.

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

隣接セルの合計(コンボリューション)

Python: how to reshape a dataframe by summing neighbour cells? – StackOverflow

隣接セルの足し合わせは要はコンボリューション(2Dのコンボリューションを行う方法としては、「scipy.ndimage.convolve」と「scipy.signal.convolve」があるが、関連に示す様に効率が全然違う(N数が大きくなると20倍以上)ので使い分けが重要;同様のケースでは「scipy.ndimage.convolve」がリーズナブルチョイス).それとは別にFlat Indexing(Linear Indexing)という手もある.

import io
import numpy as np
import pandas as pd
from scipy import ndimage
from scipy import signal


def sum_cells(arr, R=3, C=3, n=1):
    r, c = arr.shape
    idx = (
        ((np.arange(R)*c)[:, None] + np.arange(C)).ravel()
        + np.arange(0, c-n, C-n)[:, None]
        + np.arange(0, r-n, R-n)[:, None, None]*c
    )
    return arr.flat[idx].sum(-1)


strings = """        0   1   2   3   4
     0  8   3   2   2   5
     1  5   8   1   5   6
     2  1   9   1   4   2
     3  0   7   7   6   9
     4  5   8   7   0   9
     5  0   3   9   9   4
     6  7   7   8   5   4"""

df = pd.read_csv(io.StringIO(strings), sep='\s+')
arr = df.values

kernel = np.ones((3, 3), dtype=np.int8)
res1 = pd.DataFrame(signal.convolve(arr, kernel, 'same')[1::2, 1::2])
print(res1, end='\n\n')
%timeit kernel = np.ones((3, 3), dtype=np.int8);res1 = pd.DataFrame(signal.convolve(arr, kernel, 'same')[1::2, 1::2])

res2 = pd.DataFrame(ndimage.convolve(arr, kernel, mode='constant')[1::2, 1::2])
print(res2, end='\n\n')
%timeit kernel = np.ones((3, 3), dtype=np.int8);res2 = pd.DataFrame(ndimage.convolve(arr, kernel, mode='constant')[1::2, 1::2])

res3 = pd.DataFrame(sum_cells(arr))
print(res3, end='\n\n')
%timeit res3 = pd.DataFrame(sum_cells(arr))
    0   1
0  38  28
1  45  45
2  54  55

10000 loops, best of 3: 138 µs per loop
    0   1
0  38  28
1  45  45
2  54  55

10000 loops, best of 3: 117 µs per loop
    0   1
0  38  28
1  45  45
2  54  55

10000 loops, best of 3: 93.1 µs per loop

 
 
関連:
隣接カウント

隣接セルの合計(コンボリューション)

2D配列(numpy.ndarray)の隣接要素をグループ化(クラスタ化)

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