cómo calcular si la statement para el reequilibrio de valor relativo / error: “El valor de verdad de una serie es ambiguo”

Abajo encontrará el código que escribí para calcular un cambio relativo en el valor de df.a y df.b mientras que df es un dataframe. Lo que debe calcularse es básicamente df["c"] = df.a/df.a.iloc[df.d].values . df.d se establece igual a df.t si df.a/df.a.iloc[df.d].values es mayor o menor que df.b/df.b.iloc[df.d].values * (1+ tolerance)

El problema es que el código trae actualmente el siguiente código de error: ValueError: ('The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().', u'occurred at index 2011-01-01 00:00:00') y no sé por qué …

 import pandas as pd import numpy as np import datetime randn = np.random.randn rng = pd.date_range('1/1/2011', periods=10, freq='D') df = pd.DataFrame({'a': [1.1, 1.2, 2.3, 1.4, 1.5, 1.8, 0.7, 1.8, 1.9, 2.0], 'b': [1.1, 1.5, 1.3, 1.6, 1.5, 1.1, 1.5, 1.7, 2.1, 2.1],'c':[None] * 10},index=rng) df["d"]= [0,0,0,0,0,0,0,0,0,0] df["t"]= np.arange(len(df)) tolerance = 0.3 def set_t(x): if df.a/df.a.iloc[df.d].values  df.b/df.b.iloc[df.d].values * (1+tolerance): return df.iloc[df.index.get_loc(x.name) - 1]['d'] == df.t #The conditions in part one are exactly the same as in part 2, only first it says smaller than, and in the second part is bigger than df.b/df.b.iloc[df.d].values * (1+tolerance) df['d'] = df.apply(set_t, axis =1) #df["d"]= [0,0,0,3,3,3,6,7,7,7] this should be the coutcome for d df["c"] = df.a/df.a.iloc[df.d].values 

La aplicación de (df.a/df.a.iloc[df.d].values).all() < (df.b/df.b.iloc[df.d].values).all() o .any() no conduce al resultado deseado, ya que solo verifica cuando los datos establecidos actualmente son TRUE o FALSE, pero no establece el nuevo valor.

El resultado deseado se ve así:

  abcdt 2011-01-01 1.1 1.1 1.000000 0 0 2011-01-02 1.2 1.5 1.090909 0 1 2011-01-03 2.3 1.3 2.090909 0 2 2011-01-04 1.4 1.6 1.000000 3 3 2011-01-05 1.5 1.5 1.071429 3 4 2011-01-06 1.8 1.1 1.285714 3 5 2011-01-07 0.7 1.5 1.000000 6 6 2011-01-08 1.8 1.7 1.000000 7 7 2011-01-09 1.9 2.1 1.055556 7 8 2011-01-10 2.0 2.1 1.111111 7 9 

¿Alguna idea de cómo resolver eso?

Esta no es una solución al 100%, pero al menos debería llevarlo por un camino mejor y solucionar un problema principal. El problema central que estoy viendo aquí desde el lado de la syntax es que estás tratando de mezclar código vectorizado y no vectorizado. En su lugar, podrías hacer algo más como esto:

 >>> df['d1'] = df.a/df.a.iloc[df.d].values > df.b/df.b.iloc[df.d].values * (1+tolerance) >>> df['d2'] = df.a/df.a.iloc[df.d].values * (1+tolerance) < df.b/df.b.iloc[df.d].values >>> df['d'] = df['d1'] | df['d2'] >>> df abcdt d1 d2 2011-01-01 1.1 1.1 None False 0 False False 2011-01-02 1.2 1.5 None False 1 False False 2011-01-03 2.3 1.3 None True 2 True False 2011-01-04 1.4 1.6 None False 3 False False 2011-01-05 1.5 1.5 None False 4 False False 2011-01-06 1.8 1.1 None True 5 True False 2011-01-07 0.7 1.5 None True 6 False True 2011-01-08 1.8 1.7 None False 7 False False 2011-01-09 1.9 2.1 None False 8 False False 2011-01-10 2.0 2.1 None False 9 False False 

Esa no es exactamente la respuesta que desea, pero con suerte le muestra lo que está pasando con el código y cómo puede solucionarlo para obtener lo que desea (es decir, no necesita o quiere estar usando una función y aplicándola aquí, solo utilizar el código vectorizado pandas estándar).

Si puede hacer que eso funcione, la forma más limpia de hacerlo sería con np.where (dos de ellos secuencialmente o nesteds).

Ok, obtengo el resultado que desea, pero aún así es demasiado complicado e ineficiente. Me interesaría ver una solución superior:

 import pandas as pd import numpy as np import datetime randn = np.random.randn rng = pd.date_range('1/1/2011', periods=10, freq='D') df = pd.DataFrame({'a': [1.1, 1.2, 2.3, 1.4, 1.5, 1.8, 0.7, 1.8, 1.9, 2.0], 'b': [1.1, 1.5, 1.3, 1.6, 1.5, 1.1, 1.5, 1.7, 2.1, 2.1],'c':[None] * 10},index=rng) df["d"]= [0,0,0,0,0,0,0,0,0,0] df["t"]= np.arange(len(df)) tolerance = 0.3 df['d1'] = df.a/df.a.iloc[df.d].values > df.b/df.b.iloc[df.d].values * (1+tolerance) df['d2'] = df.a/df.a.iloc[df.d].values * (1+tolerance) < df.b/df.b.iloc[df.d].values df['e'] = df.d1*df.t df['f'] = df.d2*df.t df['g'] = df.e +df.f df.ix[df.g > df.g.shift(1),"h"] = df.g * 1; df df.h = df.h + 1 df.h = df.h.shift(1) df['h'][0] = 0 df.h.fillna(method='ffill',inplace=True) df["d"] = df.h df["c"] = df.a/df.a.iloc[df.d].values 

y ese es el resultado:

  abcdt d1 d2 efgh 2011-01-01 1.1 1.1 1.000000 0 0 False False 0 0 0 0 2011-01-02 1.2 1.5 1.090909 0 1 False False 0 0 0 0 2011-01-03 2.3 1.3 2.090909 0 2 True False 2 0 2 0 2011-01-04 1.4 1.6 1.000000 3 3 False False 0 0 0 3 2011-01-05 1.5 1.5 1.071429 3 4 False False 0 0 0 3 2011-01-06 1.8 1.1 1.285714 3 5 True False 5 0 5 3 2011-01-07 0.7 1.5 1.000000 6 6 False True 0 6 6 6 2011-01-08 1.8 1.7 1.000000 7 7 False False 0 0 0 7 2011-01-09 1.9 2.1 1.055556 7 8 False False 0 0 0 7 2011-01-10 2.0 2.1 1.111111 7 9 False False 0 0 0 7 

desde aquí puede eliminar fácilmente filas con, por ejemplo, del df['g']