在 pandas 数据框中编写用户定义的 fillna 函数,以用条件填充 np.nan 不同的值
Write a user defined fillna function in pandas dataframe to fill np.nan different values with conditions
考虑以下 pandas 数据帧:
import pandas as pd
change = [0.475, 0.625, 0.1, 0.2, -0.1, -0.75, 0.1, -0.1, 0.2, -0.2]
position = [1.0, 1.0, nan, nan, nan, -1.0, nan, nan, nan, nan]
date = ['20150101', '20150102', '20150103', '20150104', '20150105', '20150106', '20150107', '20150108', '20150109', '20150110']
pd.DataFrame({'date': date, 'position': position, 'change': change})
产出
date change position
20150101 0.475 1
20150102 0.625 1
20150103 0.1 np.nan
20150104 0.2 np.nan
20150105 -0.1 np.nan
20150106 -0.75 -1
20150107 0.1 np.nan
20150108 -0.1 np.nan
20150109 0.2 np.nan
20150110 -0.2 np.nan
我想填写以下规则:
对于"position"值为np.nan的行,如果"change"的值与position的最后一个非空值的符号相同(change * position >0,比如0.1*1和0.2*1 >0),我们用最后一个非空值填充。
对于"position"值为np.nan的行,如果"change"的值与position的最后一个非空值的符号相同(改变* position <=0 比如-1*0.1),我们填0.
一个np.nan补0后,后面的np.nan也补0
以下是示例数据框的预期结果:
date change position
20150101 0.475 1
20150102 0.625 1
20150103 0.1 1
20150104 0.2 1
20150105 -0.1 0
20150106 -0.75 -1
20150107 0.1 0
20150108 -0.1 0
20150109 0.2 0
20150110 -0.2 0
编辑:
我开发的方法如下:
while(any(np.isnan(x['position']))):
conditions = [(np.isnan(x['position'])) & (x['position'].shift(1) * x['change'] > 0),
(np.isnan(x['position'])) & (x['position'].shift(1) * x['change'] <= 0)]
choices = [x['position'].shift(1), 0]
x['position'] = np.select(conditions, choices, default=x['position'])
但是如您所见,它不是很令人满意,如果您有 80,000,000 行数据,它会非常慢。
有什么建议吗?感谢您的帮助!
我认为您的代码非常可靠,主要问题是您迭代它的次数超出了您的需要。 shift()
一次只返回一行,但是如果您将其更改为 fillna(method='ffill')
那么您基本上会得到无限次的轮班,但只需要这样做一次而不是多次迭代(多少次迭代次数将取决于您的数据)。
conditions = [
(np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']>0),
(np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']<=0)]
但我相信您可以更进一步,通过在末尾添加另一个 fillna
来消除 while
:
conditions = [
(np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']>0),
(np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']<=0)]
choices=[x['position'].shift(1),0]
x['position'] = np.select(conditions,choices,default=x['position'])
x['position'] = x['position'].fillna(method='ffill')
在您的示例数据上,第一个更改比您的代码快约 2 倍,第二个约快 4 倍。我得到的答案和你一样,但当然你会想在真实数据上验证这一点。
考虑以下 pandas 数据帧:
import pandas as pd
change = [0.475, 0.625, 0.1, 0.2, -0.1, -0.75, 0.1, -0.1, 0.2, -0.2]
position = [1.0, 1.0, nan, nan, nan, -1.0, nan, nan, nan, nan]
date = ['20150101', '20150102', '20150103', '20150104', '20150105', '20150106', '20150107', '20150108', '20150109', '20150110']
pd.DataFrame({'date': date, 'position': position, 'change': change})
产出
date change position
20150101 0.475 1
20150102 0.625 1
20150103 0.1 np.nan
20150104 0.2 np.nan
20150105 -0.1 np.nan
20150106 -0.75 -1
20150107 0.1 np.nan
20150108 -0.1 np.nan
20150109 0.2 np.nan
20150110 -0.2 np.nan
我想填写以下规则:
对于"position"值为np.nan的行,如果"change"的值与position的最后一个非空值的符号相同(change * position >0,比如0.1*1和0.2*1 >0),我们用最后一个非空值填充。
对于"position"值为np.nan的行,如果"change"的值与position的最后一个非空值的符号相同(改变* position <=0 比如-1*0.1),我们填0.
一个np.nan补0后,后面的np.nan也补0
以下是示例数据框的预期结果:
date change position
20150101 0.475 1
20150102 0.625 1
20150103 0.1 1
20150104 0.2 1
20150105 -0.1 0
20150106 -0.75 -1
20150107 0.1 0
20150108 -0.1 0
20150109 0.2 0
20150110 -0.2 0
编辑:
我开发的方法如下:
while(any(np.isnan(x['position']))):
conditions = [(np.isnan(x['position'])) & (x['position'].shift(1) * x['change'] > 0),
(np.isnan(x['position'])) & (x['position'].shift(1) * x['change'] <= 0)]
choices = [x['position'].shift(1), 0]
x['position'] = np.select(conditions, choices, default=x['position'])
但是如您所见,它不是很令人满意,如果您有 80,000,000 行数据,它会非常慢。
有什么建议吗?感谢您的帮助!
我认为您的代码非常可靠,主要问题是您迭代它的次数超出了您的需要。 shift()
一次只返回一行,但是如果您将其更改为 fillna(method='ffill')
那么您基本上会得到无限次的轮班,但只需要这样做一次而不是多次迭代(多少次迭代次数将取决于您的数据)。
conditions = [
(np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']>0),
(np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']<=0)]
但我相信您可以更进一步,通过在末尾添加另一个 fillna
来消除 while
:
conditions = [
(np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']>0),
(np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']<=0)]
choices=[x['position'].shift(1),0]
x['position'] = np.select(conditions,choices,default=x['position'])
x['position'] = x['position'].fillna(method='ffill')
在您的示例数据上,第一个更改比您的代码快约 2 倍,第二个约快 4 倍。我得到的答案和你一样,但当然你会想在真实数据上验证这一点。