Pandas:过滤数据帧过于频繁或过于罕见的值

时间:2015-07-08 21:17:47

标签: python pandas filtering selection

在pandas数据框架上,我知道我可以在一列或多列上进行分组,然后过滤多于/少于给定数字的值。

但我想在数据帧的每一列上执行此操作。我想删除过于频繁的值(让我们说这种情况发生的次数少于5%)或过于频繁。例如,考虑一个包含以下列的数据框:city of origin, city of destination, distance, type of transport (air/car/foot), time of day, price-interval

import pandas as pd
import string
import numpy as np
vals = [(c, np.random.choice(list(string.lowercase), 100, replace=True)) for c in 
    'city of origin', 'city of destination', 'distance, type of transport (air/car/foot)', 'time of day, price-interval']
df = pd.DataFrame(dict(vals))
>> df.head()
    city of destination     city of origin  distance, type of transport (air/car/foot)  time of day, price-interval
0   f   p   a   n
1   k   b   a   f
2   q   s   n   j
3   h   c   g   u
4   w   d   m   h

如果这是一个大数据框,删除具有虚假项目的行是有意义的,例如,如果time of day = night仅发生3%的时间,或者foot传输模式很少, 等等。

我想从所有列(或列列表)中删除所有此类值。我的一个想法是在每列value_counts上执行transform并为每个value_counts添加一列;然后根据它们是高于还是低于阈值进行过滤。但我认为必须有更好的方法来实现这一目标吗?

4 个答案:

答案 0 :(得分:9)

此过程将遍历DataFrame的每一列,并消除给定类别小于给定阈值百分比的行,缩小每个循环上的DataFrame。

这个答案与@Ami Tavory提供的答案相似,但有一些细微差别:

  • 它会对值计数进行标准化,因此您只需使用百分位阈值。
  • 它每列只计算一次计数而不是两次。这样可以加快执行速度。

代码:

threshold = 0.03
for col in df:
    counts = df[col].value_counts(normalize=True)
    df = df.loc[df[col].isin(counts[counts > threshold].index), :]

代码时间:

df2 = pd.DataFrame(np.random.choice(list(string.lowercase), [1e6, 4], replace=True), 
                   columns=list('ABCD'))

%%timeit df=df2.copy()
threshold = 0.03
for col in df:
    counts = df[col].value_counts(normalize=True)
    df = df.loc[df[col].isin(counts[counts > threshold].index), :]

1 loops, best of 3: 485 ms per loop

%%timeit df=df2.copy()
m = 0.03 * len(df)
for c in df:
    df = df[df[c].isin(df[c].value_counts()[df[c].value_counts() > m].index)]

1 loops, best of 3: 688 ms per loop

答案 1 :(得分:2)

我是Python新手并使用Pandas。我在下面提出了以下解决方案。也许其他人可能有更好或更有效的方法。

假设您的DataFrame为data_df,您可以使用以下代码过滤掉所有不常见的值。请务必更新DFcol变量。 bin_freq是您新过滤的DataFrame。

DF_Filtered

答案 2 :(得分:0)

DataFrames支持clip_lower(threshold, axis=None)clip_upper(threshold, axis=None),它们会删除某个阈值以下或以上的所有值。

答案 3 :(得分:0)

我们也可以用一个标签替换所有稀有类别,比如“Rare”,如果这不会为预测增加价值,则稍后删除。

# function finds the labels that are more than certain percentage/threshold
def get_freq_labels(df, var, rare_perc):    
    df = df.copy()
    tmp = df.groupby(var)[var].count() / len(df)
    return tmp[tmp > rare_perc].index


vars_cat = [val for val in data.columns if data[val].dtype=='O']
for var in vars_cat:
    # find the frequent categories
    frequent_cat = get_freq_labels(data, var, 0.05)
    # replace rare categories by the string "Rare"
    data[var] = np.where(data[var].isin(
        frequent_cat ), data[var], 'Rare')