Tengo un DataFrame y quiero obtener divisiones de pares de columnas como las siguientes:
df = pd.DataFrame({ 'a1': np.random.randint(1, 1000, 1000), 'a2': np.random.randint(1, 1000, 1000), 'b1': np.random.randint(1, 1000, 1000), 'b2': np.random.randint(1, 1000, 1000), 'c1': np.random.randint(1, 1000, 1000), 'c2': np.random.randint(1, 1000, 1000), }) df['a'] = df['a2'] / df['a1'] df['b'] = df['b2'] / df['b1'] df['c'] = df['c2'] / df['c1']
Quiero combinar las últimas tres líneas en una como:
df[['a', 'b', 'c']] = df[['a2', 'b2', 'c2']] / df[['a1', 'b1', 'c1']]
pero solo recibo un error de ValueError: Columns must be same length as key
. Si simplemente print(df[['a2', 'b2', 'c2']] / df[['a1', 'b1', 'c1']])
, solo obtendré un DataFrame con NaN
s de forma (1000, 6).
==== Editar
Ahora sé por qué mi código original de una sola línea no funciona. En realidad, las operaciones aritméticas de dos DataFrames se realizarán entre las columnas con las mismas etiquetas, mientras que aquellas columnas sin la misma etiqueta en otro DataFrame generarán NaN. El DataFrame resultante tendrá la unión() de las columnas de los dos DataFrames operativos. Es por eso que mi solución original dará un ValueError
y el div generará NaN
s.
El siguiente ejemplo será útil para explicar:
df1 = pd.DataFrame(data={'A':[1,2], 'B':[3,4], 'C':[5,6], 'D':[8,9]}) df2 = pd.DataFrame(data={'A':[11,12], 'B':[13,14], 'C':[15,16], 'D':[18,19]}) df1[['A', 'B']] / df2[['A', 'B']] Out[130]: AB 0 0.090909 0.230769 1 0.166667 0.285714 df1[['A', 'B']] / df2[['C', 'D']] Out[131]: ABCD 0 NaN NaN NaN NaN 1 NaN NaN NaN NaN df1[['A', 'B']] + df2[['A', 'C']] Out[132]: ABC 0 12 NaN NaN 1 14 NaN NaN
Puedes usar:
df[['a', 'b', 'c']] = df[['a2', 'b2', 'c2']].values / df[['a1', 'b1', 'c1']].values
OUTPUT
a1 a2 b1 b2 c1 c2 abc 0 864 214 551 761 174 111 0.247685 1.381125 0.637931 1 820 971 379 79 190 587 1.184146 0.208443 3.089474 2 305 154 519 378 567 186 0.504918 0.728324 0.328042 3 51 505 303 417 959 326 9.901961 1.376238 0.339937 4 84 531 625 899 248 905 6.321429 1.438400 3.649194 .. ... ... ... ... ... ... ... ... ... 995 302 695 790 777 896 975 2.301325 0.983544 1.088170 996 24 308 462 316 388 784 12.833333 0.683983 2.020619 997 135 286 359 752 282 283 2.118519 2.094708 1.003546 998 695 45 832 936 811 404 0.064748 1.125000 0.498150 999 809 454 971 335 366 884 0.561187 0.345005 2.415301
Podría hacer lo siguiente como una solución simple:
df['a'], df['b'], df['c'] = (df['a2'] / df['a1'], df['b2'] / df['b1'], df['c2'] / df['c1'])
Aunque creo que usar el método de assign
haría que su código fuera mucho más legible:
df.assign(a=lambda x: x['a2'] / x['a1'], b=lambda x: x['b2'] / x['b1'], c=lambda x: x['c2'] / x['c1'])
MultiIndex es útil aquí, ya que Pandas siempre se alinea primero en el índice (las columnas también son un índice) antes de cualquier cálculo.
Usando los datos de muestra a continuación:
df = pd.DataFrame({'a_1':range(2,10,2), 'a_2': range(4, 20, 4), 'b_1': range(3, 15,3), 'b_2': range(6,30,6), 'c_1': range(5, 25, 5), 'c_2': range(10, 50, 10)}) df a_1 a_2 b_1 b_2 c_1 c_2 0 2 4 3 6 5 10 1 4 8 6 12 10 20 2 6 12 9 18 15 30 3 8 16 12 24 20 40
dividir las columnas en un MultiIndex:
temp = df.copy() temp.columns = temp.columns.str.split('_', expand = True).swaplevel() temp 1 2 1 2 1 2 aabbcc 0 2 4 3 6 5 10 1 4 8 6 12 10 20 2 6 12 9 18 15 30 3 8 16 12 24 20 40
En este formulario, simplemente puede seleccionar 2
dividido por 1
:
df['a','b','c']] = temp['2'] / temp['1']
Esto da los mismos valores que:
df[['a_2', 'b_2', 'c_2']].values / df[['a_1', 'b_1', 'c_1']].values
Sin embargo, imagine que tiene muchas columnas, no necesita preocuparse por el emparejamiento, ya que el formulario MultiIndex se encarga de eso, con Pandas haciendo la alineación antes del cálculo.
Numpy va a ser más rápido: la respuesta de @MuhammadHassan encaja muy bien; esto es solo para mostrar cómo MultiIndex tiene su lugar y sus usos en las circunstancias adecuadas.