2015-10-22 2 views
2

У меня есть панд dataframe вроде этого:Expand панд dataframe на основе диапазона в колонке

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.)

+2

Стандартный комментарий: если вы вставляете изображение, его нельзя копировать и вставлять - им нужно будет ввести его. С другой стороны, если вы вставляете * текст *, мы можем использовать 'pd.read_clipboard () ', чтобы легко воспроизвести ваш кадр. – DSM

+0

Мне кажется, что в точке вы делаете 'range = {i: r.split ('-') для i, r в enumerate (inds ['SICs'])}' вы теряете информацию о «имени». Если вам удастся поместить все эти пары «имя», «SIC» в кортежи, вы можете просто сказать «pd.DataFrame (кортежи)» и создаст DataFrame для вас –

ответ

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 
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 

Затем расплющить это со стеком (который добавляет мультииндексный):

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 

Если вы должны вы можете удалить 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 
+1

Я думаю, что пользователь хотел расширить диапазоны, например создайте 100 строк из 'Agri 0100' в' Agri 0199' –

0

опрятных, как я найдено (исходя из ответа Энди Хайдена):

# 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. Векторное решение было бы удивительным, но я не могу найти его.