矢量化操作以根据 Python 中数据框中的不同条件创建多个新列

Vectorize operation to create multiple new columns based on different conditions in a dataframe in 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,type 总是 'Email' 并且 status 有多个值,我只对其中感兴趣'Open' 和 'Click'.

对于记录 R2,type 总是 'Event' 并且 status 有多个值,我只对其中感兴趣'Open' 和 'Registered'.

但是对于记录 R3,type 可以有多个值,即 'search'、'story' 等,每个类型都有不同的 status 我感兴趣的值。

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

我已经使用 iterrows 遍历数据帧的每一行并替换值。我知道这不是最有效的方法,但我无法制定如何使用 apply 方法或进行矢量化来加速计算。

如果您知道 faster/better 方法,请提出建议。

下面是我的代码:

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)

注意:您也可以像np.where一样使用loc,分4步

您可以创建所有新列:

new_cols = [col.lower() + '_cnt' for col in set(df['Type'])]
df = df.assign({col: 0 for col in new_cols})

然后使用以下命令将您的特定条件填入 1:

df.loc[(df['Record'] == 'R1') & (df['Type'] == 'Story') & df['Status'].isin(['Open', 'Click']), 'email_cnt'] = 1

所以对于你所拥有的所有条件。