在某些条件下检查数据框中是否存在值的有效方法

时间:2019-04-18 14:58:01

标签: python pandas

我有一个包含工作人员的相当大的数据框(2000万行)。考虑到他们以前可能曾在其他公司工作,其中一些工人出现了多次。对于每个工人,我都有关于名字,姓氏(列: first_name last_name )和每个作业的开始日期( started_working_date )的信息。我想在数据框( past_experience )中创建一个新列,以标记以前在任何公司受雇的工人。

为此,我必须检查数据框中的每个工人是否在同一数据框中有一行具有相同的名字和姓氏,并且开始日期比所考虑的日期更早。

数据框如下所示:

   first_name  last_name started_working_date
0  Bob         J         1995-01-01
1  John        S         2000-01-01
1  Mark        L         2001-01-01
1  Bob         J         1997-01-01

理想的结果应该是:

   first_name  last_name  started_working_date  past_experience
0  Bob         J          1995-01-01            0
1  John        S          2000-01-01            0
1  Mark        L          2001-01-01            0
1  Bob         J          1997-01-01            1

我试图编写一个非常简单的apply函数,该函数根据我的条件过滤数据帧,并根据结果数据帧的长度返回0或1。

def past_experience(row):
    filtered_df = my_df[(my_df['first_name'] == row['first_name']) & (my_df['last_name'] == row['last_name']) & (my_df['started_working_date'] < row['started_working_date'])]
    if filtered_df.shape[0]>0:
        return 1
    else:
        return 0

my_df['past_experience'] = my_df.apply(past_experience, axis=1)

这有效,但是效率极低。您能提出一个更好的解决方案吗?

2 个答案:

答案 0 :(得分:2)

我正在使用numpy广播,请注意,此方法仍然是o(n * n)检查,这意味着如果数据帧很大,内存将超过。

s1=my_df['first_name'].values
s2=my_df['last_name'].values
s3=my_df['started_working_date'].values

np.any((s1==s1[:,None])&(s2==s2[:,None])&(s3<s3[:,None]),1)

答案 1 :(得分:1)

尝试:

groups = df.groupby(['first_name','last_name'])
df['employed'] = groups.started_working_date.cumcount()

df['employed_shift'] = groups.employed.shift().fillna(0)

df['employed_changed'] = (df['employed'] != df['employed_shift'])

并输出:

+---+------------+-----------+----------------------+----------+----------------+
|   | first_name | last_name | started_working_date | employed | employ_changed |
+---+------------+-----------+----------------------+----------+----------------+
| 0 | Bob        | J         | 1995-01-01           |        0 | False          |
| 1 | John       | S         | 2000-01-01           |        0 | False          |
| 1 | Mark       | L         | 2001-01-01           |        0 | False          |
| 1 | Bob        | J         | 1997-01-01           |        1 | True           |
+---+------------+-----------+----------------------+----------+----------------+