# Create new DataFrame containing mean information

I have a dataframe with the columns "Action", "Filt" and "Val" which measure the resulting error of filtering an action. I want to calculate the mean of the error for each "Action" and "Filt". Currently, I do this by iterating through each combination of "Action" and "Filt". However, I'm afraid the slicing is taking up more time than I would like.

import pandas as pd

in_dat = [
("run", "raw", 1),
("run", "deep", 1),
("jump", "raw", 2),
("jump", "deep", 2),
("run", "raw", 2),
("run", "deep", 2),
("jump", "raw", 3),
("jump", "deep", 3)

]

all_err = pd.DataFrame(in_dat, columns=("action", "filt", "val"))

mean_vals = []

for act in tuple(all_err.action.unique()):
for filt in tuple(all_err.filt.unique()):
mean_val = all_err[(all_err.action == act) & (all_err.filt == filt)].val.mean()
mean_vals.append((act, filt, mean_val))

mean_err = pd.DataFrame(mean_vals, columns=("Action", "Filt", "Error"))


This gives the result of mean_err being:

  Action  Filt  Error
0    run   raw    1.5
1    run  deep    1.5
2   jump   raw    2.5
3   jump  deep    2.5


What's a faster way to do this with Pandas and getting a similar result?

• You didn't leave any data, so this is untested, butall_err.groupby(['action', 'filt']).val.mean() is worth a try. – Stephen Rauch Jun 19 '17 at 13:17
• @StephenRauch that's correct and I've updated my question to include test data if you want to add an answer – Seanny123 Jun 19 '17 at 15:31
• @StephenRauch if you don't have time to post your own answer, that's cool too. – Seanny123 Jun 20 '17 at 0:44

### pandas is deep

The pandas toolkit is very deep and can take a while to grok some of the basics. In the case of your code, you are replicating the functionality in pandas.DataFrame.groupby(). groupby gathers all of the elements together with matching values in the fields indicated and then allows those elements to be worked on as a group. In the case of:

for act in tuple(all_err.action.unique()):
for filt in tuple(all_err.filt.unique()):


This code is referencing all values of the action and filt columns into two variables. Then:

mean_val = all_err[(all_err.action == act) & (all_err.filt == filt)].val.mean()
mean_vals.append((act, filt, mean_val))


These lines perform a mean on the val column for each row that matches in the two grouped columns, and stores those results into a list. Pandas has a shortcut for these sorts of operations called groupby. The above four lines, plus the list initialization, can be equivalently written as:

all_err.groupby(['action', 'filt']).val.mean()


### How?

Starting with:

all_err.groupby(['action', 'filt'])


produces a pandas.core.groupby.DataFrameGroupBy. This object instance understands how to iterate over the dataframe a group at a time, allowing access to these groups in various ways. So then,

all_err.groupby(['action', 'filt']).val


selects the val column to work against, and finally,

all_err.groupby(['action', 'filt']).val.mean()


asks for the mean value of that column.

### Results:

mean_err = all_err.groupby(['action', 'filt']).val.mean()
print(mean_err)

Action  Filt  Error
0    run   raw    1.5
1    run  deep    1.5
2   jump   raw    2.5
3   jump  deep    2.5