我有一个带有文本列的pandas数据框。
我想创建一个新列,其中值以文本列中文本字符串的开头为条件。
所以如果文本列的第30个字符是:
=='xxx ... xxx'然后返回值1 /
=='yyy ... yyy'然后返回值2
=='zzz ... zzz'然后返回值3
如果以上都不返回0
答案 0 :(得分:5)
有可能使用多个numpy.where
,但如果更多条件使用apply
:
对于来自策略的选择字符串,请使用indexing with str。
df = pd.DataFrame({'A':['xxxss','yyyee','zzzswee','sss'],
'B':[4,5,6,8]})
print (df)
A B
0 xxxss 4
1 yyyee 5
2 zzzswee 6
3 sss 8
#check first 3 values
a = df.A.str[:3]
df['new'] = np.where(a == 'xxx', 1,
np.where(a == 'yyy', 2,
np.where(a == 'zzz', 3, 0)))
print (df)
A B new
0 xxxss 4 1
1 yyyee 5 2
2 zzzswee 6 3
3 sss 8 0
def f(x):
#print (x)
if x == 'xxx':
return 1
elif x == 'yyy':
return 2
elif x == 'zzz':
return 3
else:
return 0
df['new'] = df.A.str[:3].apply(f)
print (df)
A B new
0 xxxss 4 1
1 yyyee 5 2
2 zzzswee 6 3
3 sss 8 0
编辑:
如果长度不同,只需要:
df['new'] = np.where(df.A.str[:3] == 'xxx', 1,
np.where(df.A.str[:2] == 'yy', 2,
np.where(df.A.str[:1] == 'z', 3, 0)))
print (df)
A B new
0 xxxss 4 1
1 yyyee 5 2
2 zzzswee 6 3
3 sss 8 0
EDIT1:
感谢您Quickbeam2k1使用str.startswith
检查每个字符串的检查开始的想法:
df['new'] = np.where(df.A.str.startswith('xxx'), 1,
np.where(df.A.str.startswith('yy'), 2,
np.where(df.A.str.startswith('z'), 3, 0)))
print (df)
A B new
0 xxxss 4 1
1 yyyee 5 2
2 zzzswee 6 3
3 sss 8 0
答案 1 :(得分:0)
一种不同且较慢的解决方案: 但是,优点是模式的映射是一个函数参数(隐式默认值为0)
def map_starts_with(pat_map):
def map_string(t):
pats = [pat for pat in pat_map.keys() if t.startswith(pat)]
return pat_map.get(pats[0]) if len(pats) > 0 else 0
# get only value of "first" pattern if at least one pattern is found
return map_string
df = pd.DataFrame({'col':[ 'xx', 'aaaaaa', 'c']})
col
0 xx
1 aaaaaa
2 c
mapping = { 'aaa':4 ,'c':3}
df.col.apply(lambda x: map_starts_with(mapping)(x))
0 0
1 4
2 3
注意我们也在这里使用currying。我想知道这种方法是否可以使用额外的pandas或numpy功能来实现。
请注意"首先"模式匹配可能取决于dict键的遍历顺序。如果键中没有重叠,这是无关紧要的。 (Jezrael的解决方案,或其直接推广,也将选择一个元素用于匹配,但以更可预测的方式)