Python pandas:排除低于特定频率计数的行。

23

我有一个像这样的pandas DataFrame:

r vals    positions
1.2       1
1.8       2
2.3       1
1.8       1
2.1       3
2.0       3
1.9       1
...       ...

我想筛选出所有位置不至少出现20次的行。我见过类似这样的东西。

g=df.groupby('positions')
g.filter(lambda x: len(x) > 20)

但是这似乎不起作用,我不明白如何从中恢复原始数据框。提前感谢您的帮助。

4个回答

52

在您的有限数据集上,以下内容有效:

In [125]:
df.groupby('positions')['r vals'].filter(lambda x: len(x) >= 3)

Out[125]:
0    1.2
2    2.3
3    1.8
6    1.9
Name: r vals, dtype: float64

您可以将此筛选器的结果分配并将其与isin一起使用,以过滤您的原始数据框:

In [129]:
filtered = df.groupby('positions')['r vals'].filter(lambda x: len(x) >= 3)
df[df['r vals'].isin(filtered)]

Out[129]:
   r vals  positions
0     1.2          1
1     1.8          2
2     2.3          1
3     1.8          1
6     1.9          1

在你的情况下,你只需要将3更改为20

另一种方法是使用value_counts创建一个聚合系列,我们可以使用它来过滤您的df:

In [136]:
counts = df['positions'].value_counts()
counts

Out[136]:
1    4
3    2
2    1
dtype: int64

In [137]:
counts[counts > 3]

Out[137]:
1    4
dtype: int64

In [135]:
df[df['positions'].isin(counts[counts > 3].index)]

Out[135]:
   r vals  positions
0     1.2          1
2     2.3          1
3     1.8          1
6     1.9          1

编辑

如果你想在数据框上过滤 groupby 对象而不是一个 Series,那么可以直接在 groupby 对象上调用filter

In [139]:
filtered = df.groupby('positions').filter(lambda x: len(x) >= 3)
filtered

Out[139]:
   r vals  positions
0     1.2          1
2     2.3          1
3     1.8          1
6     1.9          1

6

我喜欢以下方法:

def filter_by_freq(df: pd.DataFrame, column: str, min_freq: int) -> pd.DataFrame:
    """Filters the DataFrame based on the value frequency in the specified column.

    :param df: DataFrame to be filtered.
    :param column: Column name that should be frequency filtered.
    :param min_freq: Minimal value frequency for the row to be accepted.
    :return: Frequency filtered DataFrame.
    """
    # Frequencies of each value in the column.
    freq = df[column].value_counts()
    # Select frequent values. Value is in the index.
    frequent_values = freq[freq >= min_freq].index
    # Return only rows with value frequency above threshold.
    return df[df[column].isin(frequent_values)]

与已接受答案中的lambda过滤方法相比,它要快得多 - Python开销被最小化。


我也更喜欢这个。在pandas中,建议避免逐行重复。 - B Furtado

1
如何选择所有 position 行并且值大于等于20?
mask = df['position'] >= 20
sel = df.ix[mask, :]

我觉得你误解了问题。我想要计算位置等于1的行数,然后如果计数小于20,则删除所有这些行。位置的值并不重要,只有包含相同值的行的计数。对于造成的困惑,我很抱歉。 - Wes Field

0
counts = df.position.value_counts(dropna=False)
df = df[df.positions.isin(counts[counts.isin(list(range(20,counts.max())))])]

这个解决方案更可取,因为它在计算时间效率上更高,而且对“长期价值”的回报更好:

CPU times: user 2.1 ms, sys: 485 µs, total: 2.58 ms Wall time: 20.3 ms 
VS 
CPU times: user 15.2 ms, sys: 11.7 ms, total: 26.9 ms Wall time: 156 m 

尽管这段代码可能回答了问题,但提供关于它如何以及/或为什么解决问题的额外上下文会提高答案的长期价值。 - mufazmi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接