熊猫:根据包含列表的列过滤行

时间:2019-11-12 11:15:04

标签: python python-3.x pandas

如何根据另一个列值过滤数据框中的行?

我有一个数据框,

ip_df:
     class    name     marks          min_marks  min_subjects
0    I        tom      [89,85,80,74]  80         2
1    II       sam      [65,72,43,40]  85         1

基于“ min_subject”和“ min_marks”的列值,应过滤该行。

  • 对于索引0,“ min_subjects”为“ 2”,“ marks”列中的至少2个元素应大于80,即“ min_marks”列,然后必须添加一个名为“ flag”的新列添加为1

  • 对于索引1,“ min_subjects”为“ 1”,“ marks”列中的至少1个元素应大于85,即“ min_marks”列,然后必须新建一个名为“ flag”的列添加为0(即flag = 0,因为此处不满足条件)

最终结果应该是

op_df:
     class    name     marks          min_marks  min_subjects flag
0    I        tom      [89,85,80,74]  80         2            1
1    II       sam      [65,72,43,40]  85         1            0

有人可以帮助我在数据框架中实现同样的目标吗?

2 个答案:

答案 0 :(得分:3)

将列表理解与zip乘以3列,比较生成器中的每个值和sum的计数,最后用最小标记进行比较并转换为整数:

df['flag'] = [1 if sum(x > c for x in a) >= b else 0 
                 for a, b, c in zip(df['marks'], df['min_subjects'], df['min_marks'])]

int转换为0,1的布尔值的替代方法:

df['flag'] = [int(sum(x > c for x in a) >= b)
                 for a, b, c in zip(df['marks'], df['min_subjects'], df['min_marks'])]

或使用numpy解决方案:

df['flag'] = [int(np.sum(np.array(a) > c) >= b)
                  for a, b, c in zip(df['marks'], df['min_subjects'], df['min_marks'])]

print (df)
  class name             marks  min_marks  min_subjects  flag
0     I  tom  [89, 85, 80, 74]         80             2     1
1    II  sam  [65, 72, 43, 40]         85             1     0

答案 1 :(得分:1)

要避免for循环并充分利用并行计算,可以使用新函数explode(Pandas 0.25.0):

df1 = df.explode('marks')
print(df1)

输出:

  class name marks  min_marks  min_subjects
0     I  tom    89         80             2
0     I  tom    85         80             2
0     I  tom    80         80             2
0     I  tom    74         80             2
1    II  sam    65         85             1
1    II  sam    72         85             1
1    II  sam    43         85             1
1    II  sam    40         85             1

比较列marksmin_marks

df['flag'] = df1['marks'].gt(df1['min_marks'])\
.groupby(df1.index).sum().ge(df['min_subjects']).astype(int)

print(df)

输出:

  class name             marks  min_marks  min_subjects  flag
0     I  tom  [89, 85, 80, 74]         80             2     1
1    II  sam  [65, 72, 43, 40]         85             1     0