2014-03-05 26 views
5

我有一个大小适中的(约60,000行15列)csv文件,我正在使用熊猫。每一行代表一个人并包含个人数据。我想要匿名呈现数据。我希望这样做的一种方式是通过替换特定列中的值来避免它们很少出现。我最初试图这样做如下:取代熊猫数据框中罕见的值

def clean_data(entry): 
    if df[df.column_name == entry].index.size < 10: 
     return 'RARE_VALUE' 
    else: 
     return entry 

df.new_column_name = df.column_name.apply(clean_data) 

但运行它冻结我的系统每一次。这不幸意味着我没有有用的调试数据。有谁知道这样做的正确方法?该列包含字符串和空值。

+0

你可以[设置应用进度表](http://stackoverflow.com/a/18611535/1240268),但这显然会减慢你正在做的任何事情。一般来说,在一个应用程序中返回不同类型的数据(这里是一个字符串或一个系列)是一个糟糕的主意,目前还不清楚你想要应用程序返回什么...... –

+0

@AndyHayden你的评论暗示我可能不了解'apply'正常。我的理解是,如果条件满足,我的函数将返回字符串'RARE_VALUE',但如果不存在则保留现有字符串/ null。这是不正确的? –

+0

啊,等一下,我看到你在说什么,我误以为这是一个DataFrame适用。不,你是对的,但在每一步布尔掩模是**慢**! –

回答

7

我想你想的GroupBy列名:

g = df.groupby('column_name') 

您可以使用过滤器,例如,仅返回谁在列名的东西出现了10倍以上的那些行:

g.filter(lambda x: len(x) >= 10) 

为了与“RARE_VALUE”可以使用变换覆盖柱(其计算一次结果对于每个组,并适当地围绕扩散它):

df.loc[g[col].transform(lambda x: len(x) < 10).astype(bool), col] = 'RARE_VALUE' 

由于DSM指出,下面的技巧是更快:

df.loc[df[col].value_counts()[df[col]].values < 10, col] = "RARE_VALUE" 

这里的一些timeit信息(显示DSM的解决方案多么令人印象深刻!):

In [21]: g = pd.DataFrame(np.random.randint(1, 100, (1000, 2))).groupby(0) 

In [22]: %timeit g.filter(lambda x: len(x) >= 10) 
10 loops, best of 3: 67.2 ms per loop 

In [23]: %timeit df.loc[g[1].transform(lambda x: len(x) < 10).values.astype(bool), 1] 
10 loops, best of 3: 44.6 ms per loop 

In [24]: %timeit df.loc[df[1].value_counts()[df[1]].values < 10, 1] 
1000 loops, best of 3: 1.57 ms per loop 
+4

'df.loc [df [col] .value_counts()[df [col]]。values <10,col] =“RARE_VALUE”'可能会快一点。 – DSM

+0

@DSM这是一些适当的巫术魔术...... *当然*这不是更快! –

+0

关心一些quatloos? – DSM