python - 矢量化操作以在 Python 中根据数据框中的不同条件创建多个新列
问题描述
我有一个如下所示的数据框:
+-----+---------+--------+-------------+
| Id | Record | Type | Status |
+-----+---------+--------+-------------+
| 111 | R1 | Email | Open |
| 123 | R2 | Event | Accepted |
| 234 | R3 | Story | Pending |
| 135 | R3 | Search | Click |
+-----+---------+--------+-------------+
It has around 1 million rows
Record列只能包含三个值,即“R1”、“R2”和“R3”。
对于记录 R1,类型始终是“电子邮件”,状态有多个值,我只对“打开”和“点击”感兴趣。
对于记录 R2,类型始终为“事件”,状态有多个值,我只对“打开”和“已注册”感兴趣。
但是对于记录 R3,可以有多个类型的值,即“搜索”、“故事”等,并且每种类型都有我感兴趣的不同状态值。
我想在以下条件下创建新的计数列:
如果记录是“R1”,则 email_cnt = 1,否则为 0
如果记录是“R2”,则 event_cnt = 1,否则为 0
如果记录是'R3'并且类型是'Story',那么story_cnt = 1,否则为0
如果记录是“R3”并且类型是“搜索”,那么对于所有不同的 R3 类型,search_cnt = 1,否则为 0,依此类推。
我已经使用iterrows来迭代每一行数据帧并替换这些值。我知道这不是最有效的方法,但我无法制定如何使用 apply 方法或进行矢量化来加快计算速度。
如果您知道更快/更好的方法,请提出建议。
下面是我的代码:
df = pd.read_csv('file.csv')
# Create new metrics columns
tempcols = ['email_cnt', 'event_cnt', 'dm_cnt', 'enc_cnt', 'exp_cnt', 'orgsearch_cnt', 'orgsocial_cnt', 'paidsm_cnt', 'paidsearch_cnt', 'pd_cnt', 'smrtroom_cnt', 'stry_cnt', 'tm_cnt']
# Append new metrics in the existing campaigns dataframe
df = pd.concat([df, pd.DataFrame(columns=tempcols)])
# Values of Status column that we need
status_vals = ['Accepted', 'Call Completed', 'Commented', 'Declined', 'Liked', 'Responded', 'Shared']
for index, row in df.iterrows():
if((row['Record']=='R1') & (row['Status'] in ['Open', 'Click'])):
df.at[index, 'email_cnt'] = 1
if((row['Record']=='R2') & (row['Status'] in ['Open', 'Registered'])):
df.at[index, 'event_cnt'] = 1
if(row['Record']=='R3'):
if((row['Type']=='Story') & (row['Status'] in status_vals)):
df.at[index, 'stry_cnt'] = 1
if((row['Type']=='Search') & (row['Status'] in status_vals+['Downloaded', 'Registered'])):
df.at[index, 'search_cnt'] = 1
if((row['Type']=='Experience') & (row['Status'] in status_vals)):
df.at[index, 'exp_cnt'] = 1
df.fillna(0, inplace=True)
解决方案
您可以列出您的条件并从中创建一个 DataFrame:
conditions=[
(df['Record'].eq('R1') & (df['Status'].isin(['Open', 'Click']))),
(df['Record'].eq('R2') & (df['Status'].isin(['Open', 'Registered']))),
(df['Record'].eq('R3') & df['Type'].eq('Story')),
(df['Record'].eq('R3') & df['Type'].eq('Search'))
]
out=pd.concat(conditions,axis=1).astype(int)
out.columns=['email_cnt', 'event_cnt', 'story_cnt', 'search_cnt']
或者
你可以使用np.where()
4次:
import numpy as np
df['email_cnt']=np.where((df['Record'].eq('R1') & (df['Status'].isin(['Open', 'Click']))),1,0)
df['event_cnt']=np.where((df['Record'].eq('R2') & (df['Status'].isin(['Open', 'Registered']))),1,0)
df['story_cnt']=np.where((df['Record'].eq('R3') & df['Type'].eq('Story')),1,0)
df['search_cnt']=np.where( (df['Record'].eq('R3') & df['Type'].eq('Search')),1,0)
注意:您也可以loc
在 4 个步骤中使用 like np.where
推荐阅读
- javascript - 分配默认道具时,状态不会通过 redux 更改
- arrays - 多选下拉列表和表单字段显示为数组?
- html - 在图像尺寸上使用 rem、em 和 px
- ios - 带有状态栏的错误位置 UIScrollView 内容
- vue.js - 具有可选值道具的组件
- node.js - 如何使用节点、createPresignedPost 和 fetch 将图像文件直接从客户端上传到 AWS S3
- c# - 在 Xamarin.iOS 中使用 C# 在带有核心图形的 UIView 中绘制“框架”时出现问题
- atlassian-sourcetree - SourceTree 认为开发分支是一个特性
- java - 如何根据关键字将解析的 JSON 消息的内容存储到字符串变量中?
- javascript - 通过输入 onBlur 停止搜索