Было интересно, если есть более эффективный способ разделения нескольких столбцов определенного столбца. Например, у меня есть:

prev    open    close   volume
20.77   20.87   19.87   962816
19.87   19.89   19.56   668076
19.56   19.96   20.1    578987
20.1    20.4    20.53   418597

И я бы хотел получить:

prev    open    close   volume
20.77   1.0048  0.9567  962816
19.87   1.0010  0.9844  668076
19.56   1.0204  1.0276  578987
20.1    1.0149  1.0214  418597

По сути, столбцы «open» и «close» были разделены на значение из столбца «prev».

Я смог сделать это

df['open'] = list(map(lambda x,y: x/y, df['open'],df['prev']))
df['close'] = list(map(lambda x,y: x/y, df['close'],df['prev']))

Мне было интересно, если есть более простой способ? Особенно если в любом случае есть примерно 10 столбцов, которые должны быть разделены на одно и то же значение?

3
user1179317 26 Авг 2017 в 23:56

3 ответа

Лучший ответ
df2[['open','close']] = df2[['open','close']].div(df2['prev'].values,axis=0)

Выход:

    prev      open     close  volume
0  20.77  1.004815  0.956668  962816
1  19.87  1.001007  0.984399  668076
2  19.56  1.020450  1.027607  578987
3  20.10  1.014925  1.021393  418597
2
Scott Boston 26 Авг 2017 в 21:05
columns_to_divide = ['open', 'close']
df[columns_to_divide] = df[columns_to_divide] / df['prev']
4
DYZ 26 Авг 2017 в 21:01

Для производительности я бы предложил использовать базовые данные массива и array-slicing, так как два столбца, которые нужно изменить, идут последовательно, чтобы использовать их вид -

a = df.values
df.iloc[:,1:3] = a[:,1:3]/a[:,0,None]

Чтобы выразить немного больше о части среза массива, с a[:,[1,2]] нужно было бы скопировать туда копию и замедлить ее. a[:,[1,2]] на стороне фрейма данных эквивалентен df[['open','close']], и это, я думаю, тоже замедляет ход событий. df.iloc[:,1:3], таким образом, улучшается.

Пробный прогон -

In [64]: df
Out[64]: 
    prev   open  close  volume
0  20.77  20.87  19.87  962816
1  19.87  19.89  19.56  668076
2  19.56  19.96  20.10  578987
3  20.10  20.40  20.53  418597

In [65]: a = df.values
    ...: df.iloc[:,1:3] = a[:,1:3]/a[:,0,None]
    ...: 

In [66]: df
Out[66]: 
    prev      open     close  volume
0  20.77  1.004815  0.956668  962816
1  19.87  1.001007  0.984399  668076
2  19.56  1.020450  1.027607  578987
3  20.10  1.014925  1.021393  418597

Тест во время выполнения

Подходы -

def numpy_app(df): # Proposed in this post
    a = df.values
    df.iloc[:,1:3] = a[:,1:3]/a[:,0,None]
    return df

def pandas_app1(df): # @Scott Boston's soln
    df[['open','close']] = df[['open','close']].div(df['prev'].values,axis=0)
    return df

Сроки -

In [44]: data = np.random.randint(15, 25, (100000,4)).astype(float)
    ...: df1 = pd.DataFrame(data, columns=(('prev','open','close','volume')))
    ...: df2 = df1.copy()
    ...: 

In [45]: %timeit pandas_app1(df1)
    ...: %timeit numpy_app(df2)
    ...: 
100 loops, best of 3: 2.68 ms per loop
1000 loops, best of 3: 885 µs per loop
5
Divakar 26 Авг 2017 в 21:59