Как вставить строки в фрейм данных на основе последовательности?

#python #pandas #dataframe

Вопрос:

Итак, у меня есть этот фрейм данных. Столбцы «Время» следуют последовательности, в которой указаны все недели, которые находятся между первой и последней строками, заполненными в столбце. Но одно из значений, т. е. W43-2021, отсутствует.

Учитывая DF

Как вставить новую строку, соответствующую W43-2021, при этом все остальные значения столбцов будут либо такими же, как у других, либо отсутствуют, а «Значения» равны 0. В основном, как показано ниже в кадре данных.

Новый DF

Я попытался использовать приведенный ниже подход для решения этой проблемы.

 f = int(df['Time.[Week]'][0][1:3]) l = int(df['Time.[Week]'].iloc[-1][1:3]) check = list(df['Time.[Week]'].str[1:3]) check = list(map(int, check)) c = [] for i in range(f, l 1):  if i not in check:  c.append(i) for week in c:  temp_df = pd.DataFrame(columns = df.columns)   temp_df.loc[0, 'Time.[Week]'] = 'W'   str(week)   '-2021'  df.append(temp_df)  

Это не кажется наиболее подходящим способом решения проблемы, поскольку порядок нарушается из-за добавления фрейма данных в конце, и может быть несколько отсутствующих строк, которые могут возникнуть позже. Что может быть лучшим и более питоническим способом решения этого дела?

Также найдите код для запуска df, если это необходимо.

 df = pd.DataFrame([[33534,9132,'Current','W41-2021',34],  [33534,9132,'Current','W42-2021', 45],  [33534,9132,'Current','W44-2021', 32],  [33534,9132,'Current','W45-2021', 41],  [33534,9132,'Current','W46-2021',49]], columns = ['Item', 'Location', 'Version', 'Time', 'Value'])  

Ответ №1:

Вы можете использовать следующее:

 # build missing values weeks = df['Time'].str.extract('(?lt;=W)(d )').astype(int) idx = [f'W{w}-2021' for w in range(weeks.min()[0], weeks.max()[0] 1)]  # add missing values df2 = df.set_index('Time').reindex(idx).reset_index()  # ffill, except 'Value' df2 = df2.combine_first(df2.drop(columns='Value').ffill())[df.columns]  

выход:

 gt;gt;gt; df2  Item Location Version Time Value 0 33534.0 9132.0 Current W41-2021 34.0 1 33534.0 9132.0 Current W42-2021 45.0 2 33534.0 9132.0 Current W43-2021 NaN 3 33534.0 9132.0 Current W44-2021 32.0 4 33534.0 9132.0 Current W45-2021 41.0 5 33534.0 9132.0 Current W46-2021 49.0  

Ответ №2:

Воспользуйся —

 df['week'] = df['Time'].str[1:3].astype(int) df2 = pd.DataFrame([ i for i in range(week.min(), week.max())], columns=['week']).merge(df, how='outer') fill_val = df['Time'].iloc[0] df2['Time'] = df2['Time'].fillna(fill_val[0] df2['week'].astype(str) fill_val[3:]) df2 = df2.fillna(0)  

Выход

 week Time Value 0 41 W41-2021 34.0 1 42 W42-2021 45.0 2 43 W43-2021 0.0 3 44 W44-2021 32.0 4 45 W45-2021 41.0 5 46 W46-2021 49.0  

Ответ №3:

Ты можешь так поступить:

Код:

 df = pd.DataFrame([[33534,9132,'Current','W41-2021',34],  [33534,9132,'Current','W42-2021', 45],  [33534,9132,'Current','W44-2021', 32],  [33534,9132,'Current','W45-2021', 41],  [33534,9132,'Current','W46-2021',49]], columns = ['Item', 'Location', 'Version', 'Time', 'Value'])  new_df = df.copy(deep=True) new_df = new_df.append(pd.DataFrame([[33534,9132,'Current','W43-2021',0]],columns=['Item', 'Location', 'Version', 'Time', 'Value'])) new_df = new_df.sort_values("Time",ascending=True) print(new_df)  

Поскольку время упорядочено, вы можете просто добавить новое значение, а затем отсортировать значения в соответствии со временем.

Выход:

 Item Location Version Time Value 0 33534 9132 Current W41-2021 34 1 33534 9132 Current W42-2021 45 0 33534 9132 Current W43-2021 0 2 33534 9132 Current W44-2021 32 3 33534 9132 Current W45-2021 41 4 33534 9132 Current W46-2021 49  

Ответ №4:

Вариант 1 с merge() обработкой любых лет с фактическим количеством недель, НЕ сохраняйте тип столбца (целое число становится плавающим)

 import pandas as pd  df = pd.DataFrame([[33534, 9132, 'Current', 'W41-2021', 34],  [33534, 9132, 'Current', 'W42-2021', 45],  [33534, 9132, 'Current', 'W44-2021', 32],  [33534, 9132, 'Current', 'W45-2021', 41],  [33535, 5555, 'Current', 'W44-2022', 132],  [33535, 5555, 'Current', 'W45-2022', 141],  [33534, 9132, 'Current', 'W46-2021', 49]], columns=['Item', 'Location', 'Version', 'Time', 'Value'])  def yproc(gd):  year = gd.Time.iloc[0].split('-')[1] # get the year from the group  # compose a complete sequence like WNN-YYYY from all week numbers in a particular year  ts = pd.Series([f'W{x 1:02d}-{year}' for x in pd.Series(pd.date_range(f'{year}-01-01',f'{year}-12-31',freq='W')).index],name='Time')  d = gd.merge(ts, how='outer').sort_values('Time') # merge the df with the sequence  d['Value'].fillna(0, inplace=True) # fill the values in the added rows  return d.fillna(method='ffill').fillna(method='bfill') # fill other fields and return  y = df.Time.str.split('-', expand=True)[1] # make a sequence to group by year df1 = df1 = df.groupby(y, as_index=False, group_keys=False).apply(yproc) # grop by year and apply the function print(df1.iloc[40:60,:])  

Выход:

 Item Location Version Time Value 0 33534.0 9132.0 Current W41-2021 34.0 1 33534.0 9132.0 Current W42-2021 45.0 45 33534.0 9132.0 Current W43-2021 0.0 2 33534.0 9132.0 Current W44-2021 32.0 3 33534.0 9132.0 Current W45-2021 41.0 4 33534.0 9132.0 Current W46-2021 49.0 46 33534.0 9132.0 Current W47-2021 0.0 47 33534.0 9132.0 Current W48-2021 0.0 48 33534.0 9132.0 Current W49-2021 0.0 49 33534.0 9132.0 Current W50-2021 0.0 50 33534.0 9132.0 Current W51-2021 0.0 51 33534.0 9132.0 Current W52-2021 0.0 2 33535.0 5555.0 Current W01-2022 0.0 3 33535.0 5555.0 Current W02-2022 0.0 4 33535.0 5555.0 Current W03-2022 0.0 5 33535.0 5555.0 Current W04-2022 0.0 6 33535.0 5555.0 Current W05-2022 0.0 7 33535.0 5555.0 Current W06-2022 0.0 8 33535.0 5555.0 Current W07-2022 0.0 9 33535.0 5555.0 Current W08-2022 0.0  

Вариант 2 с concat() обработкой любых лет с фактическим количеством недель, сохраните тип столбца (т. е. целое число)

 # df = ...  def yproc(gd):  year = gd.Time.iloc[0].split('-')[1] # get the year from the group  # compose a complete sequence like WNN-YYYY from all actual week numbers in a particular year  ts = pd.Series(  [f'W{x   1:02d}-{year}' for x in range(pd.date_range(f'{year}-01-01', f'{year}-12-31', freq='W').size)],  name='Time')  repeated = pd.concat([gd.take([0])] * ts.size, ignore_index=True) # replicate one row nth times depend of weeks number  repeated.Value, repeated.Time = 0, ts # replace Value with 0, Time with ts  d = pd.concat([gd, repeated]).drop_duplicates(['Time'], keep='first').sort_values('Time')  return d   y = df.Time.str.split('-', expand=True)[1] # make a sequence to group by year df1 = df.groupby(y, as_index=False, group_keys=False).apply(yproc) # grop by year and apply the function print(df1.iloc[39:60, :])  
 Item Location Version Time Value 39 33534 9132 Current W40-2021 0 0 33534 9132 Current W41-2021 34 1 33534 9132 Current W42-2021 45 42 33534 9132 Current W43-2021 0 2 33534 9132 Current W44-2021 32 3 33534 9132 Current W45-2021 41 6 33534 9132 Current W46-2021 49 46 33534 9132 Current W47-2021 0 ...