将数字范围转换为顺序范围

时间:2019-04-19 15:51:04

标签: python pandas numpy

我有一个大约9000个数据集,其Territory范围的格式为[1-5,10-99,100-115],我想扩展数据,并在提供的数据集中将行扩展为该格式。

我的第一个想法可能是循环遍历“ Terri”系列并通过pd.series(range(i,100))运行它,但这不会创建以下输出。

感谢帮助。

import pandas as pd
d={'Peril':['Fire','Wind'],'Terri':[1-5,6-10],'Premium':[100,200]}
output={'Peril':['Fire','Fire','Fire','Fire','Fire','Wind','Wind','Wind','Wind','Wind'],'Terri':[1,2,3,4,5,6,7,8,9,10],'Premium':[100,100,100,100,100,200,200,200,200,200]}
df=pd.DataFrame(data=d)
expected_output=pd.DataFrame(data=output)

4 个答案:

答案 0 :(得分:4)

使用几个帮助列表理解,然后使用pandas.index.repeatDataFrame.assignnumpy.hstack

import numpy as np
import pandas as pd

ranges = [np.arange(s, e+1) for s, e in [list(map(int, x)) for x in df.Terri.str.split('-')]]
lens = [len(x) for x in ranges]

df_new = df.loc[df.index.repeat(lens)].assign(Terri=np.hstack(ranges))

[出]

  Peril  Terri  Premium
0  Fire      1      100
0  Fire      2      100
0  Fire      3      100
0  Fire      4      100
0  Fire      5      100
1  Wind      6      200
1  Wind      7      200
1  Wind      8      200
1  Wind      9      200
1  Wind     10      200

供参考,ranges如下:

[array([1, 2, 3, 4, 5]), array([ 6,  7,  8,  9, 10])]

lens如下:

[5, 5]

答案 1 :(得分:2)

假设Terri包含字符串范围,而不是进行减法运算,则可以创建一个范围范围的DataFrame,然后stack可以受益于join对公共索引的访问扩展原始框架。


u = df['Terri'].str.split('-', expand=True).astype(int).values

j = pd.DataFrame(
    [np.arange(start, stop+1) for start, stop in u]
)

j.stack().reset_index(1, drop=True).to_frame('Terri')

df.drop('Terri', 1).join(f)

  Peril  Premium  Terri
0  Fire      100      1
0  Fire      100      2
0  Fire      100      3
0  Fire      100      4
0  Fire      100      5
1  Wind      200      6
1  Wind      200      7
1  Wind      200      8
1  Wind      200      9
1  Wind      200     10

由于stack的行为将删除空值,因此您的范围不必是统一的长度。

答案 2 :(得分:1)

唯一可行的方法是,如果您要启动DataFrame的Terri列是字符串:

d={'Peril':['Fire','Wind'],'Terri':['1-5','6-10'],'Premium':[100,200]}
df = pd.DataFrame(d)
print(df)
#  Peril Terri  Premium
#0  Fire   1-5      100
#1  Wind  6-10      200

如果您在Terri的{​​{1}}列中拆分了字符串,则可以将其用作-的输入,除了需要在终止值上添加一个包括端点。为了简化操作,您可以定义自己的范围函数:

range

现在,您可以拆分列,应用def myRange(a, b): return range(a, b+1) 函数,并堆叠结果:

myRange

最后将此结果与原始DataFrame结合起来

temp = pd.DataFrame(
    df['Terri'].str.split("-")\
        .apply(lambda x: pd.Series(myRange(*map(int, x))))\
        .stack()\
        .reset_index(level=1, drop=True),
    columns=["Terri"]
)
print(temp)
#   Terri
#0      1
#0      2
#0      3
#0      4
#0      5
#1      6
#1      7
#1      8
#1      9
#1     10

同一件事,简明扼要:

print(df.drop(["Terri"], axis=1).join(temp))
#  Peril  Premium  Terri
#0  Fire      100      1
#0  Fire      100      2
#0  Fire      100      3
#0  Fire      100      4
#0  Fire      100      5
#1  Wind      200      6
#1  Wind      200      7
#1  Wind      200      8
#1  Wind      200      9
#1  Wind      200     10

答案 3 :(得分:0)

如果[1-5,6-10]实际上是['1-5','6-10'],则下面的代码可以工作:

new_df = []
for row in df.iterrows():
    rng = row[1]['Terri']
    rng = rng.split('-')
    start, end = int(rng[0]), int(rng[1])
    for n in range(start, end+1):
        new_row = {
            'Peril': row[1]['Peril'],
            'Terri': n,
            'Premium': row[1]['Premium'],
        }
        new_df.append(new_row)
output = pd.DataFrame(new_df)