0

I wrote a short code to illustrate what's confusing me:

import numpy as np
import pandas as pd

a = [0.2,0.4]
f = np.linspace(0.0,4.0,5)

mindex = pd.MultiIndex.from_product([a,f], names=['a', 'f'])
df = pd.DataFrame(dtype=float, index=range(0,100), columns=mindex)

For the printed structure of the DataFrame, see the EDIT. Now, I want to know how to specifically use .loc to assign a value to a specific element. Apparently, the following:

print(df.loc[0, 0.2, 0.0])

gives the me error:

pandas.core.indexing.IndexingError: Too many indexers

but I don't understand why? The following two statements work as expected:

print(df.loc[0])
print(df.loc[0,0.2])

with print(df.loc[0,0.2]) for example outputting:

f
0.0   NaN
1.0   NaN
2.0   NaN
3.0   NaN
4.0   NaN
Name: 0, dtype: float64

But how to I get that final f=0.0 value out?

Also, my next idea would have been to use a tuple for the column index, but print(df.loc[0,[0.2,0.0]]) doesn't work either.


EDIT: Just to clarify the structure of my DataFrame.

print(df)

gives:

a  0.2                 0.4                
f  0.0 1.0 2.0 3.0 4.0 0.0 1.0 2.0 3.0 4.0
0  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4  NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
...
...

EDIT 2: Just to update after the comments, basically two suggestions were to use df.loc[0][0.2][0.0] or df[[(0.2,0.0)]].loc[0]. However, since I need this to assign values to specific elements, both of those seem to be discouraged by pandas (see http://pandas.pydata.org/pandas-docs/stable/indexing.html#returning-a-view-versus-a-copy).

In fact, df.loc[0][0.2][0.0] = 2 seems to work, but df[[(0.2,0.0)]].loc[0] = 2 doesn't (because it returns a copy of a slice instead of a view).

Marses
  • 967
  • 2
  • 13
  • 34
  • 1
    Does df.loc[0][0.2][0.0] work in your case? – greedy52 Feb 06 '17 at 13:50
  • But I wouldn't be able to assign with that since it would return copy-slices and now views though right? I.e `df[0][0.2][0.0] = ...` wouldn't work. Ok, nevermind, I just tried it and it works for assignment. That confuses me I thought it was discourage to make assignments that way. – Marses Feb 06 '17 at 13:51
  • It did edit the original df for me. pandas 0.18.1 – greedy52 Feb 06 '17 at 13:54
  • I see, it seems to work, I'm just surprised it does. According to http://pandas.pydata.org/pandas-docs/stable/indexing.html#returning-a-view-versus-a-copy this is discouraged right? – Marses Feb 06 '17 at 13:54
  • Sorry are you after `df[[(0.2,0.0)]].loc[0]`? – EdChum Feb 06 '17 at 13:59
  • That would be the same element as `df.loc[0][0.2][0.0]`, but like I said, I always thought pandas encourages using `loc` rather than sub-indexing because it can mess you up if it returns a copy instead of a view. – Marses Feb 06 '17 at 14:02
  • Looking at this post http://stackoverflow.com/questions/13842088/set-value-for-particular-cell-in-pandas-dataframe, perhaps the best way is to use `df.set_value` – Marses Feb 06 '17 at 14:05
  • If you really want to loc, as EdChum suggested, you can do `df.loc[0,0.2].loc[0]`. – greedy52 Feb 06 '17 at 14:05
  • @LimokPalantaemon that isn't the same as `df.loc[0][0.2][0.0]`, this is chained indexing, whilst `df[[(0.2,0.0)]].loc[0]` explicitly selects a column and then returns the row value matching that index label – EdChum Feb 06 '17 at 14:07
  • EdChum's thing doesn't work, while the suggestion you (Xin) posted allows assignment to values in the DataFrame, EdChum's version: `df[[(0.2,0.0)]].loc[0]` suffers from the problem I mentioned, it ends up returning a copy, and assignment won't work. Try `df[[(0.2,0.0)]].loc[0] = 2.0`, it doesn't work (for me). – Marses Feb 06 '17 at 14:08
  • 1
    Hmm, this does work `df.ix[0,[(0.2,0.0)]]` but it's going to be deprecated in 0.20.0, I think therefore you want `df.loc[0, (0.2,0)]` this does work for me – EdChum Feb 06 '17 at 14:19
  • 1
    For multiindices, use tuples to define your required location like `df.loc[0, (0.2, 0)]`. This is the recommended way. – pansen Feb 06 '17 at 14:25
  • Ah thanks, I see what it was now. Apparently it needs to be one of those `(,..)` tuples, and not a list like I was using. Thanks for the help. – Marses Feb 06 '17 at 14:36

0 Answers0