Python 根据列中的范围展开dataframe
我有这样一个熊猫数据框:Python 根据列中的范围展开dataframe,python,pandas,Python,Pandas,我有这样一个熊猫数据框: Name SICs Agric 0100-0199 Agric 0910-0919 Agric 2048-2048 Food 2000-2009 Food 2010-2019 Soda 2097-2097 SICs列提供与第一列中给出的名称匹配的整数值范围,尽管它们存储为字符串 我需要展开此数据帧,以便范围内的每个整数对应一行: Agric 100 Agric 101 Agric 102 ... Agric 199 Agric 910
Name SICs
Agric 0100-0199
Agric 0910-0919
Agric 2048-2048
Food 2000-2009
Food 2010-2019
Soda 2097-2097
SICs列提供与第一列中给出的名称匹配的整数值范围,尽管它们存储为字符串
我需要展开此数据帧,以便范围内的每个整数对应一行:
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)
但我想知道是否有更好的方法或是熊猫的特色来做到这一点。此外,我不确定这是否有效,因为我还不知道如何将扩展字典中的范围读入数据帧。您可以使用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
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
如果必须,可以删除多索引的0-1级别:
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
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
又快又脏,但我认为这能满足你的需要:
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
我从安迪·海登的回答中找到了最整洁的方式:
# 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循环,速度较慢。矢量化的解决方案会很神奇,但我找不到。标准注释:如果插入图像,没有人可以复制和粘贴它-他们必须键入它。另一方面,如果插入文本,我们可以使用pd.read_剪贴板轻松复制帧。在我看来,在enumerateinds['SICs']}中,对i,r执行ranges={i:r.split'-'时,您正在丢失名称信息。如果您设法将所有这些名称、SIC对放入元组,那么您可以简单地说pd.DataFrametuples,并将为您创建数据帧。我认为用户也想扩大范围,例如,从Agri 0100到Agri 0199创建100行