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

vpk*_*vpk 11 python filtering selection pandas

在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
Run Code Online (Sandbox Code Playgroud)

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

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

Ale*_*der 10

此过程将遍历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), :]
Run Code Online (Sandbox Code Playgroud)

代码时间:

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
Run Code Online (Sandbox Code Playgroud)