#python #pandas
#python #pandas
Вопрос:
Я пытаюсь создать новый фрейм данных на основе следующих данных с 4 столбцами: start_year, end_ear, ego_id и alter_id. Мне нужно преобразовать данные в новый фрейм данных, который имеет ежегодное наблюдение (столбец year), используя start_year и end_year. Например, если start_year в существующем фрейме данных равен 2012, а end_year равен 2016, новый фрейм данных, основанный на этой строке, должен содержать 5 строк, включая год 2012, 2013, 2014, 2015 и 2016.
d = {'start_year': [2012, 2016,2006], 'end_year': [2016, 2017,2016],'ego_id':['1011','1011','2211'],'alter_id':['3311','9192','1022']}
df = pd.DataFrame(data=d)
df
start_year end_year ego_id alter_id
0 2012 2016 1011 3311
1 2016 2017 1011 9192
2 2006 2016 2211 1022
Одним из простых способов сделать это может быть повторение каждой строки в исходном фрейме данных, а затем создание новых строк на основе start_year и end_year и, наконец, добавление этих строк в новый фрейм данных.
Однако я обнаружил, что этот метод неэффективен, поскольку я имею дело с большим набором данных. Есть ли способ сделать это быстрее?
df_empty=pd.DataFrame()
df_empty['year']=""
for i in range(df.shape[0]):
row=df.iloc[i,]
for yr in range(row.start_year,row.end_year 1):
matched_row=pd.Series([],dtype=object)
matched_row['year']=yr
matched_row=pd.concat([matched_row,row[2:]],axis=0)
df_empty=df_empty.append(matched_row,ignore_index=True)
df_empty
year alter_id ego_id
0 2012 3311 1011
1 2013 3311 1011
2 2014 3311 1011
3 2015 3311 1011
4 2016 3311 1011
5 2016 9192 1011
6 2017 9192 1011
7 2006 1022 2211
8 2007 1022 2211
9 2008 1022 2211
10 2009 1022 2211
11 2010 1022 2211
12 2011 1022 2211
13 2012 1022 2211
14 2013 1022 2211
15 2014 1022 2211
16 2015 1022 2211
17 2016 1022 2211
Ответ №1:
Вы можете использовать понимание списка для создания списка года, а затем explode
:
print (df.assign(year=[list(range(lo, hi 1)) for lo, hi in df.filter(like="year").to_numpy()])
.explode("year")
.drop(["start_year", "end_year"], 1))
ego_id alter_id year
0 1011 3311 2012
0 1011 3311 2013
0 1011 3311 2014
0 1011 3311 2015
0 1011 3311 2016
1 1011 9192 2016
1 1011 9192 2017
2 2211 1022 2006
2 2211 1022 2007
2 2211 1022 2008
2 2211 1022 2009
2 2211 1022 2010
2 2211 1022 2011
2 2211 1022 2012
2 2211 1022 2013
2 2211 1022 2014
2 2211 1022 2015
2 2211 1022 2016
Комментарии:
1.Это работает отлично. У меня есть еще один столбец для добавления: duration_month представляет, как долго сохраняются отношения между ego и alter в месяц в течение года. Есть ли способ разнесения на основе столбца месяца?
data = { "start_yr": [2012], "end_yr": [2014], "start_mon": [1], "end_mon": [7], "ego": ["1"], "alter": ["3"], } df = pandas.DataFrame(data=data)
#desired outcome data = { "yr": [2012,2013,2014], "dur_mon": [12,12,7], "ego": ["1", "1","1"], "alter": ["3","3","3"], } df = pandas.DataFrame(data=data)
Ответ №2:
Это должно сработать:
import pandas
# Your data
data = {
"start_year": [2012, 2016, 2006],
"end_year": [2016, 2017, 2016],
"ego_id": ["1011", "1011", "2211"],
"alter_id": ["3311", "9192", "1022"],
}
df = pandas.DataFrame(data=data)
# Add a column with all the years in between the start and end
df["range"] = df.apply(lambda row: range(row["start_year"], row["end_year"] 1), axis=1)
# Create a new series that contains every year on a new line, maintaining the original index
years = df.apply(lambda x: pandas.Series(x["range"]), axis=1).stack().reset_index(level=1, drop=True)
years.name = "year"
# Join back to the original dataframe on the index
df = df.drop(columns=["range"]).join(years.astype(int))
df