【问题标题】:Python expand network address in a dataframePython在数据框中扩展网络地址
【发布时间】:2020-06-11 20:36:56
【问题描述】:

我有一个类似于以下的数据框:

df:

    ip          last_active
192.167.0.9     01/02/2012
226.90.2.12     05/06/2013
10.90.2.09      05/06/2014
12.60.2.80     
192.168.2.11-17 05/06/2016

有没有办法从df中的最后一行扩展IP地址? 一个完美的解决方案是:

df:

    ip          last_active
192.167.0.9     01/02/2012
226.90.2.12     05/06/2013
10.90.2.09      05/06/2014
12.60.2.80     
192.168.2.11    05/06/2016
192.168.2.12    05/06/2016
192.168.2.13    05/06/2016
192.168.2.14    05/06/2016
192.168.2.15    05/06/2016
192.168.2.16    05/06/2016
192.168.2.17    05/06/2016

感谢任何指导!

【问题讨论】:

  • 你能提供原始数据吗?

标签: python pandas dataframe ip expand


【解决方案1】:

您可以应用一个函数来列出范围元素中的 IP,如果您有最新的 pandas 版本,请使用 explode()

def ip_splitter(ip):
    if '-' in ip:
        last_octet_range=[int(i) for i in ip.split('.')[3].split('-')]
        new_ips = [i for i in range(last_octet_range[0],last_octet_range[1]+1)]
        expanded_range = ['.'.join(ip.split('.')[:3]+[str(i)]) for i in new_ips]
        return expanded_range
    return ip

df['ip']=df['ip'].apply(ip_splitter)

df

    ip                                                  last_active
0   192.167.0.9                                         01/02/2012
1   226.90.2.12                                         05/06/2013
2   10.90.2.09                                          05/06/2014
3   12.60.2.80                                          None
4   [192.168.2.11, 192.168.2.12, 192.168.2.13, 192...   05/06/2016

df.explode('ip')

    ip              last_active
0   192.167.0.9     01/02/2012
1   226.90.2.12     05/06/2013
2   10.90.2.09      05/06/2014
3   12.60.2.80      None
4   192.168.2.11    05/06/2016
4   192.168.2.12    05/06/2016
4   192.168.2.13    05/06/2016
4   192.168.2.14    05/06/2016
4   192.168.2.15    05/06/2016
4   192.168.2.16    05/06/2016
4   192.168.2.17    05/06/2016

【讨论】:

    【解决方案2】:

    一种可能的解决方案,基于命名的捕获组:

    pat = re.compile(r'(?P<g1>(?:\d+\.){3})(?P<g2>\d+)-(?P<g3>\d+)')
    outRows = []
    for _, row in df.iterrows():
        ip = row.ip
        mtch = pat.match(ip)
        if mtch:
            n1 = mtch.group('g1')
            n2 = int(mtch.group('g2'))
            n3 = int(mtch.group('g3'))
            for n in range(n2, n3 + 1):
                outRows.append([ n1 + str(n), row.last_active])
        else:
            outRows.append([ ip, row.last_active])
    result = pd.DataFrame(outRows, columns=df.columns)
    

    【讨论】:

      【解决方案3】:

      这是我的方法:

      # separate relevant parts
      s = df['ip'].str.extract('(\d+\.\d+\.\d+.)(\d+)-?(\d+)?').ffill(1)
      
      # convert last parts to int for easy manipulation
      s[1] = s[1].astype(int)
      s[2] = s[2].astype(int)
      
      # masking the IP range
      lowers = s[1].values[:,None] <= np.arange(256)
      uppers =  np.arange(256)<= s[2].values[:,None]
      
      # create new dataframe for the new IPs
      u = pd.DataFrame(lowers & uppers, 
                       index=pd.MultiIndex.from_arrays([df['last_active'],s[0]])
                      )
      
      # final data
      (u.where(u).stack().reset_index(name='dummy')
       .assign(ip=lambda x: x[0]+x['level_2'].astype(str))
       .drop([0,'level_2','dummy'], axis=1)
      )   
      

      输出:

         last_active            ip
      0   01/02/2012   192.167.0.9
      1   05/06/2013   226.90.2.12
      2   05/06/2014     10.90.2.9
      3          NaN    12.60.2.80
      4   05/06/2016  192.168.2.11
      5   05/06/2016  192.168.2.12
      6   05/06/2016  192.168.2.13
      7   05/06/2016  192.168.2.14
      8   05/06/2016  192.168.2.15
      9   05/06/2016  192.168.2.16
      10  05/06/2016  192.168.2.17
      

      【讨论】:

        【解决方案4】:

        我喜欢各种解决方案的不同之处。这是另一个改编自这里的(!):https://stackoverflow.com/a/33291055/42346

        df2 = pd.DataFrame(columns=df.columns)
        
        count = 0 
        for idx,r in df.iterrows(): 
            data = r['ip'].split("-") 
            if len(data) > 1: 
                start = int(data[0].split('.')[-1]) 
                end = int(data[1]) + 1 
                for i in range(start,end): 
                    df2.loc[count] = (data[0][:data[0].rfind('.')+1] + 
                                      str(i),r['last_active']) 
                    count += 1 
            else: 
                df2.loc[count] = (r['ip'],r['last_active']) 
                count += 1 
        

        结果:

        In [40]: df2
        Out[40]: 
                      ip last_active
        0    192.167.0.9  01/02/2012
        1    226.90.2.12  05/06/2013
        2     10.90.2.09  05/06/2014
        3     12.60.2.80        None
        4   192.168.2.11  05/06/2016
        5   192.168.2.12  05/06/2016
        6   192.168.2.13  05/06/2016
        7   192.168.2.14  05/06/2016
        8   192.168.2.15  05/06/2016
        9   192.168.2.16  05/06/2016
        10  192.168.2.17  05/06/2016
        

        【讨论】:

          猜你喜欢
          • 2020-05-02
          • 2018-01-21
          • 2012-07-12
          • 1970-01-01
          • 1970-01-01
          • 2019-02-12
          • 2014-07-26
          • 2016-11-17
          • 1970-01-01
          相关资源
          最近更新 更多