I have a dataframe with ID’s of clients and their expenses for 2014-2018. What I want is to have the mean of the expenses per ID but only the years before a certain date can be taken into account when calculating the mean value (so column ‘Date’ dictates which columns can be taken into account for the mean).
Example: for index 0 (ID: 12), the date states ‘2016-03-08’, then the mean should be taken from the columns ‘y_2014’ and ‘y_2015’, so then for this index, the mean is 111.0. If the date is too early (e.g. somewhere in 2014 or earlier in this case), then NaN should be returned (see index 6 and 9).
Desired output:
JavaScript
x
12
12
1
y_2014 y_2015 y_2016 y_2017 y_2018 Date ID mean
2
0 100.0 122.0 324 632 NaN 2016-03-08 12 111.0
3
1 120.0 159.0 54 452 541.0 2015-04-09 96 120.0
4
2 NaN 164.0 687 165 245.0 2016-02-15 20 164.0
5
3 180.0 421.0 512 184 953.0 2018-05-01 73 324.25
6
4 110.0 654.0 913 173 103.0 2017-08-04 84 559.0
7
5 130.0 NaN 754 124 207.0 2016-07-03 26 130.0
8
6 170.0 256.0 843 97 806.0 2013-02-04 87 NaN
9
7 140.0 754.0 95 101 541.0 2016-06-08 64 447
10
8 80.0 985.0 184 84 90.0 2019-03-05 11 284.6
11
9 96.0 65.0 127 130 421.0 2014-05-14 34 NaN
12
The code below is what I tried.
Tried code:
JavaScript
1
27
27
1
import pandas as pd•
2
import numpy as np•••
3
4
df = pd.DataFrame({"ID": [12,96,20,73,84,26,87,64,11,34],•
5
"y_2014": [100,120,np.nan,180,110,130,170,140,80,96],•
6
"y_2015": [122,159,164,421,654,np.nan,256,754,985,65],•
7
"y_2016": [324,54,687,512,913,754,843,95,184,127],•
8
"y_2017": [632,452,165,184,173,124,97,101,84,130],•
9
"y_2018": [np.nan,541,245,953,103,207,806,541,90,421],•
10
"Date": ['2016-03-08', '2015-04-09', '2016-02-15', '2018-05-01', '2017-08-04',• '2016-07-03', '2013-02-04', '2016-06-08', '2019-03-05', '2014-05-14']})••
11
12
print(df)••
13
14
# the years from columns•
15
data = df.filter(like='y_')•
16
data_years = data.columns.str.extract('(d+)')[0].astype(int)••
17
18
# the years from Date•
19
years = pd.to_datetime(df.Date).dt.year.values
20
21
••df['mean'] = data.where(data_years<years[:,None]).mean(1)•
22
print(df)
23
24
-> ValueError: Lengths must match to compare
25
26
27
Advertisement
Answer
Solved: one possible answer to my own question
JavaScript
1
30
30
1
import pandas as pd•
2
import numpy as np••
3
4
df = pd.DataFrame({"ID": [12,96,20,73,84,26,87,64,11,34],•
5
"y_2014": [100,120,np.nan,180,110,130,170,140,80,96],•
6
"y_2015": [122,159,164,421,654,np.nan,256,754,985,65],•
7
"y_2016": [324,54,687,512,913,754,843,95,184,127],•
8
"y_2017": [632,452,165,184,173,124,97,101,84,130],•
9
"y_2018": [np.nan,541,245,953,103,207,806,541,90,421],•
10
"Date": ['2016-03-08', '2015-04-09', '2016-02-15', '2018-05-01', '2017-08-04',•
11
'2016-07-03', '2013-02-04', '2016-06-08', '2019-03-05', '2014-05-14']})
12
13
#Subset from original df to calculate mean
14
subset = df.loc[:,['y_2014', 'y_2015', 'y_2016', 'y_2017', 'y_2018']]•
15
16
#an expense value is only available for the calculation of the mean when that year has passed, therefore 2015-01-01 is chosen for the 'y_2014' column in the subset etc. to check with the 'Date'-column
17
subset.columns = ['2015-01-01', '2016-01-01', '2017-01-01', '2018-01-01', '2019-01-01']••
18
s = subset.columns[0:].values < df.Date.values[:,None]•
19
t = s.astype(float)
20
t[t == 0] = np.nan•
21
22
df['mean'] = (subset.iloc[:,0:]*t).mean(1)••
23
print(df)
24
25
#Additionally: (gives the sum of expenses before a certain date in the 'Date'-column
26
df['sum'] = (subset.iloc[:,0:]*t).sum(1)••
27
print(df)
28
29
30