【问题标题】:How to create separate substring column from dataframe column value如何从数据框列值创建单独的子字符串列
【发布时间】:2019-02-12 21:25:11
【问题描述】:

我有这样的数据框:

Instru,Name
16834306,INFOSYS18SEP640.50PE
16834306,INFOSYS18SEP640.50PE
16834306,BHEL18SEP52.80CE
16834306,BHEL18SEP52.80CE
16834306,IOCL18SEP640PE
16834306,IOCL18SEP640PE

我想通过从名称列中获取字符串来创建单独的列,如下所示:

Instru,Name,Symbol,Month,SP,Type
16834306,INFOSYS18SEP640.50PE,INFOSYS,18SEP,640.50,PE
16834306,INFOSYS18SEP640.50PE,INFOSYS,18SEP,640.50,PE
16834306,BHEL18SEP52.80CE,BHEL,18SEP,52.80,CE    
16834306,BHEL18SEP52.80CE,BHEL,18SEP,52.80,CE
16834306,IOCL18SEP640PE,IOCL,18SEP,640,PE
16834306,IOCL18SEP640PE,IOCL,18SEP,640,PE

注意:对于 SP 列,小数显示为小数,整数显示为 int

【问题讨论】:

标签: python python-3.x pandas dataframe list-comprehension


【解决方案1】:

pandas.Series.str.extract 与正则表达式模式中的命名组一起使用

pat = '(?P<Symbol>.*?)(?P<Month>\d{1,2}\w{3})(?P<SP>[\d\.]+)(?P<Type>.*)'
df.join(df.Name.str.extract(pat))

     Instru                  Name   Symbol  Month      SP Type
0  16834306  INFOSYS18SEP640.50PE  INFOSYS  18SEP  640.50   PE
1  16834306  INFOSYS18SEP640.50PE  INFOSYS  18SEP  640.50   PE
2  16834306      BHEL18SEP52.80CE     BHEL  18SEP   52.80   CE
3  16834306      BHEL18SEP52.80CE     BHEL  18SEP   52.80   CE
4  16834306        IOCL18SEP640PE     IOCL  18SEP     640   PE
5  16834306        IOCL18SEP640PE     IOCL  18SEP     640   PE

正则表达式的解释

正则表达式是一种有趣的模糊业务,是一种艺术形式。我会解释我做了什么以及为什么。你可以比较我相对于@jonclements 所做的事情,发现我们都用相同的方法解决了这个问题,但做出了微妙的不同假设。

  • '(?P&lt;group_name&gt;pattern)' 是一种创建捕获组并将其命名为 'group_name' 的方法
  • '(?P&lt;Symbol&gt;.*?)' 将所有字符抓取到下一个捕获组,'?' 表示不要贪心。
  • '(?P&lt;Month&gt;\d{1,2}\w{3})' 获取 1 或 2 个数字,然后是 3 个字母。 1 位或 2 位数字的模糊性是我让前一组不贪婪的原因。
  • '(?P&lt;SP&gt;[\d\.]+)' 获取一个或多个数字或句点。诚然,这不是很优雅,因为它可以抓取 '4.2.4.5',但它应该可以完成工作。
  • '(?P&lt;Type&gt;.*)' 收拾残局。

【讨论】:

  • 很好的答案。如果您解释了正则表达式模式,它可能会很有用。
  • @Alexander 处理中
【解决方案2】:

您可以使用str.extract 并将.astype 应用于结果以获得所需的列和特定的数字列作为浮点数:

separated = df.Name.str.extract(r"""(?ix)
    (?P<Symbol>[a-z]+)     # all letters up to a date that matches
    (?P<Month>\d{2}\w{3})  # the date (2 numbers then 3 letters)
    (?P<SP>.*?)            # everything until the "type"
    (?P<Type>\w{2}$)       # Last two characters of string is the type
""").astype({'SP': 'float'})

这会给你:

    Symbol  Month     SP Type
0  INFOSYS  18SEP  640.5   PE
1  INFOSYS  18SEP  640.5   PE
2     BHEL  18SEP   52.8   CE
3     BHEL  18SEP   52.8   CE
4     IOCL  18SEP  640.0   PE
5     IOCL  18SEP  640.0   PE

然后申请 df.join(separated) 以获得您的最终 DF:

     Instru                  Name   Symbol  Month     SP Type
0  16834306  INFOSYS18SEP640.50PE  INFOSYS  18SEP  640.5   PE
1  16834306  INFOSYS18SEP640.50PE  INFOSYS  18SEP  640.5   PE
2  16834306      BHEL18SEP52.80CE     BHEL  18SEP   52.8   CE
3  16834306      BHEL18SEP52.80CE     BHEL  18SEP   52.8   CE
4  16834306        IOCL18SEP640PE     IOCL  18SEP  640.0   PE
5  16834306        IOCL18SEP640PE     IOCL  18SEP  640.0   PE

【讨论】:

  • 我喜欢你对正则表达式模式的解释。我会做出同样的努力,并与你的对比。
【解决方案3】:

您可以定义拆分函数并创建所需的输出

def f(x):
    for i, c in enumerate(x):
        if c.isdigit():        
            break
    return [x[0:i], x[i:9], x[9:-2], x[-2:]]

df[['Symbol','Month','SP','Type']] = pd.DataFrame(df.Name.apply(f).tolist())

     Instru               Name Symbol  Month      SP Type
0  16834306  INFY18SEP640.50PE   INFY  18SEP  640.50   PE
1  16834306  INFY18SEP640.50PE   INFY  18SEP  640.50   PE
2  16834306   BHEL18SEP52.80CE   BHEL  18SEP   52.80   CE
3  16834306   BHEL18SEP52.80CE   BHEL  18SEP   52.80   CE
4  16834306     IOCL18SEP640PE   IOCL  18SEP     640   PE
5  16834306     IOCL18SEP640PE   IOCL  18SEP     640   PE

【讨论】:

    猜你喜欢
    • 2021-08-18
    • 2018-08-22
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 2018-04-14
    • 1970-01-01
    • 2016-02-13
    • 1970-01-01
    相关资源
    最近更新 更多