我有两个数据集,每个数据集大约有50万个观测值。我正在写下面的代码,似乎代码似乎永远不会停止执行。我想知道是否有更好的做法。欣赏输入。
下面是我的数据框架的示例格式。两个数据框架共享一组'sid'值,这意味着'df2'中的所有'sid'值将与'df1'中的'sid'值匹配。'tid'值和'rid'值('sid'和'tid'值的组合)不能同时出现在两个集合中
任务很简单。我想在df2中创建"tv"列。只要df2中的"rid"与"df1"中的"rid"匹配,df2中的"tv"列就会从df1中获取相应的"tv"值。如果不匹配,'df2'中的'tv'值将是'df1'中匹配'sid'子集的'tv'值的中位数。
事实上,我最初的任务包括在df2中创建一些类似的列,如'tv'(基于它们在'df1'中的值;这些列存在于'df1'中。
我相信我的代码包含for循环结合if else语句和多个值赋值语句,它需要永远执行。谢谢你的建议。
df1
sid tid rid tv
0 0 0 0-0 9
1 0 1 0-1 8
2 0 3 0-3 4
3 1 5 1-5 2
4 1 7 1-7 3
5 1 9 1-9 14
6 1 10 1-10 24
7 1 11 1-11 13
8 2 14 2-14 2
9 2 16 2-16 5
10 3 17 3-17 6
11 3 18 3-18 8
12 3 20 3-20 5
13 3 21 3-21 11
14 4 23 4-23 6
df2
sid tid rid
0 0 0 0-0
1 0 2 0-2
2 1 3 1-3
3 1 6 1-6
4 1 9 1-9
5 2 10 2-10
6 2 12 2-12
7 3 1 3-1
8 3 15 3-15
9 3 1 3-1
10 4 19 4-19
11 4 22 4-22
rids = [rid.split('-') for rid in df1.rid]
for r in df2.rid:
s,t = r.split('-')
if [s,t] in rids:
df2.loc[df2.rid== r,'tv'] = df1.loc[df1.rid == r,'tv']
else:
df2.loc[df2.rid== r,'tv'] = df1.loc[df1.sid == int(s),'tv'].median()
预期的df2如下:
sid tid rid tv
0 0 0 0-0 9.0
1 0 2 0-2 8.0
2 1 3 1-3 13.0
3 1 6 1-6 13.0
4 1 9 1-9 14.0
5 2 10 2-10 3.5
6 2 12 2-12 3.5
7 3 1 3-1 7.0
8 3 15 3-15 7.0
9 3 1 3-1 7.0
10 4 19 4-19 6.0
11 4 22 4-22 6.0
你可以在df2上留下一个子集(因为你只需要tv列,你也可以传递df1没有任何子集)的df1在'rid'上然后计算中位数和填充值:
out=df2.merge(df1[['rid','tv']],on='rid',how='left')
out['tv']=out['tv_y'].fillna(out['sid'].map(df1.groupby('sid')['tv'].median()))
out= out.drop(['tv_x','tid_y','tv_y'], axis=1)
out = out.rename(columns = {'tid_x': 'tid'})
out
或
既然你这么说了:
'df2'中的所有'sid'值将在'df1'中的'sid'值
因此,您也可以将它们留在['sid','rid']
上,然后通过使用map()
方法映射值,将tv的fillna()
值与df1 'tv'列的中位数合并:
out=df2.merge(df1,on=['sid','rid'],how='left')
out['tv']=out['tv_y'].fillna(out['sid'].map(df1.groupby('sid')['tv'].median()))
out= out.drop(['tv_x','tv_y'], axis=1)
out
输出:
sid tid rid tv
0 0 0 0-0 9.0
1 0 2 0-2 8.0
2 1 3 1-3 13.0
3 1 6 1-6 13.0
4 1 9 1-9 14.0
5 2 10 2-10 3.5
6 2 12 2-12 3.5
7 3 1 3-1 7.0
8 3 15 3-15 7.0
9 3 1 3-1 7.0
10 4 19 4-19 6.0
11 4 22 4-22 6.0
这是一个基于字典的没有任何循环的建议:
matching_values = dict(zip(df1['rid'][df1['rid'].isin(df2['rid'])], df1['tv'][df1['rid'].isin(df2['rid'])]))
df2[df2['rid'].isin(df1['rid'])]['tv'] = df2[df2['rid'].isin(df1['rid'])]['rid']
df2[df2['rid'].isin(df1['rid'])]['tv'].replace(matching_values)
median_values = df2[(~df2['rid'].isin(df1['rid']) & (df2['sid'].isin(df1['sid'])].groupby('sid')['tv'].median().to_dict()
df2[(~df2['rid'].isin(df1['rid']) & (df2['sid'].isin(df1['sid'])]['tv'] = df2[(~df2['rid'].isin(df1['rid']) & (df2['sid'].isin(df1['sid'])]['sid']
df2[(~df2['rid'].isin(df1['rid']) & (df2['sid'].isin(df1['sid'])]['tv'].replace(median_values)
这应该能奏效。这里的逻辑是,我们首先创建一个字典,其中的"rid"one_answers"sid"值是键和中值以及匹配的"tv"值是字典值。接下来,我们替换"电视"使用rid和sid键分别替换df2中的值(因为它们是字典键),因此可以通过调用.replace()
轻松地替换为正确的tv值。
不要在pandas中使用for循环,这是众所周知的很慢。这样你就不能从已经做过的所有内部优化中获益。
尝试使用split-apply-combine模式:
- 将df1拆分为sid计算中值:
df1.groupby('sid')['tv'].median()
- join df2 on df1:
df2.join(df1.set_index('rid'), on='rid')
- 用第1步计算的中位数填充NaN值。
(尚未测试代码)。