我不确定问题的措词是否足够准确,我希望代码示例可以更好地解释问题。
我有数据框:
links title
url
https://example.com /feed.xml EXAMPLE
https://example.com /tags.html EXAMPLE
https://example.com /tags.html EXAMPLE
https://example.com /about EXAMPLE
https://example.com /feed.xml EXAMPLE
https://example.com /feed.xml EXAMPLE
https://example222.com /about/ EXAMPLE222
https://example222.com /about/ EXAMPLE222
https://example333.com /atom.xml EXAMPLE333
https://example333.com /archives EXAMPLE333
https://example333.com /about EXAMPLE333
https://example333.com /archives EXAMPLE333
索引设置为 url 。但我也可以将其视为具有数字索引的列。
如何仅选择在列.xml
中包含两者 archive
和links
字符串的索引(url)? < / p>
即。
https://example333.com /atom.xml EXAMPLE333
https://example333.com /archives EXAMPLE333
但不是
https://example222.com /about/ EXAMPLE222
https://example222.com /about/ EXAMPLE222
即使仅满足一个条件,显然.str.contains('archive|xml')
也会选择行。
在此示例中,它还会选择:
https://example.com /feed.xml EXAMPLE
https://example.com /tags.html EXAMPLE
这不是我想要的。
有或没有set_index
的解决方案都是好的。
答案 0 :(得分:1)
第一个想法是对Series
使用Series.str.extract
并转换为set
,如果每个组都存在,则按两个值比较
s = df['links'].str.extract('(archive|xml)', expand=False)
m = s.groupby(df['url']).apply(set) >= set(['xml','archive'])
然后Series.map
屏蔽原始数据并与其他条件链接
df = df[df['url'].map(m) & s.notna()]
#alternative
#df = df[df['url'].map(m) & df['links'].str.contains('archive|xml')]
print (df)
url links title
8 https://example333.com /atom.xml EXAMPLE333
9 https://example333.com /archives EXAMPLE333
11 https://example333.com /archives EXAMPLE333
如果要为每个url
添加唯一值,请添加DataFrame.drop_duplicates
:
df = df[df['url'].map(m) & s.notna()].drop_duplicates(['url','links'])
print (df)
url links title
8 https://example333.com /atom.xml EXAMPLE333
9 https://example333.com /archives EXAMPLE333
另一种方法应该在2个帮助器列中对匹配值进行计数,并测试两个列是否都与用DataFrame.all
比较总和的值相匹配:
a = df['links'].str.contains('archive')
b = df['links'].str.contains('xml')
mask = df.assign(a=a,b=b).groupby('url')['a','b'].transform('sum').gt(0).all(axis=1)
df = df[mask & (a | b)]
print (df)
8 https://example333.com /atom.xml EXAMPLE333
9 https://example333.com /archives EXAMPLE333
11 https://example333.com /archives EXAMPLE333
答案 1 :(得分:1)
进行分组,然后应用自定义聚合函数:
def summarize(group):
has_xml = group['links'].str.contains(r'\.xml')
has_archive = group['links'].str.contains('archive')
return group[has_xml | has_archive] if has_xml.any() and has_archive.any() else None
df.groupby('url').apply(summarize).reset_index(0, drop=True)
结果:
url links title
8 https://example333.com /atom.xml EXAMPLE333
9 https://example333.com /archives EXAMPLE333
11 https://example333.com /archives EXAMPLE333
答案 2 :(得分:1)
如果您只想获取符合条件的URL,则代码如下:
urls = df.groupby(level = 0).agg({'links': (lambda x: sum([(f in list(x.str.extract('(archive|xml)', expand=False))) for f in ['archive','xml']])==2)})['links']
print(urls)
Out[1]:
https://example.com False
https://example222.com False
https://example333.com True
Name: links, dtype: bool
print(list(urls[urls].index))
Out[2]:
['https://example333.com']