Splitting at Underscore in Python and Storing the First Value

I have a pandas data frame like df with a column construct_name

construct_name
aaaa_t1_2    
cccc_t4_10
bbbb_g3_3

and so on. I want to first split all the names at the underscore and store the first element (aaaa,cccc, etc.) as another column name.

Expected output

construct_name  name
aaaa_t1_2       aaaa
cccc_t4_10      bbbb

and so on.

I tried the following df['construct_name'].map(lambda row:row.split("_")) and it gives me a list like

[aaaa,t1,2]
[cccc,t4,10]

and so on

But when I do

df['construct_name'].map(lambda row:row.split("_"))[0] to get the first element of the list I get an error. Can you suggest a fix. Thanks

5 Answers

Just use the vectorised str method split and use integer indexing on the list to get the first element:

In [228]:

df['first'] = df['construct_name'].str.split('_').str[0]
df
Out[228]:
  construct_name first
0      aaaa_t1_2  aaaa
1     cccc_t4_10  cccc
2      bbbb_g3_3  bbbb
df['name'] = df['construct_name'].str.split('_').str.get(0)

or

df['name'] = df['construct_name'].str.split('_').apply(lambda x: x[0])

After you do the split, you should get the first element (using [0]). And not after the map.:

In [608]: temp['name'] = temp['construct_name'].map(lambda v: v.split('_')[0])

In [609]: temp
Out[609]: 
  construct_name  name
0      aaaa_t1_2  aaaa
1     cccc_t4_10  cccc
2      bbbb_g3_3  bbbb

Another way of using the vectorised str.split method is passing the expand=True flag which then returns one column for each of the split parts.

>>> s = pd.Series( ['aaaa_t1_2', 'cccc_t4_10', 'bbbb_g3_3'], name='construct_name')

>>> s.str.split('_', expand=True)  # to see what expand=True does
      0   1   2
0  aaaa  t1   2
1  cccc  t4  10
2  bbbb  g3   3

>>>  s.str.split('_', expand=True)[0]  # what you want, select first elements
0    aaaa
1    cccc
2    bbbb

This would be specially useful if you wanted to keep the first and second values for example.

In terms of the general behaviour of the expand=True flag, note that if the input strings do not have the same number of underscores you ca get Nones:

>>> s = pd.Series( ['aaaa_t1_2', 'cccc_t4', 'bbbb_g33'], name='construct_name')

>>> s.str.split('_', expand=True)
      0    1     2
0  aaaa   t1     2
1  cccc   t4  None
2  bbbb  g33  None

split take an optional argument maxsplit:

>>> construct_name = 'aaaa_t1_2'
>>> name, rest = construct_name.split('_', 1)
>>> name
'aaaa'
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

James H. Sterling

James H. Sterling

Environmental Science & Climate Journalist

James Sterling reports on renewable energy developments, climate policy, ecological conservation, and green tech innovations around the globe.

Share this article
Twitter Facebook Pinterest