使用Python3如何将一列包含一组范围的df拆分为包含多个子范围的df?

使用Python3如何将一列包含一组范围的df拆分为包含多个子范围的df?,python,pandas,dataframe,Python,Pandas,Dataframe,因此,我有以下几点: #this is the data we have df = pd.DataFrame(data=(['A','1-50', 10],['B','25-200', 15],['C','25-300', 5]), columns=['Category','Range', 'Qty']) #these are the different range categories we need to have. list_of_ranges = ['1-10', '10-25', '

因此,我有以下几点:

#this is the data we have
df = pd.DataFrame(data=(['A','1-50', 10],['B','25-200', 15],['C','25-300', 5]), columns=['Category','Range', 'Qty'])

#these are the different range categories we need to have.
list_of_ranges = ['1-10', '10-25', '25-50', '50-100', '100-200', '200-300', '300-400']

# insert magic spells here

#this is what the result needs to look like
results = pd.DataFrame(data=(['A','1-25', 10],['A','25-50', 10],['B','25-50', 15],['B','50-100', 15],['B','100-200', 15],['C','25-50', 15],['C','50-100', 15],['C','100-200', 15],['C','200-300', 5]), columns=['Category','Range', 'Qty'])

根据上述示例:

我有一个df,其中的范围需要分解为子范围,除新范围外,所有列都需要复制。 我该怎么做

编辑1: 逻辑示例

“A”地区每年有10天的气温在1-50摄氏度之间。 这是一行,内容如下:

1: A,1-50,10
同一行可以解释为:在“A”区域,每年10天的温度范围可以是1-10、10-25或25-50。 所以我想有3行:

1: A,1-10,10
2: A,10-25,10
3: A,25-50,10

我们需要几个函数来处理您定义的“范围”,但除此之外,还需要为df中“内部”的每个“范围”创建一个“小范围”列表,然后分解df

def split_range(r):
    """
    split range into a tuple. range is a string 'xx-yy'
    """
    tokens =  r.split('-')
    return (int(tokens[0]), int(tokens[1]))

def is_inside(r1,r2):
    """
    True if range r1 is inside r2. Range is a string 'xx-yy'
    """
    t1, t2 = split_range(r1), split_range(r2)
    return (t1[0]>=t2[0]) and (t1[1] <= t2[1])

df['small_ranges'] = df.apply(lambda row: [rng for rng in list_of_ranges if is_inside(rng, row['Range']) ], axis=1)

现在我们
爆炸

df.explode('small_ranges')
输出

    Category    Range      Qty  small_ranges
--  ----------  -------  -----  --------------
 0  A           1-50        10  1-10
 0  A           1-50        10  10-25
 0  A           1-50        10  25-50
 1  B           25-200      15  25-50
 1  B           25-200      15  50-100
 1  B           25-200      15  100-200
 2  C           25-300       5  25-50
 2  C           25-300       5  50-100
 2  C           25-300       5  100-200
 2  C           25-300       5  200-300

这里是一个使用
pandas.Interval
的解决方案,在这种情况下似乎非常有用。首先,我们将字符串转换为
pd.Interval

list_of_ranges = [pd.Interval(*tuple(map(int, r.split('-')))) for r in list_of_ranges]

df['Range'] = df['Range'].apply(lambda r: pd.Interval(*tuple(map(int, r.split('-')))))
我们创建了一个新的数据帧,包括每个原始范围的所有所需范围:

my_temps = []

for idx, row in df.iterrows():
    _df = pd.DataFrame(columns=df.columns)
    _df['Range'] = [r for r in list_of_ranges if r.overlaps(row['Range'])]
    _df['Category'], _df['Qty'] = row['Category'], row['Qty']

    my_temps.append(_df)

final_df = pd.concat(my_temps).reset_index(drop=True)
然后,我们最终将范围再次转换为其原始字符串格式:

final_df['Range'] = final_df['Range'].apply(lambda r: '{}-{}'.format(r.left, r.right))
这将导致以下数据帧:

  Category    Range  Qty
0        A     1-10   10
1        A    10-25   10
2        A    25-50   10
0        B    25-50   15
1        B   50-100   15
2        B  100-200   15
0        C    25-50    5
1        C   50-100    5
2        C  100-200    5
3        C  200-300    5

如果您有任何其他问题,请告知我们

打破子范围背后的逻辑是什么?欢迎来到这里。这不是一个讨论论坛或教程。请花点时间阅读和阅读该页面上的其他链接。花点时间练习这些例子。@MayankPorwal请看Edit1有一个关于你们答案的问题,但已经解决了。答案绝对漂亮。谢谢大家!@迈克尔,谢谢你!这是一个很好的问题,这似乎也是一个很好的答案。非常感谢。另一个答案在我看来似乎更简洁。
  Category    Range  Qty
0        A     1-10   10
1        A    10-25   10
2        A    25-50   10
0        B    25-50   15
1        B   50-100   15
2        B  100-200   15
0        C    25-50    5
1        C   50-100    5
2        C  100-200    5
3        C  200-300    5