pandas series subset index 2:-2 doens't work

Viewed 147

I have this dataframe.

dd = pd.DataFrame({'t': np.array(['a','b', 'c', 'd', 'e', 'f', 'g']),
                   'o': np.array([1,2,3,4,5,6,7])})

I can't understand why this works:

print(dd.loc[2:4, 'o'].values)

[3, 4, 5]

and this doesn't :

print(dd.loc[2:-2, 'o'].values)

[]

while this does:

print(dd[['o']][2:-2].values)

[[3]
 [4]
 [5]]
2 Answers

Why dd.loc[2:4, 'o'].values works

.loc[] uses label slicing, where label is treated as non-monotonic and thus require exact matches. Endpoints are inclusive.

Therefore, in .loc[], 2:4 is interpreted as 2:4:1 (inclusive). So rows with index = 2, 3, and 4 are selected.

How dd.loc[2:-2, 'o'].values works

For the same reasoning above, 2:-2 in .loc[] won't translate into a length-aware 2:len(dd)-2:1 as expected. This is because 2 and -2 are regarded as nominal labels, hence the slicing expression WON'T be length-aware. It will be interpreted as 2:-2:1 (inclusive) instead of 2:len(dd)-2:1 (inclusive) .

However, since the first element 2 is already crossing the boundary of ending point (2 > -2), no element will be selected. This results in an empty dataframe.

dd[2:-2]

This is called slicing ranges.

Taken from the docs:

  • The most robust and consistent way of slicing ranges along arbitrary axes is described in the Selection by Position section detailing the .iloc method.
  • With Series, the syntax works exactly as with an ndarray
  • With DataFrame, slicing inside of [] slices the rows.

So it is just a convenient way of ndarray-style row selection with .iloc[], which knows 2:-2 means 2:len(dd)-2:1 (endpoint excluded). Therefore, rows with index=2,3,4 are selected.

dd[['o']][2:-2] also returns the same rows as dd[2:-2] because dd[['o']] is a dataframe with the same index.

If wnat use DataFrame.loc for label selection is possible it, but need indexing dd.index:

print(dd.loc[dd.index[2:-2], 'o'].values)
[3 4 5]

If use DataFrame.iloc for select by positions is necessary position of o column by Index.get_loc:

print(dd.iloc[2:-2, dd.columns.get_loc('o')].values)
[3 4 5]

Last selecting is more complicated, it seems one column DataFrame in seelcting working like selecting by Series:

print(dd[['o']][2:-2])
#working like
#print(dd[['o']].iloc[2:-2])
   o
2  3
3  4
4  5

print(dd['o'][2:-2])
#working like
#print(dd['o'].iloc[2:-2])
2    3
3    4
4    5
Name: o, dtype: int32
Related