For 和 if 循环组合在 Pandas 中花费大量时间(数据操作)
For and if loop combination takes lot of time in Pandas (Data manipulation)
我有两个数据集,每个数据集大约有 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
您可以在 'rid' 上将 df2 与 df1 的一个子集(因为您只需要 tv 列,您也可以在没有任何子集的情况下传递 df1)进行左合并,然后计算中值和填充值:
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
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”和“sid”值是键,中位数和匹配的“tv”值是字典值。接下来,我们将df2中的“tv”值替换为分别是 rid 和 sid 键(因为它们是字典键),因此可以通过调用 .replace()
.
轻松地将其替换为正确的 tv 值
不要在 pandas 中使用 for 循环,众所周知这很慢。这样您就无法从已进行的所有内部优化中获益。
尝试使用拆分-应用-组合模式:
- 将df1拆分成sid计算中位数:
df1.groupby('sid')['tv'].median()
- 在 df1 上加入 df2:
df2.join(df1.set_index('rid'), on='rid')
- 用步骤 1 中计算的中位数填充 NaN 值。
(尚未测试代码)。
我有两个数据集,每个数据集大约有 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
您可以在 'rid' 上将 df2 与 df1 的一个子集(因为您只需要 tv 列,您也可以在没有任何子集的情况下传递 df1)进行左合并,然后计算中值和填充值:
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
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”和“sid”值是键,中位数和匹配的“tv”值是字典值。接下来,我们将df2中的“tv”值替换为分别是 rid 和 sid 键(因为它们是字典键),因此可以通过调用 .replace()
.
不要在 pandas 中使用 for 循环,众所周知这很慢。这样您就无法从已进行的所有内部优化中获益。
尝试使用拆分-应用-组合模式:
- 将df1拆分成sid计算中位数:
df1.groupby('sid')['tv'].median()
- 在 df1 上加入 df2:
df2.join(df1.set_index('rid'), on='rid')
- 用步骤 1 中计算的中位数填充 NaN 值。
(尚未测试代码)。