【问题标题】:Shuffle dataframe values on condition that no element appears in its original position (derangement)在没有元素出现在其原始位置(混乱)的情况下随机播放数据帧值
【发布时间】:2022-01-09 09:53:35
【问题描述】:

Python 3.10/熊猫 1.1.3

鉴于此代码:

import pandas as pd
 
data = {'a': ['AA','BB','CC','DD', 'EE', 'FF', 'GG'],
        'b': [11, 22, 33, 44, 55, 66, 77],
        }
 
df = pd.DataFrame(data, columns=['a','b'])
df.a

print (df)

产生:

    a   b
0  AA  11
1  BB  22
2  CC  33
3  DD  44
4  EE  55
5  FF  66
6  GG  77

我需要了解如何在生成的数据帧不允许将任何 b 值与其原始 a 值关联的条件下对列 b 的值进行洗牌。

【问题讨论】:

  • 哇,到目前为止,所有 3 个答案都使用不同的方法完美运行。做得好。我将根据最少的代码行和最快的执行速度来选择最佳答案。
  • 如果b 有重复值怎么办?喜欢:[11,22,11,...]?

标签: python pandas permutation shuffle


【解决方案1】:

您可以将索引打乱,直到它不再与原始索引匹配,然后使用新的打乱索引对df['b'] 进行排序,并将这个新数组分配回df['b']

idx = df.index.tolist()
while (idx == df.index).any():
    np.random.shuffle(idx)
        
df['b'] = df['b'][idx].values

【讨论】:

  • 整洁。 while (idx == df.index).any(): np.random.shuffle(idx) 似乎是更简洁的代码。
【解决方案2】:

使用以下函数找到重新映射列的方法:

def derange(x):
  res = x
  while np.any(res == x):
    res = np.random.permutation(x)
  return res

然后将其应用于任何列:

df['b'] = derange(df['b'])

方法是生成排列,直到一个足够好为止。预期的尝试次数为(n/(n-1))^n,很快收敛到e

请注意,对于n=1,期望实际上趋于无穷大,这是有道理的,因为您不能破坏这样的列表。

为了完整起见,也可以确定性地执行错乱:

def derange2(x):
  n = len(x)
  for i in range(n - 1):
    j = random.randrange(i + 1, n)
    x[i], x[j] = x[j], x[i]

这个函数实际上是在原地转换列表。

您还可以拥有一个就地修改pandas 列的版本:

def derange3(df, col):
  n = df.shape[0]
  for i in range(n - 1):
    j = random.randrange(i + 1, n)
    df.iat[i, col], df.iat[j, col] = df.iat[j, col], df.iat[i, col]

【讨论】:

  • 到目前为止,所有 3 个答案都可以完成工作。我选择这个作为答案是因为它的代码行数最少,执行速度最快,并且有很好的详细解释。
【解决方案3】:

让我们一起做numpy

def rnd(l):
    l1 = l.copy()
    while True:
        np.random.shuffle(l1)
        if any(l == l1):
            break
        else:
            return l1
        
df.b = rnd(df.b.values)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-30
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 2023-01-09
    • 2013-07-17
    • 2020-09-07
    相关资源
    最近更新 更多