1

I have a dataframe where I want to extract stuff after double space. For all rows in column NAME there is a double white space after the company names before the integers.

                                    NAME  INVESTMENT  PERCENT
0     APPLE COMPANY A  57 638 232 stocks     OIL LTD  0.12322
1  BANANA 1 COMPANY B  12 946 201 stocks    GOLD LTD  0.02768
2     ORANGE COMPANY C  8 354 229 stocks     GAS LTD  0.01786

df = pd.DataFrame({
    'NAME': ['APPLE COMPANY A  57 638 232 stocks', 'BANANA 1 COMPANY B  12 946 201 stocks', 'ORANGE COMPANY C  8 354 229 stocks'],
    'PERCENT': [0.12322, 0.02768 , 0.01786]
    })

I have this earlier, but it also includes integers in the company name:

df['STOCKS']=df['NAME'].str.findall(r'\b\d+\b').apply(lambda x: ''.join(x))

Instead I tried to extract after double spaces

df['NAME'].str.split('(\s{2})')

which gives output:

0       [APPLE COMPANY A,   , 57 638 232 stocks]
1    [BANANA 1 COMPANY B,   , 12 946 201 stocks]
2       [ORANGE COMPANY C,   , 8 354 229 stocks]

However, I want the integers that occur after double spaces to be joined/merged and put into a new column.

                 NAME  PERCENT  STOCKS
0     APPLE COMPANY A  0.12322  57638232
1  BANANA 1 COMPANY B  0.02768  12946201
2    ORANGE COMPANY C  0.01786  12946201

How can I modify my second function to do what I want?

Mataunited18
  • 598
  • 1
  • 7
  • 20
  • Why do you want to use regex ? it's slow and you can just split on 2 spaces (`.split(' ')`) also, i assume that by removing your first column and creating a new one while putting the content into it it'd work – Nenri Mar 15 '19 at 07:56

5 Answers5

4

Following the original logic you may use

df['STOCKS'] = df['NAME'].str.extract(r'\s{2,}(\d+(?:\s\d+)*)', expand=False).str.replace(r'\s+', '')
df['NAME'] = df['NAME'].str.replace(r'\s{2,}\d+(?:\s\d+)*\s+stocks', '')

Output:

                 NAME  PERCENT    STOCKS
0     APPLE COMPANY A  0.12322  57638232
1  BANANA 1 COMPANY B  0.02768  12946201
2    ORANGE COMPANY C  0.01786   8354229

Details

  • \s{2,}(\d+(?:\s\d+)*) is used to extract the first occurrence of whitespace-separated consecutive digit chunks after 2 or more whitespaces and .replace(r'\s+', '') removes any whitespaces in that extracted text afterwards
  • .replace(r'\s{2,}\d+(?:\s\d+)*\s+stocks' updates the text in the NAME column, it removes 2 or more whitespaces, consecutive whitespace-separated digit chunks and then 1+ whitespaces and stocks. Actually, the last \s+stocks may be replaced with .* if there are other words.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
3

Another pandas approach, which will cast STOCKS to numeric type:

df_split = (df['NAME'].str.extractall('^(?P<NAME>.+)\s{2}(?P<STOCKS>[\d\s]+)')
            .reset_index(level=1, drop=True))

df_split['STOCKS'] = pd.to_numeric(df_split.STOCKS.str.replace('\D', ''))

Assign these columns back into your original DataFrame:

df[['NAME', 'STOCKS']] = df_split[['NAME', 'STOCKS']]

         COMPANY_NAME    STOCKS  PERCENT
0     APPLE COMPANY A  57638232  0.12322
1  BANANA 1 COMPANY B  12946201  0.02768
2    ORANGE COMPANY C   8354229  0.01786
Chris Adams
  • 18,389
  • 4
  • 22
  • 39
1

You can use look behind and look ahead operators.

''.join(re.findall(r'(?<=\s{2})(.*)(?=stocks)',string)).replace(' ','')

This catches all characters between two spaces and the word stocks and replace all the spaces with null.

Another Solution using Split

df["NAME"].apply(lambda x:x[x.find('  ')+2:x.find('stocks')-1].replace(' ',''))

Reference:-

  1. Look_behind
Justice_Lords
  • 949
  • 5
  • 14
  • Or he could just do `.split(' ')[1].split()[0]` which is way faster than regex (2 spaces in the first split) – Nenri Mar 15 '19 at 08:01
  • @Mataunited17 can you show me what you tried to do ? that should work just fine – Nenri Mar 15 '19 at 08:05
  • @Nenri I did `df['NAME'].str.split(' ')[1].split()[0]` which gave me error: 'list' object has no attribute 'split'. Which is strange, because I have a dataframe. – Mataunited18 Mar 15 '19 at 08:07
  • yeah, and `.str` is supposed to return you a string – Nenri Mar 15 '19 at 08:09
  • @Justice_Lords When I applied your second solution to my original dataframe, the outcome is strange when the names are very long. Is there a way to fix this? I think it has to do with the `+2` part of `x:x[x.find(' ')+2:x.find('stocks')` – Mataunited18 Mar 15 '19 at 08:37
0

You can try

df['STOCKS'] = df['NAME'].str.split(',')[2].replace(' ', '')
df['NAME'] = df['NAME'].str.split(',')[0]
Vaghinak
  • 535
  • 6
  • 12
0

This can be done without using regex by using split.

df['STOCKS'] = df['NAME'].apply(lambda x: ''.join(x.split('  ')[1].split(' ')[:-1]))
df['NAME'] = df['NAME'].str.replace(r'\s?\d+(?:\s\d+).*', '')
Loochie
  • 2,414
  • 13
  • 20