web-dev-qa-db-ja.com

パンダ:列が別の列の特定の値に達したら、行の値を返すにはどうすればよいですか?

以下はデータのサンプルです。

enter image description here

目標:
_running_bid_max_が_ask_price_target_good_の値以上の場合の新しいタイムスタンプ列を作成します。次に、_running_bid_min_が以下_ask_price_target_bad_の場合に、別のタイムスタンプ列を作成します。

:これは大量のデータに対して実行され、必要な計算は可能な限り高速に行われます。 iterrows()を使用してすべての行を反復処理する必要がないことを願っています

_running_bid_min_および_running_bid_max_は、将来の特定のタイムフレームからrunning.min()およびpd.running.max()を使用して計算されます(この例では5分のタイムラインを使用しています。したがって、実行中の最小、現在の時刻から最大5分になります)

以下のデータをコピーしてから、df = pd.read_clipboard(sep=',')を使用してください

_   time,bid_price,ask_price,running_bid_max,running_bid_min,ask_price_target_good,ask_price_target_bad
2019-07-24 07:59:44.432034,291.06,291.26,291.4,291.09,291.46,291.06
2019-07-24 07:59:46.393418,291.1,291.33,291.4,291.09,291.53,291.13
2019-07-24 07:59:48.425615,291.1,291.33,291.4,291.09,291.53,291.13
2019-07-24 07:59:50.084206,291.12,291.33,291.4,291.09,291.53,291.13
2019-07-24 07:59:52.326455,291.12,291.33,291.4,291.09,291.53,291.13
2019-07-24 07:59:54.428181,291.12,291.33,291.4,291.09,291.53,291.13
2019-07-24 07:59:58.550378,291.14,291.35,291.4,291.2,291.55,291.15
2019-07-24 08:00:00.837238,291.2,291.35,291.4,291.2,291.55,291.15
2019-07-24 08:00:57.338769,291.4,291.46,291.51,291.4,291.66,291.26
2019-07-24 08:00:59.058198,291.4,291.46,291.96,291.4,291.66,291.26
2019-07-24 08:01:00.802679,291.4,291.46,291.96,291.4,291.66,291.26
2019-07-24 08:01:02.781289,291.4,291.46,291.96,291.45,291.66,291.26
2019-07-24 08:01:04.645144,291.45,291.46,291.96,291.45,291.66,291.26
2019-07-24 08:01:06.491997,291.45,291.46,292.07,291.45,291.66,291.26
2019-07-24 08:01:08.586688,291.45,291.46,292.1,291.45,291.66,291.26
_
14
bbennett36

あなたの質問から:

running_bid_maxask_price_target_goodの値以上の場合の新しいタイムスタンプ列を作成します。次に、running_bid_minask_price_target_bad以下の場合に、別のタイムスタンプ列を作成します

問題は些細なようです:

df['g'] = np.where(df.running_bid_max.ge(df.ask_price_target_good), df['time'], pd.NaT)

df['l'] = np.where(df.running_bid_min.le(df.ask_price_target_bad), df['time'], pd.NaT)

それとも何か不足していますか?


更新:上記のコマンドの後にffillおよびbfillを実行することができます。

df['g'] = df['g'].bfill()
df['l'] = df['l'].ffill()

出力、たとえばdf['g']

0    2019-07-24 08:00:59.058198
1    2019-07-24 08:00:59.058198
2    2019-07-24 08:00:59.058198
3    2019-07-24 08:00:59.058198
4    2019-07-24 08:00:59.058198
5    2019-07-24 08:00:59.058198
6    2019-07-24 08:00:59.058198
7    2019-07-24 08:00:59.058198
8    2019-07-24 08:00:59.058198
9    2019-07-24 08:00:59.058198
10   2019-07-24 08:01:00.802679
11   2019-07-24 08:01:02.781289
12   2019-07-24 08:01:04.645144
13   2019-07-24 08:01:06.491997
14   2019-07-24 08:01:08.586688
11
Quang Hoang

必要な出力を印刷できれば非常に便利です。さもなければ、私は論理を見逃すかもしれません。

大量のデータで作業している場合、 スチーム分析 *を適用することは理にかなっています。 (これはかなりメモリ効率が良く、cytoolzを使用すると2〜4倍速くなります)

したがって、基本的には、データをpartitionいずれかの条件に基づいてデータにしたいとします。

partitions = toolz.partitionby(lambda x: (x['running_bid_max'] >= x['ask_price_target_good']) or
                                         (x['running_bid_min'] <= x['ask_price_target_bad']), data_stream)

個々のパーティションで何をするかはあなた次第です(追加のフィールドや列などを作成できます)。

print([(part[0]['time'], part[-1]['time'], 
        part[0]['running_bid_max'] > part[0]['ask_price_target_good'],
        part[0]['running_bid_min'] > part[0]['ask_price_target_bad']) 
       for part in partitions])
[('2019-07-24T07:59:46.393418', '2019-07-24T07:59:46.393418', False, False), 
 ('2019-07-24T07:59:44.432034', '2019-07-24T07:59:44.432034', False,  True), 
 ('2019-07-24T07:59:48.425615', '2019-07-24T07:59:54.428181', False, False), 
 ('2019-07-24T07:59:58.550378', '2019-07-24T08:00:57.338769', False,  True), 
 ('2019-07-24T08:00:59.058198', '2019-07-24T08:01:08.586688',  True,  True)]

また、個別のDataFramesを作成するのは簡単です。

info_cols = ['running_bid_max', 'ask_price_target_good', 'running_bid_min', 'ask_price_target_bad', 'time'] 
data_frames = [pandas.DataFrame(_)[info_cols] for _ in partitions]
data_frames
   running_bid_max  ask_price_target_good  running_bid_min  ask_price_target_bad                        time
0            291.4                 291.53           291.09                291.13  2019-07-24T07:59:46.393418

   running_bid_max  ask_price_target_good  running_bid_min  ask_price_target_bad                        time
0            291.4                 291.46           291.09                291.06  2019-07-24T07:59:44.432034

   running_bid_max  ask_price_target_good  running_bid_min  ask_price_target_bad                        time
0            291.4                 291.53           291.09                291.13  2019-07-24T07:59:48.425615
1            291.4                 291.53           291.09                291.13  2019-07-24T07:59:50.084206
2            291.4                 291.53           291.09                291.13  2019-07-24T07:59:52.326455
3            291.4                 291.53           291.09                291.13  2019-07-24T07:59:54.428181

   running_bid_max  ask_price_target_good  running_bid_min  ask_price_target_bad                        time
0           291.40                 291.55            291.2                291.15  2019-07-24T07:59:58.550378
1           291.40                 291.55            291.2                291.15  2019-07-24T08:00:00.837238
2           291.51                 291.66            291.4                291.26  2019-07-24T08:00:57.338769

   running_bid_max  ask_price_target_good  running_bid_min  ask_price_target_bad                        time
0           291.96                 291.66           291.40                291.26  2019-07-24T08:00:59.058198
1           291.96                 291.66           291.40                291.26  2019-07-24T08:01:00.802679
2           291.96                 291.66           291.45                291.26  2019-07-24T08:01:02.781289
3           291.96                 291.66           291.45                291.26  2019-07-24T08:01:04.645144
4           292.07                 291.66           291.45                291.26  2019-07-24T08:01:06.491997
5           292.10                 291.66           291.45                291.26  2019-07-24T08:01:08.586688

残念ながら、ワンライナーが見つかりませんでしたpytition_by for DataFrame。きっとどこかに隠されています。 (ただし、pandasは通常、すべてのデータをメモリにロードします。I/ O中に集約したい場合は、ストリーミングが適しています。)


*ストリーミングの例

たとえば、単純なcsvストリームを作成してみましょう。

def data_stream():
    with open('blubb.csv') as tsfile:
        reader = csv.DictReader(tsfile, delimiter='\t')
        number_keys = [_ for _ in reader.fieldnames if _ != 'time']

        def update_values(data_item):
            for k in number_keys:
                data_item[k] = float(data_item[k])
            return data_item
        for row in reader:
            yield update_values(dict(row))

一度に1つの処理された行を生成します。

next(data_stream())

{'time': '2019-07-24T07:59:46.393418',
 'bid_price': 291.1,
 'ask_price': 291.33,
 'running_bid_max': 291.4,
 'running_bid_min': 291.09,
 'ask_price_target_good': 291.53,
 'ask_price_target_bad': 291.13}
5
Drey

これを試して:

df['g']=np.NaN
df['l']=np.NaN
deep=len(df.index)
irange= np.arange(1,deep)

for i in irange:
    G=df.time[df.running_bid_max.shift(i)-df.ask_price_target_good>=0]
    G.index=G.index-i
    df['g']=df['g'].combine_first(G)

    L=df.time[df.running_bid_min.shift(i)-df.ask_price_target_bad<=0]
    L.index=L.index-i
    df['l']=df['l'].combine_first(L)

ディープパラメーターを変更できます(時間枠)

最適化できる

4
Andrea Mannari

私はあなたの問題を正しく理解しているとは思いません。以下の問題の解決策を以下に示します。

  • 特定の行(現在の行と呼びます)について、この行の時刻とこの行の時刻に5分を足した時刻の間にあるすべての行を保持します。
  • 保持した行で、running_bid_maxが現在の行のask_price_target_good列にある値よりも優れているかどうかを検索します
  • その場合、最初のrunning_bid_maxを現在の行のask_price_target_goodよりも上に保持します

あなたの例では、行0の場合、291.46ask_price_target_goodがあります。行8(row0の時間から5分の時間枠内の時間)で291.51291.46より優れている)を見つけ、したがって、この値を行0に保持します。

対称操作はrunning_bid_minに対して行う必要があります。これは、ask_price_target_badよりも劣るようにテストする必要があります。

この問題を解決するために、次のコードを書きました。私はiterrowsではなくapplyDataFrame関数を使用しています。それにもかかわらず、各行について、ask_price_target_goodよりも優れている可能性がある行を検索する前に、データフレーム全体(5分の時間枠)から一連の行を選択する必要があります。データフレームが大きい場合、これで十分高速になることを願っています。

import numpy as np
import pandas as pd
import datetime as dtm

data = pd.read_csv("data.csv", parse_dates=["time"])

TIME_WINDOW = 5*60

def over_target_good(row, dataframe):
    time_window = dataframe.time <= (row.time
                                     + dtm.timedelta(seconds=TIME_WINDOW))
    window_data = dataframe[time_window]
    over_test = window_data.running_bid_max >= row.ask_price_target_good
    over_data = window_data[over_test]
    if len(over_data) > 0:
        return over_data.running_bid_max[over_data.index[0]]
    return np.NaN

def below_target_bad(row, dataframe):
    time_window = dataframe.time <= (row.time
                                     + dtm.timedelta(seconds=TIME_WINDOW))
    window_data = dataframe[time_window]
    below_test = window_data.running_bid_min <= row.ask_price_target_bad
    below_data = window_data[below_test]
    if len(below_data) > 0:
        return below_data.running_bid_min[below_data.index[0]]
    return np.NaN

print("OVER\n", data.apply(over_target_good, axis=1, args=(data,)) )
print("BELOW\n", data.apply(below_target_bad, axis=1, args=(data,)) )
4
Olivier CAYROL

あなたはただ使うことができます:

df['time_bid_max_greater'] = df.time[df['running_bid_max'] >= df['ask_price_target_good']]

df['time_bid_min_less'] = df.time[df['running_bid_min'] <= df['ask_price_target_bad']]

df

enter image description here

1
kederrac

目標

running_bid_maxask_price_target_goodの値以上の場合の新しいタイムスタンプ列を作成します。次に、running_bid_minask_price_target_bad以下の場合に、別のタイムスタンプ列を作成します

これを試して :

import numpy as np

#   Setup conditions
conditions = [
  (df['running_bid_max'] >= df['ask_price_target_good']),
  (df['running_bid_min'] >= df['ask_price_target_bad'])]

#   Setup output (you could insert timestamp var here)
choices = ["Greater", "Lesser"]

#   Apply conditions
df['bid_value'] = np.select(conditions, choices, default='N/A')

これが解決策を提供するのに役立つことを願っています:)

1
Anthony R

わかりましたので、理解すると思います。各行の値を、これらの条件が満たされる次の日付のタイムスタンプにしたいですか?もしそうなら、クアンの答えに基づいて構築することができます。具体的には、まだやってみましょう

df['g'] = np.where(df.running_bid_max.ge(df.ask_price_target_good), df['time'], pd.NaT)

df['l'] = np.where(df.running_bid_min.le(df.ask_price_target_bad), df['time'], pd.NaT)

これで、次のことができます。

 df['g'] = df['g'].fillna(method='bfill')
 df['l'] = df['l'].fillna(method='bfill')

これで、行9の行0のタイムスタンプが得られます。

これはあなたが探しているものですか?

1
hchw