我有一个熊猫DataFrame,我想从它删除行,其中字符串的长度在特定列大于2。

我希望能够做到这一点(根据这个答案):

df[(len(df['column name']) < 2)]

但是我得到了一个错误:

KeyError: u'no item named False'

我做错了什么?

(注意:我知道我可以使用df.dropna()来去除包含任何NaN的行,但我没有看到如何基于条件表达式删除行。)


当前回答

如果你想要根据列值上的一些复杂条件来删除数据帧的行,那么按照上面所示的方式来写会很复杂。我有以下简单的解决方案,它总是有效的。让我们假设你想要删除带有“header”的列,所以先在列表中获取该列。

text_data = df['name'].tolist()

现在对列表中的每个元素应用一些函数,并将其放入一个熊猫系列:

text_length = pd.Series([func(t) for t in text_data])

对我来说,我只是想知道代币的数量:

text_length = pd.Series([len(t.split()) for t in text_data])

现在在数据帧中添加一个以上系列的额外列:

df = df.assign(text_length = text_length .values)

现在我们可以在新列上应用条件,比如:

df = df[df.text_length  >  10]
def pass_filter(df, label, length, pass_type):

    text_data = df[label].tolist()

    text_length = pd.Series([len(t.split()) for t in text_data])

    df = df.assign(text_length = text_length .values)

    if pass_type == 'high':
        df = df[df.text_length  >  length]

    if pass_type == 'low':
        df = df[df.text_length  <  length]

    df = df.drop(columns=['text_length'])

    return df

其他回答

当你做len(df['列名'])时,你只得到一个数字,即DataFrame中的行数(即列本身的长度)。如果你想对列中的每个元素应用len,使用df['列名'].map(len)。所以尝试

df[df['column name'].map(len) < 2]

为了直接回答这个问题的原始标题“如何根据条件表达式从pandas DataFrame中删除行”(我理解这不一定是OP的问题,但可以帮助其他用户遇到这个问题),一种方法是使用drop方法:

df = df.drop(some labels)
df = df.drop(df[<some boolean condition>].index)

例子

删除列'score' < 50的所有行:

df = df.drop(df[df.score < 50].index)

就地版本(如评论中所指出)

df.drop(df[df.score < 50].index, inplace=True)

多个条件

(见布尔索引)

操作符为:|表示或,&表示与,~表示非。这些一定是 用圆括号分组。

删除列“score”< 50且> < 20的所有行

df = df.drop(df[(df.score < 50) & (df.score > 20)].index)

你可以将DataFrame分配给它自己的一个过滤版本:

df = df[df.score > 50]

这比drop更快:

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test[test.x < 0]
# 54.5 ms ± 2.02 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test.drop(test[test.x > 0].index, inplace=True)
# 201 ms ± 17.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test.drop(test[test.x > 0].index)
# 194 ms ± 7.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

在pandas中,你可以对你的边界执行str.len,并使用布尔结果来过滤它。

df[df['column name'].str.len().lt(2)]

如果你想要根据列值上的一些复杂条件来删除数据帧的行,那么按照上面所示的方式来写会很复杂。我有以下简单的解决方案,它总是有效的。让我们假设你想要删除带有“header”的列,所以先在列表中获取该列。

text_data = df['name'].tolist()

现在对列表中的每个元素应用一些函数,并将其放入一个熊猫系列:

text_length = pd.Series([func(t) for t in text_data])

对我来说,我只是想知道代币的数量:

text_length = pd.Series([len(t.split()) for t in text_data])

现在在数据帧中添加一个以上系列的额外列:

df = df.assign(text_length = text_length .values)

现在我们可以在新列上应用条件,比如:

df = df[df.text_length  >  10]
def pass_filter(df, label, length, pass_type):

    text_data = df[label].tolist()

    text_length = pd.Series([len(t.split()) for t in text_data])

    df = df.assign(text_length = text_length .values)

    if pass_type == 'high':
        df = df[df.text_length  >  length]

    if pass_type == 'low':
        df = df[df.text_length  <  length]

    df = df.drop(columns=['text_length'])

    return df