【问题标题】:Expand pandas dataframe based on range in a column根据列中的范围扩展熊猫数据框
【发布时间】:2016-02-10 22:55:52
【问题描述】:

我有一个这样的熊猫数据框:

Name   SICs
Agric  0100-0199
Agric  0910-0919
Agric  2048-2048
Food   2000-2009
Food   2010-2019
Soda   2097-2097

SICs 列给出了与第一列中给出的Name 匹配的整数值范围(尽管它们存储为字符串)。

我需要扩展这个 DataFrame 以便它在范围内的每个整数都有一行:

Agric  100
Agric  101
Agric  102
...
Agric  199
Agric  910
Agric  911
...
Agric  919
Agric 2048
Food  2000
...

有没有特别好的方法可以做到这一点?我打算做这样的事情

ranges = {i:r.split('-') for i, r in enumerate(inds['SICs'])}
ranges_expanded = {}
for r in ranges:
    ranges_expanded[r] = range(int(ranges[r][0]),int(ranges[r][1])+1)

但我想知道是否有更好的方法或熊猫功能可以做到这一点。 (另外,我不确定这是否可行,因为我还没有看到如何将 ranges_expanded 字典读入 DataFrame。)

【问题讨论】:

  • 标准注释:如果您插入图像,则没有人可以复制和粘贴它——他们必须输入它。另一方面,如果您插入 text,我们可以使用pd.read_clipboard()轻松重现你的框架。
  • 在我看来,在您执行ranges = {i:r.split('-') for i, r in enumerate(inds['SICs'])} 时,您正在丢失“名称”信息。如果您设法将所有这些 nameSIC 对放入元组中,那么您可以简单地说 pd.DataFrame(tuples) 并为您创建 DataFrame

标签: python pandas


【解决方案1】:

又快又脏,但我认为这可以满足您的需求:

from io import StringIO
import pandas as pd

players=StringIO(u"""Name,SICs
Agric,0100-0199
Agric,0210-0211
Food,2048-2048
Soda,1198-1200""")

df = pd.DataFrame.from_csv(players, sep=",", parse_dates=False).reset_index()


df2 = pd.DataFrame(columns=('Name', 'SIC'))

count = 0
for idx,r in df.iterrows():
    data = r['SICs'].split("-")
    for i in range(int(data[0]), int(data[1])+1):
                   df2.loc[count] = (r['Name'], i)
                   count += 1

【讨论】:

    【解决方案2】:

    我发现的最简洁的方式(基于安迪·海登的回答):

    # Extract date min and max
    df = df.set_index("Name")
    df = df['SICs'].str.extract("(\d+)-(\d+)")
    df.columns = ['min', 'max']
    df = df.astype('int')
    
    # Enumerate dates into wide table
    enumerated_dates = [np.arange(row['min'], row['max']+1) for _, row in df.iterrows()]
    df = pd.DataFrame.from_records(data=enumerated_dates, index=df.index)
    
    # Convert from wide to long table
    df = df.stack().reset_index(1, drop=True)
    

    但是由于 for 循环,它很慢。矢量化解决方案会很棒,但我找不到。

    【讨论】:

      【解决方案3】:

      您可以使用 str.extract 从正则表达式中获取字符串:

      In [11]: df
      Out[11]:
         Name       SICs
      0  Agri  0100-0199
      1  Agri  0910-0919
      2  Food  2000-2009
      

      首先取出名字,因为这是我们要保留的东西:

      In [12]: df1 = df.set_index("Name")
      
      In [13]: df1
      Out[13]:
                 SICs
      Name
      Agri  0100-0199
      Agri  0910-0919
      Food  2000-2009
      
      In [14]: df1['SICs'].str.extract("(\d+)-(\d+)")
      Out[14]:
               0     1
      Name
      Agri  0100  0199
      Agri  0910  0919
      Food  2000  2009
      

      然后用堆栈将其展平(添加一个 MultiIndex):

      In [15]: df1['SICs'].str.extract("(\d+)-(\d+)").stack()
      Out[15]:
      Name
      Agri  0    0100
            1    0199
            0    0910
            1    0919
      Food  0    2000
            1    2009
      dtype: object
      

      如果必须,您可以删除 MultiIndex 的 0-1 级别:

      In [16]: df1['SICs'].str.extract("(\d+)-(\d+)").stack().reset_index(1, drop=True)
      Out[16]:
      Name
      Agri    0100
      Agri    0199
      Agri    0910
      Agri    0919
      Food    2000
      Food    2009
      dtype: object
      

      【讨论】:

      • 我认为用户也想扩大范围,例如创建一个从Agri 0100Agri 0199 的100 行
      猜你喜欢
      • 2020-07-02
      • 2017-10-14
      • 2022-01-23
      • 2015-12-28
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      • 2022-07-12
      • 1970-01-01
      相关资源
      最近更新 更多