根据列条件交换列值(Pandas DataFrame)

4

这个数据框有两列整数AB

a        b
1        3
4        2
2        0
6        1
...

我需要以以下方式进行交换:
if df.a > df.b:
    temp = df.b
    df.b = df.a
    df.a = temp

期望输出:

a        b
1        3
2        4    <----
0        2    <----
1        6    <----

基本上,始终将两个值中较小的值放在A列。

我觉得我应该使用 loc,但是我还没有找到正确的方法。

4个回答

7
In [443]: df['a'], df['b'] = df.min(axis=1), df.max(axis=1)

In [444]: df
Out[444]:
   a  b
0  1  3
1  2  4
2  0  2
3  1  6

或者

pd.DataFrame(np.sort(d.values, axis=1), d.index, d.columns)

6
使用np.where,您可以执行以下操作:
In [21]: df.a, df.b = np.where(df.a > df.b, [df.b, df.a], [df.a, df.b])

In [23]: df
Out[23]:
   a  b
0  1  3
1  2  4
2  0  2
3  1  6

或者,使用.loc
In [35]: cond = df.a > df.b

In [36]: df.loc[cond, ['a', 'b']] = df.loc[cond, ['b', 'a']].values

In [37]: df
Out[37]:
   a  b
0  1  3
1  2  4
2  0  2
3  1  6

或者.apply(np.sort, axis=1) 如果你需要更小的 a 值和更大的 b

In [54]: df.apply(np.sort, axis=1)
Out[54]:
   a  b
0  1  3
1  2  4
2  0  2
3  1  6

3

看到@JohnGait和@MaxU提出的方法,我进行了一个小速度比较。

arr = np.random.randint(low = 100, size = (10000000, 2))

# using np.where
df = pd.DataFrame(arr, columns = ['a', 'b'])
t_0 = time.time()
df.a, df.b = np.where(df.a > df.b, [df.b, df.a], [df.a, df.b])
t_1 = time.time()

# using df.loc
df = pd.DataFrame(arr, columns = ['a', 'b'])
t_2 = time.time()
cond = df.a > df.b
df.loc[cond, ['a', 'b']] = df.loc[cond, ['b', 'a']].values
t_3 = time.time()

# using df.min
df = pd.DataFrame(arr, columns = ['a', 'b'])
t_4 = time.time()
df['a'], df['b'] = df.min(axis=1), df.max(axis=1)
t_5 = time.time()

# using np.sort
t_6 = time.time()
df_ = pd.DataFrame(np.sort(arr, axis=1), df.index, df.columns)
t_7 = time.time()

t_1 - t_0 # using np.where:  5.759037971496582
t_3 - t_2 # using .loc:      0.12156987190246582
t_5 - t_4 # using df.min:    1.0503261089324951
t_7 - t_6 # 0.20351791381835938    

尽管第二种方法是最快的方法,但实际上获得的收益微不足道。我因为追求完美而添加了它。我没有包括排序方法,因为我相信那会慢得多。
编辑: 我之前错误地报告了 np.where 的计算时间,由于我的错误。已经更正了(结果发现它是最慢的!),并添加了另一种方法(遵循@MaxU的评论)。

很好的比较!+1。你能否为 pd.DataFrame(np.sort(d.values, axis=1), d.index, d.columns) 添加时间? - MaxU - stand with Ukraine

3

解决方案
这很简单,只需要

df.values.sort(1)

df

   a  b
0  1  3
1  2  4
2  0  2
3  1  6

发生了什么
我可以使用numpy.arraysort方法就地对其进行排序。 我传递参数axis = 1,表示我想按第一轴(按行)排序。 数据帧的values属性访问基础numpy数组。 因此,df.values.sort(1)以行为单位就地对基础值进行了排序... 完成。


我们可以更加明确一些

df.values[:] = np.sort(df.values, 1)

这使我们可以非常灵活地对列的子集或反向排序进行操作。
df.values[:, ::-1] = np.sort(df.values, 1)

1
这太棒了! - MaxU - stand with Ukraine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接