Python Pandas: Inconsistent behaviour of boolean indexing on a Series using the len() method
<p>I have a Series of strings and I need to apply boolean indexing using <code>len()</code> on it.</p>

<p>In one case it works, in another case it does not:</p>

<p>The working case is a <code>groupby</code> on a dataframe, followed by a <code>unique()</code> on the resulting Series and a <code>apply(str)</code> to change the resulting <code>numpy.ndarray</code> entries into strings:</p>

<pre><code>import pandas as pd
df = pd.DataFrame({'A':['a','a','a','a','b','b','b','b'],'B':[1,2,2,3,4,5,4,4]})
dg = df.groupby('A')['B'].unique().apply(str)
db = dg[len(dg) &gt; 2]
</code></pre>

<p>This just works fine and yields the desired result:</p>

<pre><code>&gt;&gt;db
Out[119]: '[1 2 3]'
</code></pre>

<p>The following however throws <code>KeyError: True</code>:</p>

<pre><code>ss = pd.Series(['a','b','cc','dd','eeee','ff','ggg'])
ls = ss[len(ss) &gt; 2]
</code></pre>

<p>Both objects <code>dg</code> and <code>ss</code> are just Series of Strings:</p>

<pre><code>&gt;&gt;type(dg)
Out[113]: pandas.core.series.Series

&gt;&gt;type(ss)
Out[114]: pandas.core.series.Series

&gt;&gt;type(dg['a'])
Out[115]: str

&gt;&gt;type(ss[0])
Out[116]: str
</code></pre>

<p>I'm following the syntax as described in the docs: <a href="http://pandas.pydata.org/pandas-docs/stable/indexing.html#boolean-indexing" rel="nofollow">http://pandas.pydata.org/pandas-docs/stable/indexing.html#boolean-indexing</a></p>

<p>I can see a potential conflict because <code>len(ss)</code> on its own returns the length of the Series itself and now that exact command is used for boolean indexing <code>ss[len(ss) &gt; 2]</code>, but then I'd expect neither of the two examples to work.</p>

<p>Right now this behaviour seems inconsistent, unless I'm missing something obvious.</p>

<p>I think you need <a href="http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.str.len.html" rel="nofollow"><code>str.len</code></a>, because need length of each value of <code>Series</code>:</p>

<pre><code>ss = pd.Series(['a','b','cc','dd','eeee','ff','ggg'])

print (ss.str.len())
0    1
1    1
2    2
3    2
4    4
5    2
6    3
dtype: int64

print (ss.str.len() &gt; 2)
0    False
1    False
2    False
3    False
4     True
5    False
6     True
dtype: bool

ls = ss[ss.str.len() &gt; 2]
print (ls)
4    eeee
6     ggg
dtype: object
</code></pre>

<p>If use <code>len</code>, get length of <code>Series</code>:</p>

<pre><code>print (len(ss))
7
</code></pre>

<p>Another solution is <a href="http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.apply.html" rel="nofollow"><code>apply</code></a> <code>len</code>:</p>

<pre><code>ss = pd.Series(['a','b','cc','dd','eeee','ff','ggg'])
ls = ss[ss.apply(len) &gt; 2]
print (ls)
4    eeee
6     ggg
dtype: object
</code></pre>

<p>First script is wrong, you need <a href="http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.apply.html" rel="nofollow"><code>apply</code></a> <code>len</code> also:</p>

<pre><code>df = pd.DataFrame({'A':['a','a','a','a','b','b','b','b'],'B':[1,2,2,2,4,5,4,6]})
dg = df.groupby('A')['B'].unique()
print (dg)
A
a       [1, 2]
b    [4, 5, 6]
Name: B, dtype: object

db = dg[dg.apply(len) &gt; 2]
print (db)
A
b    [4, 5, 6]
Name: B, dtype: object
</code></pre>

<p>If cast list to <code>str</code>, you get another <code>len</code> (<code>length</code> of data + length of <code>[]</code> + length of whitespaces):</p>

<pre><code>dg = df.groupby('A')['B'].unique().apply(str)
print (dg)
A
a      [1 2]
b    [4 5 6]
Name: B, dtype: object

print (dg.apply(len))
A
a    5
b    7
Name: B, dtype: int64
</code></pre>

python python-2.7 pandas