熊猫-选择其他列满足两个条件的索引

时间:2020-01-17 14:40:13

标签: python pandas

我不确定问题的措词是否足够准确,我希望代码示例可以更好地解释问题。

我有数据框:

                                 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中包含两者 archivelinks字符串的索引(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的解决方案都是好的。

3 个答案:

答案 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']