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