将行拆分为多个列,只选择行中的某些值并删除其余值

时间:2017-11-26 19:01:25

标签: python regex python-3.x pandas dataframe

我的df看起来像这样:

name      surname     device
anna      smith       Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Mobile/14E304
petr      lebowski    Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:48.0) Gecko/20100101 Firefox/48.0
eveline   jones       Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G903F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36

我的目标是将这些行拆分为多个列,并选择某些值来创建新列,以便新数据框如下所示:

name      surname     device        column1     column2               column3
anna      smith       as in df      iPhone CPU  iPhone OS 10_3_1      Mac OS X 
petr      lebowski    as in df      Macintosh   Intel Mac OS X 10.6   rv:48.0
eveline   jones       as in df      Linux       Android 6.0.1         SAMSUNG SM-G903F Build/MMB29K

所以基本上我只想从这些行中选择某些值:只是用括号分隔的那些值;'。'。

我知道如何用符号分割符号:

def split_it(string):
    return re.findall(r"[\w']+|[.,!?;]", string)

以及如何使用拆分行创建新列:

df['device'].str[1:-1].str.split(',', expand=True)

但是如何只选择某些值并用它们创建列不明白......

2 个答案:

答案 0 :(得分:1)

你需要一个更好的正则表达式:

pattern = re.compile(r"\((.+?); (.+?)(?: like|;) (.+?)\)")
new_columns = df.device.str.extract(pattern, expand=False)

你甚至可以预先命名:

new_columns = df.Device.str.extract(r"\((?P<column1>.+?); (?P<column2>.+?)(?: like|;) (?P<column3>.+?)\)", expand=False)

然后,您只需要将join与其余数据一起返回:

df = df.join(new_columns)

答案 1 :(得分:1)

您可以利用较新的regex module和一些编程逻辑:

import pandas as pd, regex as re

# your df here

rx = re.compile(r'(?:\G(?!\A)|^[^()]*\()([^();]+);?')

def getter(col):
    # default empty dict
    empty = {'column1': '', 'column2': '', 'column3': ''}

    # generate results with a comprehension
    matches = {'column{}'.format(idx): val 
        for idx, val in enumerate(rx.findall(col), 1)}
    return pd.Series(dict(empty, **matches))

df[["column1", "column2", "column3"]] = df["device"].apply(getter)
print(df[["column1", "column2", "column3"]])

这样可以为你的例子

     column1                              column2  \
0     iPhone   CPU iPhone OS 10_3_1 like Mac OS X   
1  Macintosh                  Intel Mac OS X 10.6   
2      Linux                        Android 6.0.1   

                          column3  
0                                  
1                         rv:48.0  
2   SAMSUNG SM-G903F Build/MMB29K  

<小时/>

说明

虽然肯定不完美,但我们的想法是匹配;(内的)。在这里,需要\G匹配最后一个匹配停止的地方:

(?:           # non-capturing group
    \G(?!\A)  # match where the last match stopped, not the beginning
    |         # or
    ^[^()]*\( # find the first (
)
(             # capture group 1
    [^();]+   # anything not (, ) or ; at least once
)
;?            # semicolon optionally

之后,函数getter会返回一个新的pd.Series(),该df将保存在getter()中。 ln -s /source_folder /home/user/public_html/target_folder内的逻辑覆盖空字典。

请参阅a demo on regex101.com