在熊猫数据框中的两列之间传输值

时间:2020-10-10 21:19:03

标签: python pandas python-2.7

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

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

4 个答案:

答案 0 :(得分:3)

您可以使用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),这意味着对于大型数据帧,它可以大大降低速度。

如您所见,一百万行数据帧需要花费几分钟的时间来执行。而且,如果您有一千万行到一亿行的数据帧,那么这些一线执行可能要花费数小时。


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);

enter image description here

答案 1 :(得分: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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

您可以使用Apply功能:

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' )