根据列中的范围扩展pandas数据帧

时间:2015-10-22 20:41:42

标签: python pandas

我有一个像这样的pandas数据框:

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字典读入数据框架。)

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

您可以使用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

答案 2 :(得分:0)

我找到的最好的方式(基于Andy Hayden的答案):

# 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循环,它很慢。矢量化解决方案会很棒,但我找不到。