Python 在pandas中洗牌/置换数据帧

Python 在pandas中洗牌/置换数据帧,python,numpy,pandas,Python,Numpy,Pandas,什么是一种简单而有效的方法,可以按行或列将数据帧以大熊猫的形式洗牌?也就是说,如何编写一个函数shuffle(df,n,axis=0),该函数接受一个数据帧、多个shufflen、一个轴(axis=0是行,axis=1是列),并返回一个已被洗牌n次的数据帧副本 编辑:关键是在不破坏数据帧的行/列标签的情况下执行此操作。如果你只是洗牌df.index,就会丢失所有信息。我希望得到的df与原始值相同,只是行或列的顺序不同 编辑2:我的问题不清楚。当我说洗牌的行,我的意思是洗牌每一行独立。因此,如果您

什么是一种简单而有效的方法,可以按行或列将数据帧以大熊猫的形式洗牌?也就是说,如何编写一个函数
shuffle(df,n,axis=0)
,该函数接受一个数据帧、多个shuffle
n
、一个轴(
axis=0
是行,
axis=1
是列),并返回一个已被洗牌
n
次的数据帧副本

编辑:关键是在不破坏数据帧的行/列标签的情况下执行此操作。如果你只是洗牌
df.index
,就会丢失所有信息。我希望得到的
df
与原始值相同,只是行或列的顺序不同

编辑2:我的问题不清楚。当我说洗牌的行,我的意思是洗牌每一行独立。因此,如果您有两列
a
b
,我希望每一行都单独进行洗牌,这样您就不会像您只是将每一行作为一个整体重新排序一样,在
a
b
之间有相同的关联。比如:

for 1...n:
  for each col in df: shuffle column
return new_df
但希望比单纯的循环更有效。这对我不起作用:

def shuffle(df, n, axis=0):
        shuffled_df = df.copy()
        for k in range(n):
            shuffled_df.apply(np.random.shuffle(shuffled_df.values),axis=axis)
        return shuffled_df

df = pandas.DataFrame({'A':range(10), 'B':range(10)})
shuffle(df, 5)

使用numpy的
random.permuation
功能:

In [1]: df = pd.DataFrame({'A':range(10), 'B':range(10)})

In [2]: df
Out[2]:
   A  B
0  0  0
1  1  1
2  2  2
3  3  3
4  4  4
5  5  5
6  6  6
7  7  7
8  8  8
9  9  9


In [3]: df.reindex(np.random.permutation(df.index))
Out[3]:
   A  B
0  0  0
5  5  5
6  6  6
3  3  3
8  8  8
7  7  7
9  9  9
1  1  1
2  2  2
4  4  4

我求助于稍微修改@root的答案,并直接使用原始值。当然,这意味着您将失去创建奇特索引的能力,但它仅适用于无序排列数据

[1]中的
:导入numpy
在[2]中:输入大熊猫
在[3]中,df=pandas.DataFrame({“A”:range(10),“B”:range(10)})
在[4]中:%timeit df.apply(numpy.random.shuffle,axis=0)
1000个回路,最好为3:406µs/回路
在[5]中:%%timeit
…:对于numpy.rollaxis中的视图(df.values,1):
…:numpy.random.shuffle(视图)
...: 
10000个回路,最好为3个:每个回路22.8µs
在[6]中:%timeit df.apply(numpy.random.shuffle,axis=1)
1000个回路,最佳3个:每个回路746µs
在[7]中:%%timeit
对于numpy.rollaxis(df.values,0)中的视图:
numpy.random.shuffle(视图)
...: 
10000个回路,最佳3个:每个回路23.4µs
请注意,
numpy.rollaxis
将指定的轴带到第一个维度,然后让我们用剩余维度遍历数组,也就是说,如果我们想沿着第一个维度(列)移动,我们需要将第二个维度向前移动,以便将移动应用到第一个维度上的视图

In [8]: numpy.rollaxis(df, 0).shape
Out[8]: (10, 2) # we can iterate over 10 arrays with shape (2,) (rows)

In [9]: numpy.rollaxis(df, 1).shape
Out[9]: (2, 10) # we can iterate over 2 arrays with shape (10,) (columns)
然后,您的最终函数使用技巧使结果与将函数应用于轴的预期一致:

def随机播放(df,n=1,轴=0): df=df.copy() axis=int(非axis)#pandas.DataFrame始终为2D 对于范围内的u(n): 对于numpy.rollaxis(df.values,axis)中的视图: numpy.random.shuffle(视图) 返回df
当您希望索引被洗牌时,这可能更有用

def shuffle(df):
    index = list(df.index)
    random.shuffle(index)
    df = df.ix[index]
    df.reset_index()
    return df

它使用新索引选择新的df,然后重置它们

从文档中使用
sample()


采样随机化,所以只需对整个数据帧进行采样

df.sample(frac=1)

如果您只想洗牌数据帧的一个子集,我发现了一个解决方法:

shuffle_to_index = 20
df = pd.concat([df.iloc[np.random.permutation(range(shuffle_to_index))], df.iloc[shuffle_to_index:]])
您可以使用(sklearn 0.16.1或更高版本来支持熊猫数据帧):

产出:

df:    A  B
0  0  0
1  1  1
2  2  2
3  3  3
4  4  4


df:    A  B
1  1  1
0  0  0
3  3  3
4  4  4
2  2  2
df:    A  B
0  1  1
1  0  0
2  4  4
3  2  2
4  3  3
然后,如果需要,可以使用重置索引列:

df = df.reset_index(drop=True)
print('\n\ndf: {0}'.format(df)
产出:

df:    A  B
0  0  0
1  1  1
2  2  2
3  3  3
4  4  4


df:    A  B
1  1  1
0  0  0
3  3  3
4  4  4
2  2  2
df:    A  B
0  1  1
1  0  0
2  4  4
3  2  2
4  3  3

我知道问题是关于
pandas
df的,但是如果按行进行洗牌(列顺序改变,行顺序不变),那么列名就不再重要了,可以使用
np。数组
,然后
np。沿着轴应用()
将是您要寻找的

如果这是可以接受的,那么这将是有帮助的,请注意,很容易切换数据移动的轴

def shuffle(df):
    index = list(df.index)
    random.shuffle(index)
    df = df.ix[index]
    df.reset_index()
    return df
如果您将熊猫数据框命名为
df
,可能您可以:

  • 使用
    values=df.values
    获取数据帧的值
  • 值创建
    np.array
  • 应用下面显示的方法按行或列洗牌
    np.array
  • 从无序排列的
    np.数组重新创建一个新的(无序排列的)数组
  • 原始数组 保持行顺序,在每行内洗牌 保持列的顺序,洗牌每列中的行 原始数组不变
    pandas中的一个简单解决方案是在每个列上单独使用
    sample
    方法。使用
    apply
    迭代每列:

    df = pd.DataFrame({'a':[1,2,3,4,5,6], 'b':[1,2,3,4,5,6]})
    df
    
       a  b
    0  1  1
    1  2  2
    2  3  3
    3  4  4
    4  5  5
    5  6  6
    
    df.apply(lambda x: x.sample(frac=1).values)
    
       a  b
    0  4  2
    1  1  6
    2  6  5
    3  5  3
    4  2  4
    5  3  1
    
    您必须使用
    .value
    ,以便返回一个numpy数组而不是序列,否则返回的序列将与原始数据帧对齐,而不会改变任何内容:

    df.apply(lambda x: x.sample(frac=1))
    
       a  b
    0  1  1
    1  2  2
    2  3  3
    3  4  4
    4  5  5
    5  6  6
    

    这里如何区分行和列洗牌?谢谢。。我澄清了我不清楚的问题。我正在寻找独立于其他行的逐行洗牌-因此,洗牌的方式不会总是将
    1,5
    4,8
    放在一起(但也不仅仅是一个列洗牌,它将您限制为两个选择)警告我认为
    df.apply(np.random.permutation)
    将作为解决方案
    df.reindex(np.随机排列(df.索引))
    看起来更整洁,但实际上它们的行为不同。后者在同一行的列之间保持关联,前者没有。当然,我的误解,但希望它能避免其他人犯同样的错误。在这种情况下,“np”是什么?numpy。通常会这样做:
    将numpy导入为np
    +1,因为这是确切地说,我正在寻找的(尽管它不是OP想要的)也可以使用
    df.iloc[np.random.permutation(np.arange(len(df))]
    如果有重复和类似的东西(对于mi可能更快)。很好的方法。但是有什么方法可以做到吗?对于我(Python v3.6和Pandas v0.20.1),我必须替换
    df.reindex(np.random.permutation(df.index))
    by
    df.set_index(np.random.permutation(df.index))
    以获得所需的效果
    print(np.apply_along_axis(np.random.permutation, 0, a))
    [[40 41 32]
     [20 31 42]
     [10 11 12]
     [30 21 22]]
    
    print(a)
    [[10 11 12]
     [20 21 22]
     [30 31 32]
     [40 41 42]]
    
    df = pd.DataFrame({'a':[1,2,3,4,5,6], 'b':[1,2,3,4,5,6]})
    df
    
       a  b
    0  1  1
    1  2  2
    2  3  3
    3  4  4
    4  5  5
    5  6  6
    
    df.apply(lambda x: x.sample(frac=1).values)
    
       a  b
    0  4  2
    1  1  6
    2  6  5
    3  5  3
    4  2  4
    5  3  1
    
    df.apply(lambda x: x.sample(frac=1))
    
       a  b
    0  1  1
    1  2  2
    2  3  3
    3  4  4
    4  5  5
    5  6  6