Pandas随机替换k百分比

10
拥有一个简单的 Pandas 数据框,其中包含 2 列,例如 idvalue,其中 value 可以是 01。我希望随机替换所有 value==1 的记录中的 10%0
如何使用 Pandas 实现这个功能?
3个回答

15

pandas答案

  • 使用query筛选出只有value == 1的过滤后的df
  • 使用sample(frac=.1)取其中的10%
  • 利用结果的索引将其赋值为零

df.loc[
    df.query('value == 1').sample(frac=.1).index,
    'value'
] = 0

numpy备选方案

  • 获取df['value']等于1的布尔数组
  • 赋予一个由10%零和90%一组成的随机数组

v = df.value.values == 1
df.loc[v, 'value'] = np.random.choice((0, 1), v.sum(), p=(.1, .9))

1
你成为“query”函数的赞助商 :-) - Zeugma
1
@Boud 我倾向于专注于某个特定的功能,并用它来回答许多问题。 - piRSquared

3

这是一个使用NumPy的方法,其中包括np.random.choice -

a = df.value.values  # get a view into value col
idx = np.flatnonzero(a) # get the nonzero indices

# Finally select unique 10% from those indices and set 0s there
a[np.random.choice(idx,size=int(0.1*len(idx)),replace=0)] = 0

示例运行 -

In [237]: df = pd.DataFrame(np.random.randint(0,2,(100,2)),columns=['id','value'])

In [238]: (df.value==1).sum() # Original Count of 1s in df.value column
Out[238]: 53

In [239]: a = df.value.values

In [240]: idx = np.flatnonzero(a)

In [241]: a[np.random.choice(idx,size=int(0.1*len(idx)),replace=0)] = 0

In [242]: (df.value==1).sum() # New count of 1s in df.value column
Out[242]: 48

另一种更具Pandas风格的方法 -
idx = np.flatnonzero(df['value'])
df.ix[np.random.choice(idx,size=int(0.1*len(idx)),replace=0),'value'] = 0

运行时测试

迄今为止发布的所有方法 -

def f1(df):  #@piRSquared's soln1
    df.loc[df.query('value == 1').sample(frac=.1).index,'value'] = 0

def f2(df):  #@piRSquared's soln2
    v = df.value.values == 1
    df.loc[v, 'value'] = np.random.choice((0, 1), v.sum(), p=(.1, .9))

def f3(df): #@Roman Pekar's soln
    idx = df.index[df.value==1]
    df.loc[np.random.choice(idx, size=idx.size/10, replace=False)].value = 0

def f4(df): #@Mine soln1
    a = df.value.values
    idx = np.flatnonzero(a)
    a[np.random.choice(idx,size=int(0.1*len(idx)),replace=0)] = 0

def f5(df): #@Mine soln2
    idx = np.flatnonzero(df['value'])
    df.ix[np.random.choice(idx,size=int(0.1*len(idx)),replace=0),'value'] = 0

时间 -

In [2]: # Setup inputs
   ...: df = pd.DataFrame(np.random.randint(0,2,(10000,2)),columns=['id','value'])
   ...: df1 = df.copy()
   ...: df2 = df.copy()
   ...: df3 = df.copy()
   ...: df4 = df.copy()
   ...: df5 = df.copy()
   ...: 

In [3]: # Timings
   ...: %timeit f1(df1)
   ...: %timeit f2(df2)
   ...: %timeit f3(df3)
   ...: %timeit f4(df4)
   ...: %timeit f5(df5)
   ...: 
100 loops, best of 3: 3.96 ms per loop
1000 loops, best of 3: 844 µs per loop
1000 loops, best of 3: 1.62 ms per loop
10000 loops, best of 3: 163 µs per loop
1000 loops, best of 3: 663 µs per loop

2

你可以使用numpy.random.choice来实现:

>>> idx = df.index[df.value==1]
>>> df.loc[np.random.choice(idx, size=idx.size/10, replace=False)].value = 0

OP想要随机替换仅为1的行,而不是整个df的随机样本。 - EdChum
是的,我错过了那个,我会修改答案。 - Roman Pekar

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