首页 > 解决方案 > 矢量化操作以在 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,可以有多个类型的值,即“搜索”、“故事”等,并且每种类型都有我感兴趣的不同状态值。

我想在以下条件下创建新的计数列:

我已经使用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)

标签: pythonpandasdataframevectorization

解决方案


您可以列出您的条件并从中创建一个 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


推荐阅读