【问题标题】:Sort but have uniform distribution for a second variable if values are same如果值相同,则排序但第二个变量的分布均匀
【发布时间】:2017-02-22 16:20:54
【问题描述】:

我有 2 列:熊猫数据框中的 Col1、Col2。 Col1 有 1 到 100 的数字,Col2 有 0 和 1。

我想对这个数据框进行排序,使行按 Col1 排序。在我的例子中,我有几百万行,所以 Col1 的值肯定会重复很多次。

我可以使用data = data.sort_values('Col1') 来根据 Col1 对值进行排序。例如,这可以给出:

Col1 Col2 ... OR ... Col1 Col2 ... OR ... Col1 Col2
100  0               100  1               100  0
100  0               100  1               100  0
100  1               100  1               100  0
100  0               100  1               100  0
100  1               100  0               100  1
100  1               100  0               100  1
100  1               100  0               100  1
100  0               100  0               100  1
99   1               99   1               99   1
...                  ...                  ...

根据我使用的排序算法(快速排序、归并排序等),当 Col1=100 时,Col2 可能有多种分布。

在我的 Col1 值相同的部分,我希望我的 Col2 的分布是均匀的,就像这样:

Col1 Col2
100  0
100  1
100  0
100  1
100  0
100  1
100  0
100  1
99   1
...

python/numpy/pandas/[任何其他库]有什么排序方法可以做到这一点吗?任何可以做到这一点的算法的想法?

【问题讨论】:

    标签: python sorting pandas numpy


    【解决方案1】:

    您必须在每个组的开头生成良好的排名以交替 0 和 1:

    df=pd.DataFrame({'col1':randint(0,100,1000),'col2':randint(0,2,1000),}) 
    df.sort_values(['col1','col2'],inplace=True)
    cnt= df.groupby(['col1','col2']).col1.count()
    df['rk']=np.hstack([list(range(n)) for n in cnt])
    df.sort_values(['col1','rk'],inplace=True)
    

    一些解释:

    第一排序df:

    df.sort_values(['col1','col2'],inplace=True)
    

    然后计算每个值:

    cnt= df.groupby(['col1','col2']).col1.count()
    

    然后排名:

    df['rk']=np.hstack([list(range(n)) for n in cnt])
    

    解决办法是:

    df.sort_values(['col1','rk'],inplace=True)
    

    df=pd.DataFrame({'col1':randint(0,100,1000),'col2':randint(0,2,1000),})

         col1  col2  rk
    161     0     0   0
    1       0     1   0
    253     0     0   1
    118     0     1   1
    471     0     0   2
    391     0     1   2
    582     0     0   3
    444     0     1   3
    579     0     1   4
    735     0     1   5
    887     0     1   6
    111     1     0   0
    57      1     1   0
    ......
    

    【讨论】:

    • Eas 尝试了这个,df['rk']=sum([list(range(n)) for n in cnt]) 给出了一个错误。你能检查一下吗?我无法重现结果
    • 我将代码放在块中以避免拼写错误。错误信息是什么?
    • 它本质上说你不能在列表列表上做sumsum([[1,1], [2,2]]) 也不起作用。它给了unsupported operand type(s) for +: 'int' and 'list'。它需要一个整数列表
    【解决方案2】:

    我能想到的一个想法是创建一个新列,它的值代表顺序:

    offset_dict = defaultdict(lambda: defaultdict(lambda: 2))
    
    def get_offset(row):
        step = offset_dict[row["Col1"]][row["Col2"]]
        offset_dict[row["Col1"]][row["Col2"]] += 1
        return row["Col1"] + 1.0/step
    
    df["offset"] = df.apply(get_offset, axis=1)
    df = df.sort_values("offset")
    

    对于表单的输入:

        Col1  Col2
    0    100     1
    1    100     1
    2    100     1
    3     99     1
    4    100     0
    5    100     0
    6     99     1
    7     99     0
    8     99     0
    9    100     0
    10    99     0
    11   100     1
    12   100     1
    13   100     0
    14   100     0
    

    输出将是:

        Col1  Col2      offset
    10    99     0   99.250000
    6     99     1   99.333333
    8     99     0   99.333333
    3     99     1   99.500000
    7     99     0   99.500000
    12   100     1  100.166667
    14   100     0  100.166667
    11   100     1  100.200000
    13   100     0  100.200000
    2    100     1  100.250000
    9    100     0  100.250000
    1    100     1  100.333333
    5    100     0  100.333333
    0    100     1  100.500000
    4    100     0  100.500000
    

    【讨论】:

      【解决方案3】:

      这取决于您所说的“均匀分布”是什么意思。你会应用一些必须通过特定阈值的特定测试吗?如果您只需要它“足够均匀”或“不可预测”,您可以在 Col1 的每个值内随机化。

      # setup
      import pandas as pd
      import numpy as np
      df=pd.DataFrame({'col1':randint(0,100,1000),'col2':randint(0,2,1000),})
      
      # add a column with random numbers
      df['random_col'] = np.random.random(len(df))
      
      # two-level sort 
      df.sort_values(['col1','random_col'])
      

      【讨论】:

      • 嗯,所以我基本上希望(概率,如有必要)当 Col1 具有相同值时,0 和 1 是均匀分布的。我的最终目标是,在我获取的任何数据块中(假设 Col1=99 的前 10% 行),平均 Col2 应该相同。我知道前 10% 可能与 1%-11% 不同,因为这是离散数据。但从概率上来说就足够了。
      • 非常感谢您提出关于“如何统一”的问题。这让我意识到,也许这个问题没有很好地定义。并帮助我重新思考如何构建这个问题。
      【解决方案4】:

      我们可以使用cumcount,然后按列和计数排序:

      import pandas as pd
      import numpy as np
      #data from B. M.
      
      df=pd.DataFrame({'col1':np.random.randint(0,100,1000),'col2':np.random.randint(0,2,1000)}) 
      
      #make a new column, with the cumulative count for each of col1:col2
      df['values'] = df.groupby(['col1','col2']).cumcount()
      
      #sort by the col1, and values:
      df.sort_values(['col1', 'values'])
      
          col1    col2    values
      61  0   1   0
      213 0   0   0
      173 0   1   1
      473 0   0   1
      266 0   1   2
      

      如果它们非常不平衡,这将失败!

      作为一种快速技巧,要按不平衡排序,我们可以通过每个值的计数进行更正,然后除以我们的索引:

      #make a new column, with the cumulative count for each of col1:col2
      df['values'] = df.groupby(['col1','col2']).cumcount()
      
      #sort by the col1, and values:
      df.sort_values(['col1', 'values'])
      #merge in a count of each value
      df = df.merge(df.groupby(['col1', 'col2']).size().reset_index())
      #make a key of index/count
      df['sortkey'] = df['values']/df[0]
      #sort
      df.sort_values(['col1', 'sortkey'])
      
          col1    col2    values  sortkey 0
      393 0   0   0   0.000000    3
      812 0   1   0   0.000000    4
      813 0   1   1   0.250000    4
      394 0   0   1   0.333333    3
      814 0   1   2   0.500000    4
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-18
        • 1970-01-01
        • 2018-10-07
        • 2019-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-12
        相关资源
        最近更新 更多