矢量化操作以根据 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 我感兴趣的值。
我想在以下条件下创建新的计数列:
如果记录为'R1',则email_cnt = 1,否则为0
如果记录为'R2',则event_cnt = 1,否则为0
如果记录为 'R3' 且类型为 'Story',则 story_cnt = 1,否则为 0
如果记录为 'R3' 且类型为 'Search',则 search_cnt = 1,否则为 0,依此类推所有不同的 R3 类型。
我已经使用 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
所以对于你所拥有的所有条件。
我有一个如下所示的数据框:
+-----+---------+--------+-------------+
| 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 我感兴趣的值。
我想在以下条件下创建新的计数列:
如果记录为'R1',则email_cnt = 1,否则为0
如果记录为'R2',则event_cnt = 1,否则为0
如果记录为 'R3' 且类型为 'Story',则 story_cnt = 1,否则为 0
如果记录为 'R3' 且类型为 'Search',则 search_cnt = 1,否则为 0,依此类推所有不同的 R3 类型。
我已经使用 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
所以对于你所拥有的所有条件。