在熊猫中改组/排列DataFrame


76

有什么简单有效的方法可以按行或按列对panda中的数据框进行随机排序?即,如何编写一个函数shuffle(df, n, axis=0),该函数接受一个数据帧,许多随机播放n和一个轴(axis=0是行,axis=1是列),并返回已被随机播放n多次的数据帧的副本。

编辑:关键是这样做而不破坏数据框的行/列标签。如果您只是随机播放df.index,则会丢失所有这些信息。df除了行顺序或列顺序不同之外,我希望结果与原始结果相同。

Edit2:我的问题不清楚。我说的是随机排列,是指分别随机排列每一行。因此,如果您有两列ab,则我希望每一行都按其顺序进行随机排列,这样,您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)


^您的答案确实回答了问题,但似乎不是人们所寻找的答案
cs95

Answers:


39
In [16]: def shuffle(df, n=1, axis=0):     
    ...:     df = df.copy()
    ...:     for _ in range(n):
    ...:         df.apply(np.random.shuffle, axis=axis)
    ...:     return df
    ...:     

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

In [18]: shuffle(df)

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

2
在这里,我如何区分行和列改组?

谢谢..我澄清了我不清楚的问题。我希望独立于其他行按行随机播放-如此随机播放,您不必总是1,5在一起4,8在一起(也不只是将您限制为两个选择的列随机播放)

14
警告我认为df.apply(np.random.permutation)可以作为解决方案df.reindex(np.random.permutation(df.index)),看起来更整洁,但实际上它们的行为有所不同。后者维护同一行列之间的关联,而前者则不维护。我的误解当然可以,但是希望它将使其他人摆脱同样的错误。
gozzilli

1
在这种情况下,“ np”是什么?
雪橇

1
麻木 这是常见的事:import numpy as np
阿库

216

使用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

25
+1,因为这正是我一直在寻找的东西(即使事实证明这不是OP想要的东西)
Doug Paul

4
df.iloc[np.random.permutation(np.arange(len(df)))]如果有虚假的东西也可以使用(对于mi可能更快)。
安迪·海登

3
不错的方法。有办法做到这一点吗?
安德鲁(Andrew)

3
对我来说(Python v3.6和Pandas v0.20.1)我不得不替换df.reindex(np.random.permutation(df.index))df.set_index(np.random.permutation(df.index))以获得所需的效果。
伊曼纽尔

1
set_index像伊曼纽尔(Emanuel)之后,我还需要df.sort_index(inplace=True)
shadi

92

采样是随机的,因此只需采样整个数据帧。

df.sample(frac=1)

7
请注意,如果您尝试使用此方法重新分配列,则必须这样做df['column'] = df['column'].sample(frac=1).reset_index(drop=True)
Corey Levinson

18

您可以使用 sklearn.utils.shuffle()需要sklearn 0.16.1或更高版本才能支持Pandas数据帧):

# Generate data
import pandas as pd
df = pd.DataFrame({'A':range(5), 'B':range(5)})
print('df: {0}'.format(df))

# Shuffle Pandas data frame
import sklearn.utils
df = sklearn.utils.shuffle(df)
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.reset_index()来重置索引列,如果需要的话:

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

输出:

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

仅供参考,df.sample(frac=1)略快(400k行为76.9 ms与78.9 ms)。
m-dz

6

从文档使用sample()

In [79]: s = pd.Series([0,1,2,3,4,5])

# When no arguments are passed, returns 1 row.
In [80]: s.sample()
Out[80]: 
0    0
dtype: int64

# One may specify either a number of rows:
In [81]: s.sample(n=3)
Out[81]: 
5    5
2    2
4    4
dtype: int64

# Or a fraction of the rows:
In [82]: s.sample(frac=0.5)
Out[82]: 
5    5
4    4
1    1
dtype: int64

6

大熊猫的一个简单解决方案是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数组而不是一个Series,否则返回的Series将与原始DataFrame对齐而不改变任何内容:

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

4

我诉诸于略微调整@root的答案,并直接使用原始值。当然,这意味着您将失去执行花式索引的能力,但仅对数据进行混排就可以完美地工作。

In [1]: import numpy

In [2]: import pandas

In [3]: df = pandas.DataFrame({"A": range(10), "B": range(10)})    

In [4]: %timeit df.apply(numpy.random.shuffle, axis=0)
1000 loops, best of 3: 406 µs per loop

In [5]: %%timeit
   ...: for view in numpy.rollaxis(df.values, 1):
   ...:     numpy.random.shuffle(view)
   ...: 
10000 loops, best of 3: 22.8 µs per loop

In [6]: %timeit df.apply(numpy.random.shuffle, axis=1)
1000 loops, best of 3: 746 µs per loop

In [7]: %%timeit                                      
for view in numpy.rollaxis(df.values, 0):
    numpy.random.shuffle(view)
   ...: 
10000 loops, best of 3: 23.4 µs per loop

请注意,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 shuffle(df, n=1, axis=0):     
    df = df.copy()
    axis = int(not axis) # pandas.DataFrame is always 2D
    for _ in range(n):
        for view in numpy.rollaxis(df.values, axis):
            numpy.random.shuffle(view)
    return df

3

当您希望改组索引时,这可能会更有用。

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

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


1

我知道问题是针对pandasdf的,但是如果按行进行随机播放(列顺序已更改,行顺序未更改),那么列名称就不再重要了,np.array而改为使用a可能很有趣,那么np.apply_along_axis()您将正在找。

如果可以接受,那么这将有所帮助,请注意,切换数据沿其进行混合的轴很容易。

如果您将熊猫数据框命名为df,则可以:

  1. 得到数据框的值用values = df.values
  2. np.array从创建values
  3. 应用下面显示的方法np.array按行或列进行随机排列
  4. 从改组中重新创建新的(改组)pandas df np.array

原始阵列

a = np.array([[10, 11, 12], [20, 21, 22], [30, 31, 32],[40, 41, 42]])
print(a)
[[10 11 12]
 [20 21 22]
 [30 31 32]
 [40 41 42]]

保持行顺序,在每行中随机排列列

print(np.apply_along_axis(np.random.permutation, 1, a))
[[11 12 10]
 [22 21 20]
 [31 30 32]
 [40 41 42]]

保持列的顺序,随机排列每列中的行

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]]

0

这是我发现的一种变通方法,如果您只想改组DataFrame的一个子集:

shuffle_to_index = 20
df = pd.concat([df.iloc[np.random.permutation(range(shuffle_to_index))], df.iloc[shuffle_to_index:]])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.