如何仅对 Pandas 数据框中的一小部分列进行洗牌?

数据挖掘 Python 熊猫 数据框
2022-02-10 23:45:30

我想对 Pandas 数据框中特定列的值的一小部分(例如 40%)进行洗牌。

你会怎么做?有没有一种简单的惯用方法可以做到这一点,也许使用np.random, 或sklearn.utils.shuffle

我已经搜索并只找到了与改组整个列或改组 df 中的完整行相关的答案,但没有一个与仅改组一列的一小部分有关的答案。

显然,我实际上已经做到了,但我收到了警告,所以我认为即使在这个简单的例子中它似乎有效,这可能不是这样做的方法。

这是我所做的:

import pandas as pd
import numpy as np
df = pd.DataFrame({'i':range(20),
                   'L':[chr(97+i) for i in range(20)]
                  })

df['L2'] = df['L']
df.T
    0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19
i   0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19
L   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p   q   r   s   t
L2  a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p   q   r   s   t

现在,L2只是 column 的一个副本L我保持L原样,我想 shuffle L2,所以我可以直观地比较两者。i列只是一个虚拟列。它在那里表明我想保持我所有的列完好无损,除了L2我想洗牌的一小部分。

n_rows=len(df)
n_shuffle=int(n_rows*0.4)
n_rows, n_shuffle

(20, 8)
pick_rows=np.random.permutation(list(range(n_rows)))[0:n_shuffle]
pick_rows

array([ 3,  0, 11, 16, 14,  4,  8, 12])
shuffled_values=np.random.permutation(df['L2'][pick_rows])
shuffled_values

array(['l', 'e', 'd', 'q', 'o', 'i', 'm', 'a'], dtype=object)
df['L2'][pick_rows]=shuffled_values

我收到这个警告:

C:\Users\adumont\.conda\envs\fastai-cpu\lib\site-packages\ipykernel_launcher.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  """Entry point for launching an IPython kernel.
df.T

我得到以下结果,这是我所期望的(L2 的 40% 的值现在被打乱了):

    0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19
i   0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19
L   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p   q   r   s   t
L2  e   b   c   l   i   f   g   h   m   j   k   d   a   n   o   p   q   r   s   t

您可以在此处查看笔记本(在 nbviewer 上的渲染效果比此处更好):https ://nbviewer.jupyter.org/gist/adumont/bc2bac1b6cf7ba547e7ba6a19c01adb6

提前致谢。

1个回答

我认为没有任何惯用的方法可以做到这一点,因为这是非常不寻常的操作,通常应该整行或整列。你正在做的看起来是一个好方法。

您收到的错误SettingWithCopyWarning是一个常见警告,您可能正在对原始数据的副本而不是视图(原始数据)进行操作。有关更多信息,我建议在此处查看答案:https ://stackoverflow.com/questions/20625582/how-to-deal-with-settingwithcopywarning-in-pandas 。

为了避免错误并使代码更紧凑,您可以按如下方式执行:

import random

fraction = 0.4
n_rows = len(df)
n_shuffle=int(n_rows*fraction)

pick_rows = random.sample(range(1, n_rows), n_shuffle)

df.loc[pick_rows, 'L2'] = np.random.permutation(df.loc[pick_rows, 'L2'])

请注意,loc此处的使用将确保不会创建任何副本,并且一切都在原始数据帧上完成(即,这不会发出SettingWithCopyWarning警告)。