【问题标题】:shuffling/permutating a DataFrame in pandas改组/排列熊猫中的DataFrame
【发布时间】:2013-03-24 05:07:34
【问题描述】:

在 pandas 中按行或按列对数据帧进行洗牌的简单而有效的方法是什么? IE。如何编写一个函数shuffle(df, n, axis=0),它接受一个数据帧、多个洗牌n 和一个轴(axis=0 是行,axis=1 是列)并返回已洗牌的数据帧的副本@987654326 @时代。

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

Edit2:我的问题不清楚。当我说洗牌时,我的意思是独立洗牌每一行。因此,如果您有两列 ab,我希望每一行都自行改组,这样您就不会像重新排序那样在 ab 之间拥有相同的关联每一行作为一个整体。类似的东西:

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)

【问题讨论】:

标签: python numpy pandas


【解决方案1】:

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

【讨论】:

  • +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)) 替换为 df.set_index(np.random.permutation(df.index)) 以获得所需的效果。
  • set_index 像Emanuel 之后,我还需要df.sort_index(inplace=True)
【解决方案2】:
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

【讨论】:

  • 这里如何区分行和列洗牌?
  • 警告 我认为df.apply(np.random.permutation) 可以作为df.reindex(np.random.permutation(df.index)) 的解决方案,看起来更整洁,但实际上它们的行为不同。后者维护同一行的列之间的关联,前者没有。当然是我的误解,但希望它能帮助其他人避免同样的错误。
  • 在这种情况下什么是“np”?
  • numpy.常做:import numpy as np
  • 我只想做一个随机播放,所以我只使用了df.apply(np.random.shuffle, index=1) 但这似乎没有任何作用,打印结果 df 看起来与输入完全相同。如果我做df = df.apply( ... ) 我得到一个带有Nans. 的系列如果我做df.apply( ... inplace=True) 然后我得到一个错误。
【解决方案3】:

我稍微调整了@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

【讨论】:

    【解决方案4】:

    当您想要随机排列索引时,这可能会更有用。

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

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

    【讨论】:

      【解决方案5】:

      从文档中使用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】:

        抽样是随机的,所以只需对整个数据帧进行抽样。

        df.sample(frac=1)
        

        正如@Corey Levinson 所说,重新分配时必须小心:

        df['column'] = df['column'].sample(frac=1).reset_index(drop=True)
        

        【讨论】:

        • 请注意,如果您尝试使用此重新分配列,则必须执行df['column'] = df['column'].sample(frac=1).reset_index(drop=True)
        【解决方案7】:

        如果您只想随机播放 DataFrame 的子集,我发现了一个解决方法:

        shuffle_to_index = 20
        df = pd.concat([df.iloc[np.random.permutation(range(shuffle_to_index))], df.iloc[shuffle_to_index:]])
        

        【讨论】:

          【解决方案8】:

          您可以使用sklearn.utils.shuffle()requiressklearn 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 对 78.9 毫秒)。
          【解决方案9】:

          我知道问题是针对pandas df,但是如果按行发生随机播放(列顺序已更改,行顺序未更改),那么列名不再重要,使用 @ 可能会很有趣改为 987654322@,然后 np.apply_along_axis() 将是您要查找的内容。

          如果这是可以接受的,那么这将是有帮助的,注意很容易切换数据被打乱的轴。

          如果你的熊猫数据框被命名为df,也许你可以:

          1. values = df.values获取dataframe的值,
          2. values 创建一个np.array
          3. 应用如下所示的方法将np.array按行或列打乱
          4. 从改组的np.array 重新创建一个新的(改组的)pandas df

          原始数组

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

          【讨论】:

            【解决方案10】:

            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 数组而不是一个系列,否则返回的系列将与原始 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
            

            【讨论】:

              猜你喜欢
              • 2015-07-02
              • 2023-02-07
              • 1970-01-01
              • 2014-11-23
              相关资源
              最近更新 更多