在 pandas 数据框中的两列之间传输值
Transferring values between two columns in a pandas data frame
我有一个这样的 pandas 数据框:
p q
0.5 0.5
0.6 0.4
0.3 0.7
0.4 0.6
0.9 0.1
所以,我想知道如何将更大的值转移到 p 列,反之亦然(将较小的值转移到 q 列),如下所示:
p q
0.5 0.5
0.6 0.4
0.7 0.3
0.6 0.4
0.9 0.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!
:
- 对于大型数据集,Erfan 的 numpy 答案看起来是执行速度最快的(以毫秒为单位)
- 我的
.where()
答案也有很好的性能,可以将执行时间保持在几毫秒内(我假设 `np.where() 会有类似的结果。
- 我以为MHDG7的回答是最慢的,但实际上比Alexander的回答更快。
- 我猜亚历山大的回答很慢,因为它需要通过
axis=1
。 MGDG7 和 Alexander 的答案是 row-wise(axis=1
),这意味着它可以大大降低大型数据帧的速度。
如您所见,一百万行数据帧需要几分钟才能执行。而且,如果您有一个 1000 万行到 1 亿行的数据框,这些 one-liners 可能需要数小时才能执行。
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);
使用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
使用 agg
,传递函数列表(max
和 min
)并指定 axis=1
以将这些函数应用于列 row-wise.
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
您可以使用应用功能:
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' )
我有一个这样的 pandas 数据框:
p q
0.5 0.5
0.6 0.4
0.3 0.7
0.4 0.6
0.9 0.1
所以,我想知道如何将更大的值转移到 p 列,反之亦然(将较小的值转移到 q 列),如下所示:
p q
0.5 0.5
0.6 0.4
0.7 0.3
0.6 0.4
0.9 0.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!
:
- 对于大型数据集,Erfan 的 numpy 答案看起来是执行速度最快的(以毫秒为单位)
- 我的
.where()
答案也有很好的性能,可以将执行时间保持在几毫秒内(我假设 `np.where() 会有类似的结果。 - 我以为MHDG7的回答是最慢的,但实际上比Alexander的回答更快。
- 我猜亚历山大的回答很慢,因为它需要通过
axis=1
。 MGDG7 和 Alexander 的答案是 row-wise(axis=1
),这意味着它可以大大降低大型数据帧的速度。
如您所见,一百万行数据帧需要几分钟才能执行。而且,如果您有一个 1000 万行到 1 亿行的数据框,这些 one-liners 可能需要数小时才能执行。
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);
使用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
使用 agg
,传递函数列表(max
和 min
)并指定 axis=1
以将这些函数应用于列 row-wise.
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
您可以使用应用功能:
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' )