#python #pandas #numpy
#python #pandas #numpy
Вопрос:
У меня есть набор данных около 9000 с диапазонами территорий вида [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)
Комментарии:
1.
[1-5,6-10]
точно так же, как[-4,-4]
. Это реальное представление ваших данных или вы имеете в виду['1-5','6-10']
?2. Можете ли вы лучше уточнить ожидаемые входные и выходные данные
3. Извинения, [‘1-5′,’6-10’] это правильная интерпретация
Ответ №1:
Используйте пару вспомогательных списков, затем используйте, и pandas.index.repeat
DataFrame.assign
numpy.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]
Ответ №2:
Предполагая, что Terri
он должен содержать диапазоны строк, вместо операций вычитания вы можете создать фрейм данных из ваших диапазонов, а затем 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
будет отбрасывать нулевые значения, ваши диапазоны не обязательно должны быть одинаковой длины.
Ответ №3:
Единственный способ, которым это работает, — это если вы запускаете Terri
столбец DataFrame в виде строки:
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
столбце на -
, вы можете использовать ее в качестве входных данных range
, за исключением того, что вам нужно будет добавить единицу к значению остановки, чтобы включить конечную точку. Чтобы упростить это, вы можете определить свою собственную функцию диапазона:
def myRange(a, b):
return range(a, b 1)
Теперь вы можете разделить столбец, применить myRange
функцию и сложить результат:
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
То же самое, сжатый:
df.drop(["Terri"], axis=1).join(
pd.DataFrame(
df['Terri'].str.split("-")
.apply(lambda x: pd.Series(myRange(*map(int, x))))
.stack()
.reset_index(level=1, drop=True),
columns=["Terri"]
)
)
Ответ №4:
Если [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)