数据框列值与列表的比较

18
考虑以下数据框:

df = pd.DataFrame({'A': [1, 1, 2, 2, 3, 3],
                   'B': [10, 15, 20, 25, 30,35],
                   'C': [100, 150, 200, 250, 300, 350]})

这是获取每个分组(A列)的第一行的C列值的代码:

firsts = df.groupby('A').first()['C']

首先是:(100, 200, 300)

现在我想添加一列,如果行的列C的值在firsts中,则该列将为1,否则为0

A B C D
1 10 100 1
1 15 150 0
2 20 200 1
2 25 250 0
3 30 300 1
3 35 350 0

我使用了这个:

df['D'] = df['C'].apply(lambda x: 1 if x in firsts else 0)
但是输出结果为:
A B C D
1 10 100 0
1 15 150 0
2 20 200 0
2 25 250 0
3 30 300 0
3 35 350 0
如果有人能解释为什么我的解决方案是错误的以及这个问题的实际解决方案,我会非常感激。
4个回答

25
你可以使用 isin 方法:

isin 方法可用于筛选包含在指定列表中的数据。

df['D'] = df.C.isin(firsts).astype(int)

df
#   A   B   C   D
#0  1   10  100 1
#1  1   15  150 0
#2  2   20  200 1
#3  2   25  250 0
#4  3   30  300 1
#5  3   35  350 0
你的方法失败的原因是Python in 运算符检查Series的索引而不是值,这与字典的工作方式相同。
firsts
#A
#1    100
#2    200
#3    300
#Name: C, dtype: int64

1 in firsts
# True

100 in firsts
# False

2 in firsts
# True

200 in firsts
# False

按照以下方式修改您的方法即可:

firstSet = set(firsts)
df['C'].apply(lambda x: 1 if x in firstSet else 0)

#0    1
#1    0
#2    1
#3    0
#4    1
#5    0
#Name: C, dtype: int64

5
TL;DR:(简单来说)
df['newColumn'] = np.where((df.compareColumn.isin(yourlist)), TrueValue, FalseValue)

另一种一步方法是使用np.where()isin函数。

import pandas as pd
import numpy as np

df = pd.DataFrame({'A': [1, 1, 2, 2, 3, 3],
                   'B': [10, 15, 20, 25, 30,35],
                   'C': [100, 150, 200, 250, 300, 350]})

df['D'] = np.where((df.B.isin(firsts)), 1, 0)

我们使用isin的返回值作为条件,使用np.where()来返回以下结果:
  • 1表示True
  • 0表示False
并将它们赋值给同一个数据框中的新列df['D']注意:np.where允许使用位运算符和替换情况进行更复杂的条件判断,例如在False时执行“绕过”操作。
df['col1'] = np.where(((df['col1'] == df['col2']) &
                       (~df['col1'].str.startswith('r'))),
                       'replace', df['col1'])


1

你也可以使用.transform('first')来一步完成:

In [280]: df['D'] = df.groupby('A')['C'].transform('first').eq(df['C']).astype(np.int8)

In [281]: df
Out[281]:
   A   B    C  D
0  1  10  100  1
1  1  15  150  0
2  2  20  200  1
3  2  25  250  0
4  3  30  300  1
5  3  35  350  0
说明:GroupBy.transform('func')将返回一个向量,其长度与原始数据框相同,应用了func
In [14]: df.groupby('A')['C'].transform('first')
Out[14]:
0    100
1    100
2    200
3    200
4    300
5    300
Name: C, dtype: int64

In [15]: df.groupby('A')['C'].transform('max')
Out[15]:
0    150
1    150
2    250
3    250
4    350
5    350
Name: C, dtype: int64

In [16]: df.groupby('A')['C'].transform('min')
Out[16]:
0    100
1    100
2    200
3    200
4    300
5    300
Name: C, dtype: int64

In [17]: df.groupby('A')['C'].transform('mean')
Out[17]:
0    125
1    125
2    225
3    225
4    325
5    325
Name: C, dtype: int64

In [18]: df.groupby('A')['C'].transform('sum')
Out[18]:
0    250
1    250
2    450
3    450
4    650
5    650
Name: C, dtype: int64

请问一下,这里的'transform('first')'是什么意思?(我找不到transform的简单解释) - Mehrdad Salimi
@MehrdadSComputer,我已经添加了一份说明——希望现在更清楚了。 - MaxU - stand with Ukraine
谢谢。所以它有点像“apply”函数。 - Mehrdad Salimi

-1

firsts 是 pandas series,所以当我们使用 in 来搜索值时,它会在索引列表中搜索该值。为了解决这个问题,我们可以将 firsts 转换成列表或数组。

%timeit df['D'] = df['C'].apply(lambda x: 1 if x in firsts.values else 0)

每次循环314微秒±17.3微秒(平均值±7次运行的标准差,每次1000次循环)

或者

%timeit df['D'] = df['C'].apply(lambda x: 1 if x in list(firsts) else 0)

每次循环301微秒±11.2微秒(平均值±7次运行的标准差,每次1000次循环)

或者

%timeit df['D'] = list(map(lambda x: 1 if x in list(firsts) else 0,list(df['C'])))

每个循环27.6微秒±1.02微秒(平均值±7次运行的标准偏差,每个循环10000次)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接