【发布时间】:2017-05-11 18:38:21
【问题描述】:
我有一个包含超过 600 万个观察值的数据框,其中 20 列是权重,将应用于单个得分列。即,Wgt1 * Wgt2 * Wgt3...* 得分。此外,并非每个权重都适用于每个观察,因此我创建了 20 个代表权重掩码的列。即 (Wgt1*Msk1) * (Wgt2*Msk2) * (Wgt3*Msk3) ... 得分。当掩码为0时,权重不适用;当掩码为1时,适用。
对于数据框中的每一行,我想: 1、检查2个表明该行应该被处理的限定条件 2、求权重的乘积,以对应掩码(ttl_wgt)的存在为准 3、将此乘积乘以分数(prob),得出最终加权分数
为此,我创建了一个用户定义函数:
import functools
import operator
import time
def mymult(a):
ttl_wgt = float('NaN') #Initialize to NaN
if ~np.isnan(a['ID']): #condition 1, only process if an ID is present
if a['prob'] > -1.0: #condition 2, only process if our unweighted score is NOT -1.0
b = np.where(a[msks] ==1)[0] #index for which of our masks is 1?
ttl_wgt = functools.reduce(operator.mul, a[np.asarray(wgt_nms)[b]], 1)
return ttl_wgt
我在开发过程中内存不足,所以我决定一次将它分成 500000 行。我使用 lambda 函数来应用到块:
msks = ['Msk1','Msk2','Msk3','Msk4',...,'Msk20']
wgt_nms = ['Wgt1','Wgt2','Wgt3','Wgt4',...,'Wgt20']
print('Determining final weights...')
chunksize = 500000 #we'll operate on this many rows at a time
start_time = time.time()
ttl_wgts = [] #initialize list to hold weight products
for i in range(0,len(df),chunksize):
ttl_wgts.extend(df[i:(i+chunksize)].apply(lambda x: mymult(x), axis=1))
print("--- %s seconds ---" % (time.time() - start_time)) #Expect between 30 and 40 minutes
print('Done!')
然后我将 ttl_wgts 列表分配为数据框中的新列,并做权重 * 初始分数的最终乘积。
#Initialize the fields
#Might not be necessary or evenuseful
df['ttl_wgt'] = float('NaN')
df['wgt_prob'] = float('NaN')
df['ttl_wgt'] = ttl_wgts
df['wgt_prob'] = df['ttl_wgt'] * df['prob']
我在multiplying elements in a list 上查看了之前的帖子。这是值得深思的好东西,但我无法将其转化为对我 600 万以上的观察更有效的东西。我还应该考虑其他方法吗?
按照建议添加示例 df
数据框的样本可能看起来像这样,只有 3 个掩码/权重:
df = pd.DataFrame({'id': [999999999,136550,80010170,80010177,90002408,90002664,16207501,62992,np.nan,80010152],
'prob': [-1,0.180274382,0.448361456,0.000945058,0.005060279,0.009893078,0.169686288,0.109541453,0.117907763,0.266242921],
'Msk1': [0,1,1,1,0,0,1,0,0,0],
'Msk2': [0,0,1,0,0,0,0,1,0,0],
'Msk3': [1,0,0,0,1,1,0,0,1,1],
'Wgt1': [np.nan,0.919921875,1.08984375,1.049804688,np.nan,np.nan,np.nan,0.91015625,np.nan,0.810058594],
'Wgt2': [np.nan,1.129882813,1.120117188,0.970214844,np.nan,np.nan,np.nan,1.0703125,np.nan,0.859863281],
'Wgt3': [np.nan,1.209960938,1.23046875,1,np.nan,np.nan,np.nan,1.150390625,np.nan,0.649902344]
})
在第一次观察中,prob 字段为 -1,因此不会处理该行。在第二个观察中,Msk1 打开,而 Msk2 和 Msk3 关闭。因此,最终权重将是 Wgt1 = 0.919922 的值。在第 3 行,Mask1 和 Msk2 处于打开状态,而 Msk3 处于关闭状态。因此最终权重为 Wgt1*Wgt2 = 1.089844*1.120117 = 1.220752。
【问题讨论】:
-
这是一个非常令人困惑的问题,如果您提供一个非常小的数据子集并提供所需的结果会更好。了解如何制作good reproducible pandas example
-
这个问题已经有点长了,所以我来回包括一个例子。感谢您的提醒,我添加了一个希望能澄清情况。
标签: python pandas dataframe lambda iteration