【问题标题】:Filling a default value if count is less than threshold in pandas如果计数小于熊猫中的阈值,则填充默认值
【发布时间】:2018-08-16 20:31:57
【问题描述】:

我有一个数据框:

import pandas as pd
import numpy as np

df = pd.DataFrame()
df['name'] = ['john','sam','john','john','dean','dean','maggi',
              'ram','maggi','ana','sam','sam']
df['pt'] = [23, 32, 45, 65, 65, 45, 32, 45, 90, 10, 32, 22]

如果名称仅在名称列中出现一次,我想将名称替换为其他名称。

所以我的输出是:

     name  pt
0    john  23
1     sam  32
2    john  45
3    john  65
4    dean  65
5    dean  45
6   maggi  32
7   other  45
8   maggi  90
9   other  10
10    sam  32
11    sam  22

在我的原始数据中,值有数百个,因此使用 df.replacemap 不可行。

np.where 仅适用于二进制列。所以我被困在这里了。

谢谢,

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    使用numpy.whereduplicated 选择所有唯一行,或使用transformsize 获得更通用的解决方案,并指定阈值:

    df['name'] = np.where(~df['name'].duplicated(keep=False), 'other', df['name'])
    

    或者:

    df['name'] = np.where(df.groupby('name')['name'].transform('size') == 1, 'other', df['name'])
    print (df)
         name  pt
    0    john  23
    1     sam  32
    2    john  45
    3    john  65
    4    dean  65
    5    dean  45
    6   maggi  32
    7   other  45
    8   maggi  90
    9   other  10
    10    sam  32
    11    sam  22
    

    另一个解决方案,感谢@Jon Clements:

    df.name.where(df.groupby('name')['name'].transform('size') > 1, 'other', inplace=True)
    

    【讨论】:

    • 谢谢。有效。虽然我实际使用的阈值是 5,但将无法使用第一个。
    • @AkshayNevrekar - 是的,然后第二个解决方案需要transform
    • @jezrael 我有df.name.where(df.groupby('name')['name'].transform('size') > 1, 'other', inplace=True) - 不确定您是否想将其添加为可能的选项 - 不确定它的性能如何
    • @JonClements - 我将它添加到答案中,这个难题,这取决于数据。
    • 嗯...另一个随机的想法:df.name.apply(lambda name, counts=Counter(df.name): name if counts[name] > 1 else 'other')
    【解决方案2】:

    这是使用pd.Series.value_countspd.DataFrame.loc 的矢量化解决方案:

    s = df['name'].value_counts(sort=False)
    df.loc[df['name'].isin(s[s == 1].index), 'name'] = 'other'
    
    print(df)
    
         name  pt
    0    john  23
    1     sam  32
    2    john  45
    3    john  65
    4    dean  65
    5    dean  45
    6   maggi  32
    7   other  45
    8   maggi  90
    9   other  10
    10    sam  32
    11    sam  22
    

    性能基准测试

    如果您有很多重复的名称,为了提高性能,您可以使用Categorical Data。以下是 Python 3.6、Pandas 0.19 的时间安排。

    def jpp(df):
        s = df['name'].value_counts(sort=False)
        df.loc[df['name'].isin(s[s == 1].index), 'name'] = 'other'
        return df
    
    def jez(df):
        df['name'] = np.where(df.groupby('name')['name'].transform('size') == 1, 'other', df['name'])
        return df
    
    def jon(df):
        df['name'] = df['name'].apply(lambda name, counts=Counter(df['name']): name if counts[name] > 1 else 'other')
        return df
    
    assert jpp(df).equals(jez(df))
    assert jpp(df).equals(jon(df))
    
    %timeit jpp(df)  # 49.4 ms per loop
    %timeit jez(df)  # 56.2 ms per loop
    %timeit jon(df)  # 274 ms per loop
    

    设置

    df = pd.DataFrame({'name': ['john','sam','john','john','dean','dean','maggi',
                                'ram','maggi','ana','sam','sam'],
                       'pt': [23, 32, 45, 65, 65, 45, 32, 45, 90, 10, 32, 22]})
    
    df['name'] = df['name'].astype('category')
    df['name'] = df['name'].cat.add_categories('other')
    
    df = pd.concat([df, pd.concat([df.iloc[:5]]*100000)])
    

    【讨论】:

      猜你喜欢
      • 2018-11-19
      • 1970-01-01
      • 1970-01-01
      • 2019-11-24
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      • 2020-05-26
      • 1970-01-01
      相关资源
      最近更新 更多