如何根据两个条件提取行
How to extract rows based on two conditions
嗨,我有一个数据集 d1。
import pandas as pd
d1 = {
'customers': pd.Series([1, 1, 1, 2, 2, 3, 3, 4, 4]),
'channel': pd.Series(['a', 'a', 'b', 'c', 'a', 'a', 'b', 'b', 'c']),
'freq': pd.Series([3, 3, 3, 2, 2, 2, 2, 2, 2])
}
d1=pd.DataFrame(d1)
我想获取只使用过两个不同渠道的客户列表,渠道 'a' 是必需的。
例如..第一个客户使用了两个不同的渠道'a'&'b'
第二位客户使用了 'a' & 'c' 第三位客户使用了 'a' & 'b'。但是客户4没有用过渠道'a'等等....
提前致谢
这有点令人费解,但基本上我们使用 groupby、过滤和 2 级布尔索引对 df 执行乘法过滤:
In [140]:
d1[d1.customers.isin(d1[d1.channel=='a'].customers)].groupby('customers').filter(lambda x: x['channel'].nunique() == 2)
Out[140]:
channel customers freq
0 a 1 3
1 a 1 3
2 b 1 3
3 c 2 2
4 a 2 2
5 a 3 2
6 b 3 2
分解:
In [141]:
# filter out just those that have channel a
d1[d1.channel=='a']
Out[141]:
channel customers freq
0 a 1 3
1 a 1 3
4 a 2 2
5 a 3 2
In [144]:
# we want these customer ids
d1[d1.channel=='a'].customers
Out[144]:
0 1
1 1
4 2
5 3
Name: customers, dtype: int64
In [146]:
# perform an additional filtering so we only want customers who have channel a
d1[d1.customers.isin(d1[d1.channel=='a'].customers)]
Out[146]:
channel customers freq
0 a 1 3
1 a 1 3
2 b 1 3
3 c 2 2
4 a 2 2
5 a 3 2
6 b 3 2
以上是对客户进行分组,然后我们可以应用一个过滤器,其中唯一 (nunique) 客户的数量等于 2
慢一点,例如如果您打算进一步复杂化过滤逻辑,这是一种替代方法(而且公认的不太优雅),它尽量不成为单行代码:
def func(x):
vals = x['channel'].value_counts()
if 'a' in vals and len(vals) == 2:
return True
return False
mask = d1.groupby('customers').apply(func)
print mask
输出:
customers
1 True
2 True
3 True
4 False
dtype: bool
现在取决于您希望输出的方式:
# Get a list of customers, like
# [1, 2, 3]
target_customers = [k for k, v in mask.to_dict().iteritems() if v]
# Get a slice of the original DataFrame
print d1[d1['customers'].isin(target_customers)]
嗨,我有一个数据集 d1。
import pandas as pd
d1 = {
'customers': pd.Series([1, 1, 1, 2, 2, 3, 3, 4, 4]),
'channel': pd.Series(['a', 'a', 'b', 'c', 'a', 'a', 'b', 'b', 'c']),
'freq': pd.Series([3, 3, 3, 2, 2, 2, 2, 2, 2])
}
d1=pd.DataFrame(d1)
我想获取只使用过两个不同渠道的客户列表,渠道 'a' 是必需的。
例如..第一个客户使用了两个不同的渠道'a'&'b'
第二位客户使用了 'a' & 'c' 第三位客户使用了 'a' & 'b'。但是客户4没有用过渠道'a'等等....
提前致谢
这有点令人费解,但基本上我们使用 groupby、过滤和 2 级布尔索引对 df 执行乘法过滤:
In [140]:
d1[d1.customers.isin(d1[d1.channel=='a'].customers)].groupby('customers').filter(lambda x: x['channel'].nunique() == 2)
Out[140]:
channel customers freq
0 a 1 3
1 a 1 3
2 b 1 3
3 c 2 2
4 a 2 2
5 a 3 2
6 b 3 2
分解:
In [141]:
# filter out just those that have channel a
d1[d1.channel=='a']
Out[141]:
channel customers freq
0 a 1 3
1 a 1 3
4 a 2 2
5 a 3 2
In [144]:
# we want these customer ids
d1[d1.channel=='a'].customers
Out[144]:
0 1
1 1
4 2
5 3
Name: customers, dtype: int64
In [146]:
# perform an additional filtering so we only want customers who have channel a
d1[d1.customers.isin(d1[d1.channel=='a'].customers)]
Out[146]:
channel customers freq
0 a 1 3
1 a 1 3
2 b 1 3
3 c 2 2
4 a 2 2
5 a 3 2
6 b 3 2
以上是对客户进行分组,然后我们可以应用一个过滤器,其中唯一 (nunique) 客户的数量等于 2
慢一点,例如如果您打算进一步复杂化过滤逻辑,这是一种替代方法(而且公认的不太优雅),它尽量不成为单行代码:
def func(x):
vals = x['channel'].value_counts()
if 'a' in vals and len(vals) == 2:
return True
return False
mask = d1.groupby('customers').apply(func)
print mask
输出:
customers
1 True
2 True
3 True
4 False
dtype: bool
现在取决于您希望输出的方式:
# Get a list of customers, like
# [1, 2, 3]
target_customers = [k for k, v in mask.to_dict().iteritems() if v]
# Get a slice of the original DataFrame
print d1[d1['customers'].isin(target_customers)]