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

Posted

技术标签:

【中文标题】使用三元条件运算符对系列进行 Python 字符串连接【英文标题】:Python string concatenation on series with ternary condition operator 【发布时间】:2017-12-04 01:30:24 【问题描述】:

我想添加一个列,该列应该表示基于其他列连接的 Pandas 数据框的 URL。另外我想添加一个条件。

目前是这样的

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:] 应该发生(即,取matches['id'] 列的最后3 个字符,否则取matches['id'].str[-4:]应该发生。

但是,我收到以下错误:

ValueError:Series 的真值不明确。使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()。

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

【问题讨论】:

我猜你应该在创建字符串之前将字符串的部分构造为变量。在创建字符串时,使用.format() 你不能那样做,因为三元运算符没有向量化。它同时对整个系列执行 if-then,而不是对每个单独的元素。您必须使用 .map.apply 单独构建字符串的各个部分。 【参考方案1】:

我认为你需要 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

【讨论】:

map() 方法效果很好。非常感谢您。有趣的是np.where() 不起作用。我做的和你做的一模一样。我没有遇到异常,但字符串匹配 (str.contains()) 似乎不起作用。你知道为什么会这样吗? 没有数据的难题。掩码返回正确的TrueFalse 值? 可能需要mask = matches['id'].str.contains('^M|^-0') 来匹配字符串的开头。 实际上我的字符串看起来像这样2010-M012(匹配)或2010-1234(不匹配)。但我刚刚发现map() 对我也不起作用.. 它总是匹配字符串,即使M-0 没有出现。 @beta - 地图解决方案获胜,检查时间。【参考方案2】:

变化:

(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:])

看看它是否有效。

【讨论】:

以上是关于使用三元条件运算符对系列进行 Python 字符串连接的主要内容,如果未能解决你的问题,请参考以下文章

python条件(三元)运算符

python 三元运算

python 三元运算符

Python 三元运算

python中的三元运算

python-三元运算