Landon G
Landon G

Reputation: 839

Finding percentage change with Numpy

I'm writing a function to find the percentage change using Numpy and function calls. So far what I got is:

def change(a,b):
  answer = (np.subtract(a[b+1], a[b])) / a[b+1] * 100
  return answer

print(change(a,0))

"a" is the array I have made and b will be the index/numbers I am trying to calculate.

For example:

My Array is

[[1,2,3,5,7]
 [1,4,5,6,7]
 [5,8,9,10,32]
 [3,5,6,13,11]]

How would I calculate the percentage change between 1 to 2 (=0.5) or 1 to 4(=0.75) or 5,7 etc..

Note: I know how mathematically to get the change, I'm not sure how to do this in python/ numpy.

Upvotes: 5

Views: 43903

Answers (6)

Ashish Malhotra
Ashish Malhotra

Reputation: 1

  1. Combine all your arrays.

  2. Then make a data frame from them.

    df = pd.df(data=array you made)
    
  3. Use the pct_change() function on dataframe. It will calculate the % change for all rows in dataframe.

Upvotes: 0

Andi
Andi

Reputation: 4865

I suggest to simply shift the array. The computation basically becomes a one-liner.

import numpy as np

arr = np.array(
    [
        [1, 2, 3, 5, 7],
        [1, 4, 5, 6, 7],
        [5, 8, 9, 10, 32],
        [3, 5, 6, 13, 11],
    ]
)

# Percentage change from row to row
pct_chg_row = arr[1:] / arr[:-1] - 1

[[ 0.          1.          0.66666667  0.2         0.        ]
 [ 4.          1.          0.8         0.66666667  3.57142857]
 [-0.4        -0.375      -0.33333333  0.3        -0.65625   ]]

# Percentage change from column to column
pct_chg_col = arr[:, 1::] / arr[:, 0:-1] - 1

[[ 1.          0.5         0.66666667  0.4       ]
 [ 3.          0.25        0.2         0.16666667]
 [ 0.6         0.125       0.11111111  2.2       ]
 [ 0.66666667  0.2         1.16666667 -0.15384615]]

You could easily generalize the task, so that you are not limited to compute the change from one row/column to another, but be able to compute the change for n rows/columns.

n = 2
pct_chg_row_generalized = arr[n:] / arr[:-n] - 1

[[4.         3.         2.         1.         3.57142857]
 [2.         0.25       0.2        1.16666667 0.57142857]]

pct_chg_col_generalized = arr[:, n:] / arr[:, :-n] - 1

[[2.         1.5        1.33333333]
 [4.         0.5        0.4       ]
 [0.8        0.25       2.55555556]
 [1.         1.6        0.83333333]]

If the output array must have the same shape as the input array, you need to make sure to insert the appropriate number of np.nan.

out_row = np.full_like(arr, np.nan, dtype=float)
out_row[n:] = arr[n:] / arr[:-n] - 1

[[       nan        nan        nan        nan        nan]
 [       nan        nan        nan        nan        nan]
 [4.         3.         2.         1.         3.57142857]
 [2.         0.25       0.2        1.16666667 0.57142857]]

out_col = np.full_like(arr, np.nan, dtype=float)
out_col[:, n:] = arr[:, n:] / arr[:, :-n] - 1

[[       nan        nan 2.         1.5        1.33333333]
 [       nan        nan 4.         0.5        0.4       ]
 [       nan        nan 0.8        0.25       2.55555556]
 [       nan        nan 1.         1.6        0.83333333]]

Finally, a small function for the general 2D case might look like this:

def np_pct_chg(arr: np.ndarray, n: int = 1, axis: int = 0) -> np.ndarray:
    out = np.full_like(arr, np.nan, dtype=float)

    if axis == 0:
        out[n:] = arr[n:] / arr[:-n] - 1
    elif axis == 1:
        out[:, n:] = arr[:, n:] / arr[:, :-n] - 1

    return out

Upvotes: 2

Ioannis Mourginakis
Ioannis Mourginakis

Reputation: 39

The accepted answer is close but incorrect if you're trying to take % difference from left to right. You should get the following percent difference:

1,2,3,5,7 --> 100%, 50%, 66.66%, 40%

check for yourself: https://www.calculatorsoup.com/calculators/algebra/percent-change-calculator.php

Going by what Josmoor98 said, you can use np.diff(a) / a[:,:-1] * 100 to get the percent difference from left to right, which will give you the correct answer.

array([[100.        ,  50.        ,  66.66666667,  40.        ],
       [300.        ,  25.        ,  20.        ,  16.66666667],
       [ 60.        ,  12.5       ,  11.11111111, 220.        ],
       [ 66.66666667,  20.        , 116.66666667, -15.38461538]])

Upvotes: 1

Prayson W. Daniel
Prayson W. Daniel

Reputation: 15578

I know you have asked this question with Numpy in mind and got answers above:

import numpy as np
np.diff(a) / a[:,1:]

I attempt to solve this with Pandas. For those who would have the same question but using Pandas instead of Numpy

import pandas as pd 
data = [[1,2,3,4,5],
        [1,4,5,6,7],
        [5,8,9,10,32],
        [3,5,6,13,11]]

df = pd.DataFrame(data)
df_change = df.rolling(1,axis=1).sum().pct_change(axis=1)
print(df_change)

Upvotes: 4

Rudolf Morkovskyi
Rudolf Morkovskyi

Reputation: 869

import numpy as np
a = np.array([[1,2,3,5,7],
              [1,4,5,6,7],
              [5,8,9,10,32],
              [3,5,6,13,11]])    
np.array([(i[:-1]/i[1:]) for i in a])

Upvotes: 0

sacuL
sacuL

Reputation: 51365

If I understand correctly, that you're trying to find percent change in each row, then you can do:

>>> np.diff(a) / a[:,1:] * 100

Which gives you:

array([[ 50.        ,  33.33333333,  40.        ,  28.57142857],
       [ 75.        ,  20.        ,  16.66666667,  14.28571429],
       [ 37.5       ,  11.11111111,  10.        ,  68.75      ],
       [ 40.        ,  16.66666667,  53.84615385, -18.18181818]])

Upvotes: 15

Related Questions