目标是用零替换某些列中的所有负值(“capped1”和“capped2”但不是“signed”)。需要通过正则表达式选择列。 (实际df具有> 1000列,名称更复杂)
我想出了:
import pandas as pd
import re
import numpy as np
index = [1,2,3,4]
d = {'capped1': [1,0,-1,np.nan], 'capped2': [2,0,np.nan,-9999],'signed':[2,0,-3,np.nan]}
df = pd.DataFrame(data=d, index=index)
df_right = df.filter(regex=("capped.*")).clip(lower=0)
df_left = df.drop(list(df_right.columns), 1)
df_out = df_left.merge(df_right,left_index=True,right_index=True,how="outer")
df_out
有更好的方法吗?我的猜测是,这可以替换为一行而不是3,直接替换df中的值。
答案 0 :(得分:5)
选项1
将pd.DataFrame.update
与pd.DataFrame.clip
一起使用
这样就编辑了df
df.update(df.filter(regex="^capped.*$").clip(lower=0))
df
capped1 capped2 signed
1 1.0 2.0 2.0
2 0.0 0.0 0.0
3 0.0 NaN -3.0
4 NaN 0.0 NaN
选项2
使用pd.DataFrame.assign
和np.maximum
这会生成副本并单独留下df
我使用np.maximum
作为变种。我可以使用pd.DataFrame.clip
请注意,我使用**
将np.maximum
返回的数据帧解包为字典。它相当于**{c: s for c, s in d.iteritems()}
,其中d
是np.maximum
df.assign(**np.maximum(df.filter(regex='^capped.*'), 0))
capped1 capped2 signed
1 1.0 2.0 2.0
2 0.0 0.0 0.0
3 0.0 NaN -3.0
4 NaN 0.0 NaN
答案 1 :(得分:3)
您可以获取列名称,然后仅在子集中应用函数:
cols = df.columns[df.columns.str.contains('^capped.*')]
print (cols)
Index(['capped1', 'capped2'], dtype='object')
df[cols] = df[cols].clip(lower=0)
print (df)
capped1 capped2 signed
1 1.0 2.0 2.0
2 0.0 0.0 0.0
3 0.0 NaN -3.0
4 NaN 0.0 NaN
类似的解决方案:
m = df.columns.str.contains('^capped.*')
print (m)
[ True True False]
df.loc[:, m] = df.loc[:, m].clip(lower=0)
print (df)
capped1 capped2 signed
1 1.0 2.0 2.0
2 0.0 0.0 0.0
3 0.0 NaN -3.0
4 NaN 0.0 NaN
Jon Clements评论的好主意 - 使用regex
没有必要,可以使用startswith
:
cols = df.columns[df.columns.str.startswith('capped')]
m = df.columns.str.startswith('capped')