Python 使用三元条件运算符对系列进行字符串连接

Python string concatenation on series with ternary condition operator

我想根据其他列的串联将代表 URL 的列添加到 Pandas 数据框。另外我想添加一个条件。

目前是这样的

matches['url'] = 'http://www.example.org' +
                matches['column1'] + 
                '/' +
                (matches['id'].str[-3:] if matches['id'].str.contains('M|-0') else matches['id'].str[-4:]) +
                '/xyz.pdf'

我遇到问题的情况是:(matches['id'].str[-3:] if matches['id'].str.contains('M|-0') else matches['id'].str[-4:])

这应该执行以下操作:如果 matches['id'] 包含字符串 M-0 那么 matches['id'].str[-3:] 应该发生(即取字符串的最后 3 个字符matches['id'] 列,否则 matches['id'].str[-4:] 应该发生。

但是,我收到以下错误:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

我知道我可以用 apply() 创建一个中间列并在其中编码条件。但我想用一个漂亮的单线来做,我想我离解决方案不远了。感谢您的帮助。

我认为你需要 numpy.whereSeries 完美搭配的东西:

mask = matches['id'].str.contains('M|-0') 
matches['url'] = 'http://www.example.org' + matches['column1'] + '/' +
                  np.where(mask, matches['id'].str[-3:], matches['id'].str[-4:]) + '/xyz.pdf'

样本:

matches = pd.DataFrame({'id':['2010-M012','2010-1234','2010-1234'],
                        'column1':['s','d','m']})
print (matches)                 
  column1         id
0       s  2010-M012
1       d  2010-1234
2       m  2010-1234

mask = matches['id'].str.contains('M|-0') 
matches['url'] = 'http://www.example.org' + matches['column1'] + '/' + \
                  np.where(mask, matches['id'].str[-3:], matches['id'].str[-4:]) + '/xyz.pdf'

matches['url1'] = 'http://www.example.org' + matches['column1'] + '/' + \
                   matches['id'].map(lambda x : x[-3:] if (('M' in x) or ('-0' in x)) else x[-4:]) + '/xyz.pdf'

matches['url2'] = matches.apply(lambda x: 'http://www.example.org{}/{}/xyz.pdf'.format(x['column1'], x['id'][-3:] if (('M' in x['id']) or ('-0' in x['id'])) else x['id'][-4:]), axis=1)


print (matches)
  column1         id                                   url  \
0       s  2010-M012   http://www.example.orgs/012/xyz.pdf   
1       d  2010-1234  http://www.example.orgd/1234/xyz.pdf   
2       m  2010-1234  http://www.example.orgm/1234/xyz.pdf   

                                   url1                                  url2  
0   http://www.example.orgs/012/xyz.pdf   http://www.example.orgs/012/xyz.pdf  
1  http://www.example.orgd/1234/xyz.pdf  http://www.example.orgd/1234/xyz.pdf  
2  http://www.example.orgm/1234/xyz.pdf  http://www.example.orgm/1234/xyz.pdf  

时间:

matches = pd.DataFrame({'id':['2010-M012','2010-1234','2010-1234'],
                        'column1':['s','d','m']})
#[30000 rows x 2 columns]
matches = pd.concat([matches]*10000).reset_index(drop=True)

In [168]: %timeit matches['url'] = 'http://www.example.org' + matches['column1'] + '/' + np.where(matches['id'].str.contains('M|-0'), matches['id'].str[-3:], matches['id'].str[-4:]) + '/xyz.pdf'
10 loops, best of 3: 50.9 ms per loop

In [169]: %timeit matches['url1'] = 'http://www.example.org' + matches['column1'] + '/' + matches['id'].map(lambda x : x[-3:] if (('M' in x) or ('-0' in x)) else x[-4:]) + '/xyz.pdf'
10 loops, best of 3: 22.1 ms per loop

In [170]: %timeit matches['url2'] = matches.apply(lambda x: 'http://www.example.org{}/{}/xyz.pdf'.format(x['column1'], x['id'][-3:] if (('M' in x['id']) or ('-0' in x['id'])) else x['id'][-4:]), axis=1)
1 loop, best of 3: 1.07 s per loop

变化:

(matches['id'].str[-3:] if matches['id'].str.contains('M|-0') else matches['id'].str[-4:])

至:

np.where(matches['id'].str.contains('M|-0'), matches['id'].str[-3:],matches['id'].str[-4:])

看看它是否有效。