【问题标题】:Transferring values between two columns in a pandas data frame在熊猫数据框中的两列之间传输值
【发布时间】:2020-10-10 21:19:03
【问题描述】:

我有一个这样的熊猫数据框:

p q
0.5 0.5
0.6 0.4
0.3 0.7
0.4 0.6
0.9 0.1

所以,我想知道,如何将较大的值传输到 p 列,反之亦然,用于 q 列(将较小的值传输到 q 列),如下所示:

p q
0.5 0.5
0.6 0.4
0.7 0.3
0.6 0.4
0.9 0.1

【问题讨论】:

    标签: python pandas python-2.7


    【解决方案1】:

    您可以使用np.where() 存储一些条件系列,然后将它们应用于数据框:

    s1 = np.where(df['p'] < df['q'], df['q'], df['p'])
    s2 = np.where(df['p'] > df['q'], df['q'], df['p'])
    df['p'] = s1
    df['q'] = s2
    df
    Out[1]: 
         p    q
    0  0.5  0.5
    1  0.6  0.4
    2  0.7  0.3
    3  0.6  0.4
    4  0.9  0.1
    

    你也可以使用.where():

    s1 = df['p'].where(df['p'] > df['q'], df['q'])
    s2 = df['p'].where(df['p'] < df['q'], df['q'])
    df['p'] = s1
    df['q'] = s2
    df
    

    我测试了从 100 行到 100 万行的不同行的执行时间,需要通过 axis=1 的答案可以是 10,000 times slower!

    1. Erfan 的 numpy 答案看起来是大型数据集执行速度最快的毫秒数
    2. 我的.where() 答案也具有出色的性能,可以将执行时间保持在毫秒内(我假设 `np.where() 会产生类似的结果。
    3. 我以为 MHDG7 的回答会最慢,但实际上它比 Alexander 的回答要快。
    4. 我猜亚历山大的回答很慢,因为它需要通过axis=1。 MGDG7 和 Alexander 的答案是逐行的(axis=1),这意味着它可以极大地减慢大型数据帧的速度。

    如您所见,执行一百万行数据帧需要几分钟时间。而且,如果您有 1000 万行到 1 亿行的数据帧,这些单行代码可能需要数小时才能执行。


    from timeit import timeit
    df = d.copy()
    
    def df_where(df):
        s1 = df['p'].where(df['p'] > df['q'], df['q'])
        s2 = df['p'].where(df['p'] < df['q'], df['q'])
        df['p'] = s1
        df['q'] = s2
        return df
    
    
    def agg_maxmin(df):
        df[['p', 'q']] = df[['p', 'q']].agg([max, min], axis=1)
        return df
    
    
    def np_flip(df):
        df = pd.DataFrame(np.flip(np.sort(df), axis=1), columns=df.columns)
        return df
    
    
    def lambda_x(df):
        df = df.apply(lambda x: [x['p'],x['q']] if x['p']>x['q'] else [x['q'],x['p']],axis=1,result_type='expand')
        return df
    
    
    res = pd.DataFrame(
        index=[20, 200, 2000, 20000, 200000],
        columns='df_where agg_maxmin np_flip lambda_x'.split(),
        dtype=float
    )
    
    for i in res.index:
        d = pd.concat([df]*i)
        for j in res.columns:
            stmt = '{}(d)'.format(j)
            setp = 'from __main__ import d, {}'.format(j)
            print(stmt, d.shape)
            res.at[i, j] = timeit(stmt, setp, number=1)
    
    res.plot(loglog=True);
    

    【讨论】:

    • @Siavash 没问题,顺便说一句,我注意到每次你支持一个解决方案时,你都会接受它作为解决方案。我不确定您是否打算这样做,但您应该接受您认为的“最佳解决方案”。在我看来,亚历山大的解决方案是最好的解决方案,但重要的是你认为最好的解决方案是什么。当有多个相互竞争的解决方案并且您接受一个时,最好用一句话或几句话说明原因。如果你不知道最好的解决方案是什么,就说你不知道并随机挑选一个。
    • 感谢您的通知!实际上,Alexander 和 MhDG7 解决方案都是最好的解决方案。然而,Alexander 解决方案很简单并且可能比 MhDG7 解决方案更快;我相信 MhDG7 的解决方案对于初学者来说可能更容易理解。
    • @Siavash 出于自己的好奇心,我测试了四个答案的性能。对我来说,关键的一点是,需要传递axis=1 的操作将显着减慢对较大数据帧的操作,并且对于具有非逐行操作的矢量化解决方案可能需要几分钟或几小时而不是几毫秒或几秒。出于某种原因,我认为亚历山大的回答仍然很快,但这是一个很好的教训,传递 axis=1 对性能很危险——慢了 10,000 倍!你也可以通过数据框for-loop
    • 很好的分析。我用一个似乎比迄今为止提出的任何解决方案都更快的解决方案更新了我的答案。
    • @DavidErickson 在二凡回答有问题。当我们有超过两列(例如三列)时,Erfan 的解决方案将最大值传输到第一列,反之亦然,而我只想在两列之间传输值。因此,您的解决方案是处理图表的最快方法!
    【解决方案2】:

    使用numpy.sort对水平轴升序排序,然后将数组翻转到axis=1

    df = pd.DataFrame(np.flip(np.sort(df), axis=1), columns=df.columns)
    
         p    q
    0  0.5  0.5
    1  0.6  0.4
    2  0.7  0.3
    3  0.6  0.4
    4  0.9  0.1
    

    【讨论】:

    • @Erfan 在我的回答中,出于好奇,我测试了不同的答案。这个是所有测试行数的获胜者。 +1
    【解决方案3】:

    使用 agg,传递函数列表(maxmin)并指定 axis=1 以将这些函数逐行应用于列。

    df[['p', 'q']] = df[['p', 'q']].agg([max, min], axis=1)
    
    >>> df
         p    q
    0  0.5  0.5
    1  0.6  0.4
    2  0.7  0.3
    3  0.6  0.4
    4  0.9  0.1
    

    简单的解决方案并不总是性能最好的(例如上面的那个)。以下解决方案明显更快。它会屏蔽p 列小于q 列的数据框,然后交换值。

    mask = df['p'].lt(df['q'])
    df.loc[mask, ['p', 'q']] = df.loc[mask, ['q', 'p']].to_numpy()
    >>> df
         p    q
    0  0.5  0.5
    1  0.6  0.4
    2  0.7  0.3
    3  0.6  0.4
    4  0.9  0.1
    

    【讨论】:

    • 不错! +1 或者干脆df = df.agg([max, min], axis=1);但是,在实际数据框中可能还有其他列,这就是您指定的原因。我认为这是最简单也是最好的答案。
    • 正确,我假设数据框将包含其他列。
    • @Alexander 这在性能方面被证明是最慢的。这是因为传递了axis=1 - 使其按行排列?
    • @Alexander 不确定您是否看到我的更新答案,但从 100 到 100 万
    【解决方案4】:

    您可以使用应用功能:

    df[['p','q']] = df.apply(lambda x: [x['p'],x['q']] if x['p']>x['q'] else [x['q'],x['p']],axis=1,result_type='expand' )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-09
      • 1970-01-01
      • 2022-08-22
      • 2021-10-05
      • 1970-01-01
      • 2018-04-18
      • 2020-09-01
      • 2022-12-15
      相关资源
      最近更新 更多