10

I would like to apply a function on a multiindex dataframe (basically groupby describe dataframe) without using for loop to traverse level 0 index.

Function I'd like to apply:

def CI(x):
    import math
    sigma = x["std"]
    n = x["count"]
    return 1.96 * sigma / math.sqrt(n)

Sample of my dataframe:

df = df.iloc[47:52, [3,4,-1]]

               a          b                    id
47          0.218182   0.000000  0d1974107c6731989c762e96def73568
48          0.000000   0.000000  0d1974107c6731989c762e96def73568
49          0.218182   0.130909  0d1974107c6731989c762e96def73568
50          0.000000   0.000000  0fd4f3b4adf43682f08e693a905b7432
51          0.000000   0.000000  0fd4f3b4adf43682f08e693a905b7432

And I replace zeros with nan:

df = df.replace(float(0), np.nan)

Groupy on id and describe and I get multiindex:

df_group = df.groupby("id").describe()

Current solution I don't like and think could be improved:

l_df = []
for column in df_group.columns.levels[0]:
    df = pd.DataFrame({"CI" : df_group[column].apply(CI, axis = 1)})
    l_df.append(df)
CI = pd.concat(l_df, axis = 1)
CI.columns = df_group.columns.levels[0]

so I get something like:

                                    a       b
id
06f32e6e45da385834dac983256d59f3    nan     nan
0d1974107c6731989c762e96def73568    0.005   0.225
0fd4f3b4adf43682f08e693a905b7432    0.008   nan
11e0057cdc8b8e1b1cdabfa8a092ea5f    0.018   0.582
120549af6977623bd01d77135a91a523    0.008   0.204

So again, if I have top level columns from a to z, and each contains std and count column, how can I apply my function to each of these columns at the same time?

  • Thank you John for reply. It's shorter solution, but in principle it's just rephrasing my solution. I wanted to know if there is a method within pandas that could operate on multiindex level, without for loops or list comprehensions. – LostBoardOnTaurangaBeach Sep 08 '17 at 06:42

1 Answers1

8

Using groupby on level with axis=1, let's you iterate and apply over the first level columns.

In [104]: (df.groupby("id").describe()
             .groupby(level=0, axis=1)
             .apply(lambda x: x[x.name].apply(CI, axis=1)))
Out[104]:
                                    a   b
id
0d1974107c6731989c762e96def73568  0.0 NaN
0fd4f3b4adf43682f08e693a905b7432  NaN NaN

Infact, you don't need CI, if you were to

In [105]: (df.groupby("id").describe()
             .groupby(level=0, axis=1).apply(lambda x: x[x.name]
             .apply(lambda x: 1.96*x['std']/np.sqrt(x['count']), axis=1)))
Out[105]:
                                    a   b
id
0d1974107c6731989c762e96def73568  0.0 NaN
0fd4f3b4adf43682f08e693a905b7432  NaN NaN

Sample df

In [106]: df
Out[106]:
           a         b                                id
47  0.218182       NaN  0d1974107c6731989c762e96def73568
48       NaN       NaN  0d1974107c6731989c762e96def73568
49  0.218182  0.130909  0d1974107c6731989c762e96def73568
50       NaN       NaN  0fd4f3b4adf43682f08e693a905b7432
51       NaN       NaN  0fd4f3b4adf43682f08e693a905b7432
Zero
  • 74,117
  • 18
  • 147
  • 154
  • 1
    Thank you for answer. May I ask how are you printing results to stackoverflow, because when I tried to copy from jupyter notebook formatting was messed up and I had to do quite a few corrections by hand. – LostBoardOnTaurangaBeach Sep 08 '17 at 11:00
  • 1
    Read https://meta.stackexchange.com/questions/216464/how-to-insert-code-properly-on-stack-overflow and https://stackoverflow.com/questions/20109391/how-to-make-good-reproducible-pandas-examples – Zero Sep 08 '17 at 11:02