1

たとえば、dfを作成します。

import pandas as pd
import random as randy
import numpy as np
df_size = int(1e6)
df = pd.DataFrame({'first':       randy.sample(np.repeat([np.NaN,'Cat','Dog','Bear','Fish'],df_size),df_size),
               'second': randy.sample(np.repeat([np.NaN,np.NaN,'Cat','Dog'],df_size),df_size),
                'value': range(df_size)},
                index=randy.sample(pd.date_range('2013-02-01 09:00:00.000000',periods=1e6,freq='U'),df_size)).sort_index()

そしてそれはこのように見えます:

                            first   second    value
2013-02-01 09:00:00          Fish    Cat     95409
2013-02-01 09:00:00.000001   Dog     Dog     323089
2013-02-01 09:00:00.000002   Fish    Cat     785925
2013-02-01 09:00:00.000003   Dog     Cat     866171
2013-02-01 09:00:00.000004   nan     nan     665702
2013-02-01 09:00:00.000005   Cat     nan     104257
2013-02-01 09:00:00.000006   nan     nan     152926
2013-02-01 09:00:00.000007   Bear    Cat     707747

私が欲しいのは、「2番目の」列の各値に対して、最初の「最後の」値が欲しいということです。

                            first   second   value  new_value
2013-02-01 09:00:00         Fish     Cat     95409    NaN
2013-02-01 09:00:00.000001   Dog     Dog     323089   323089
2013-02-01 09:00:00.000002   Fish    Cat     785925   NaN
2013-02-01 09:00:00.000003   Dog     Cat     866171   NaN
2013-02-01 09:00:00.000004   nan     nan     665702   NaN
2013-02-01 09:00:00.000005   Cat     nan     104257   NaN
2013-02-01 09:00:00.000006   nan     nan     152926   NaN
2013-02-01 09:00:00.000007   Bear    Cat     707747   104257

おそらく、それは絶対的な最良の例ではありませんが、一番下の「second」が「Cat」の場合、「first」が「Cat」のときの最新の値が必要です。

実際のデータセットには10​​00以上のカテゴリがあるため、シンボルをループしてasof()を実行すると非常にコストがかかるように見えます。Cythonで文字列を渡すことはできませんでしたが、シンボルをintにマッピングし、ブルートフォースループを実行するとうまくいくと思います。もっとPython的なものを望んでいました。(それでもかなり速いです)

参照、およびやや壊れやすいCythonハックは次のようになります。

%%cython
import numpy as np
import sys
cimport cython
cimport numpy as np

ctypedef np.double_t DTYPE_t

def last_of(np.ndarray[DTYPE_t, ndim=1] some_values,np.ndarray[long, ndim=1] first_sym,np.ndarray[long, ndim=1] second_sym):
    cdef long val_len = some_values.shape[0], sym1_len = first_sym.shape[0], sym2_len = second_sym.shape[0], i = 0
    assert(sym1_len==sym2_len)
    assert(val_len==sym1_len)
    cdef int enum_space_size = max(first_sym)+1

    cdef np.ndarray[DTYPE_t, ndim=1] last_values = np.zeros(enum_space_size, dtype=np.double) * np.NaN
    cdef np.ndarray[DTYPE_t, ndim=1] res = np.zeros(val_len, dtype=np.double) * np.NaN
    for i in range(0,val_len):
        if first_sym[i]>=0:
            last_values[first_sym[i]] = some_values[i]
        if second_sym[i]<0 or second_sym[i]>=enum_space_size:
            res[i] = np.NaN
        else:
            res[i] = last_values[second_sym[i]]
    return res

そして、いくつかのdictがナンセンスを置き換えます:

syms= unique(df['first'].values)
enum_dict = dict(zip(syms,range(0,len(syms))))
enum_dict['nan'] = -1
df['enum_first'] = df['first'].replace(enum_dict)
df['enum_second'] = df['second'].replace(enum_dict)
df['last_value'] = last_of(df.value.values*1.0,df.enum_first.values.astype(int64),df.enum_second.values.astype(int64))

これには、「2番目の」列に最初の列にない値がある場合に問題が発生するという問題があります。(これを修正するための迅速な方法はわかりません...たとえば、2番目に「ロバ」を追加した場合)

1000万行あたりのcythonicの愚かなバージョンは、混乱全体で約21秒ですが、cython部分では約2秒です。(これはまともな量をより速くすることができます)

@HYRY-これはかなり堅固な解決策だと思います。1000万行のDFの場合、私のラップトップでは、これには約30秒かかります。

2番目のリストに最初のリストにないエントリが含まれている場合の簡単な処理方法がわからないことを考えると、かなり高価なisin以外に、HYRYのPythonバージョンはかなり良いと思います。

4

2 に答える 2

3

dict を使用してすべてのカテゴリの最後の値を保持し、DataFrame 内のすべての行を繰り返します。

import pandas as pd
import random as randy
import numpy as np
np.random.seed(1)
df_size = int(1e2)
df = pd.DataFrame({'first':       randy.sample(np.repeat([None,'Cat','Dog','Bear','Fish'],df_size),df_size),
               'second': randy.sample(np.repeat([None,None,'Cat','Dog'],df_size),df_size),
                'value': range(df_size)},
                index=randy.sample(pd.date_range('2013-02-01 09:00:00.000000',periods=1e6,freq='U'),df_size)).sort_index()

last_values = {}
new_values = []
for row in df.itertuples():
    t, f, s, v = row    
    last_values[f] = v
    if s is None:
        new_values.append(None)
    else:
        new_values.append(last_values.get(s, None))
df["new_value"] = new_values

結果は

                          first second  value new_value
2013-02-01 09:00:00.010373   Cat   None     87      None
2013-02-01 09:00:00.013015   Cat    Dog     69      None
2013-02-01 09:00:00.024910  Fish    Cat      1        69
2013-02-01 09:00:00.025943   Cat   None     98      None
2013-02-01 09:00:00.041318  Fish    Dog     66      None
2013-02-01 09:00:00.057894  None   None     36      None
2013-02-01 09:00:00.059678  None   None     50      None
2013-02-01 09:00:00.067228  Bear   None     38      None
2013-02-01 09:00:00.095867  Bear    Cat     84        98
2013-02-01 09:00:00.096867   Dog    Cat     97        98
2013-02-01 09:00:00.101540   Dog    Dog     76        76
2013-02-01 09:00:00.106753   Dog   None     22      None
2013-02-01 09:00:00.138936  None   None      8      None
2013-02-01 09:00:00.139273  Bear    Cat      2        98
2013-02-01 09:00:00.143180  Fish   None     94      None
2013-02-01 09:00:00.184757  None    Cat     73        98
2013-02-01 09:00:00.193063  None   None      5      None
2013-02-01 09:00:00.231056  Fish    Cat     62        98
2013-02-01 09:00:00.237658  None   None     64      None
2013-02-01 09:00:00.240178  Bear    Dog     80        22
于 2013-02-24T05:49:00.373 に答える
0

私が知っている古い質問ですが、これはPythonループを回避する解決策です。'value'最初のステップは、各カテゴリの時系列を取得することです。スタックを解除することでこれを行うことができます:

first_values = df.dropna(subset=['first']).set_index('first', append=True).value.unstack()    
second_values = df.dropna(subset=['second']).set_index('second', append=True).value.unstack()

NaNこれは、列に文字列ではなく真の値が含まれている場合にのみ機能することに注意してください'nan'(df = df.replace('nan', np.nan)必要に応じて準備してください)。

次に、元のペアを使用して、 を順方向に埋めfirst_values、 のようsecond_valuesに再インデックスし、再度スタックし、結果にインデックスを付けることで、最後の最初の値を取得できます。'time', 'second'

ix = pd.MultiIndex.from_arrays([df.index, df.second])
new_value = first_values.ffill().reindex_like(second_values).stack().reindex(ix)
df['new_value'] = new_value.values

In [1649]:    df
Out[1649]:
                           first    second  value   new_value
2013-02-01 09:00:00.000000  Fish    Cat     95409   NaN
2013-02-01 09:00:00.000001  Dog     Dog     323089  323089
2013-02-01 09:00:00.000002  Fish    Cat     785925  NaN
2013-02-01 09:00:00.000003  Dog     Cat     866171  NaN
2013-02-01 09:00:00.000004  NaN     NaN     665702  NaN
2013-02-01 09:00:00.000005  Cat     NaN     104257  NaN
2013-02-01 09:00:00.000006  NaN     NaN     152926  NaN
2013-02-01 09:00:00.000007  Bear    Cat     707747  104257
于 2015-10-15T09:29:09.883 に答える