#python #python-3.x #pandas #dataframe
#python #python-3.x #панды #фрейм данных
Вопрос:
У меня есть df, подобный этому:
time units cost
0 4 10
1 2 10
3 4 20
4 1 20
5 3 10
6 1 20
9 2 10
Как вы можете видеть, df.time
не является последовательным. Если отсутствует значение, я хочу добавить новую строку, df.time
заполнив последовательным значением времени, df.units
с 2
помощью и df.cost
с 20
помощью .
Ожидаемый результат:
time units cost
0 4 10
1 2 10
2 2 20
3 4 20
4 1 20
5 3 10
6 1 20
7 2 20
8 2 20
9 2 10
Как мне это сделать? Я понимаю, как это сделать, разбирая все ряды на списки, просматривая их и добавляя значения, когда время не равно времени — 1, но это кажется неэффективным.
Ответ №1:
Для этого можно использовать reindex
метод с вызовом fillna
:
# Build new index that ranges from time min to time max with a step of 1
new_index = range(df["time"].min(), df["time"].max() 1)
out = (df.set_index("time") # Index our dataframe with the original time column
.reindex(new_index) # Reindex our dataframe with the new_index, all empty cells appear as nan
.fillna({"units": 2, "cost": 20}) # Fill in the nans for units and cost with 2 and 20 respectively
.astype(int)) # Due to NaNs that were in column from reindexing, we'll manually recast our
# data type from float to int (not necessary, but produces cleaner output)
print(out)
units cost
time
0 4 10
1 2 10
2 2 20
3 4 20
4 1 20
5 3 10
6 1 20
7 2 20
8 2 20
9 2 10
Комментарии:
1.
fillna
take dict забыл об этом. 1
Ответ №2:
Тогда вы можете использовать df.reindex
pd.Series.fillna
.
idx = pd.RangeIndex(df['time'].min(), df['time'].max() 1)
# If `df.time` is always sorted then,
# idx = pd.RangeIndex(df['time'].iat[0], df['time'].iat[-1] 1)
df = df.set_index('time')
df = df.reindex(idx)
df['units'] = df['units'].fillna(2).astype(int)
df['cost'] = df['cost'].fillna(20).astype(int)
# if you prefer not to hard-code the names of the columns, replace last
# the two lines with:
# defaults = [2,20]
# for (name, default) in zip(df.columns, defaults):
# df[name] = df[name].fillna(default).astype(type(default))
units cost
time
0 4 10
1 2 10
2 2 20
3 4 20
4 1 20
5 3 10
6 1 20
7 2 20
8 2 20
9 2 10
Комментарии:
1. Собираюсь отредактировать это с предложением в качестве комментария — не стесняйтесь редактировать дальше, чтобы либо включить это в фактический код, либо отменить мою правку, как вы считаете нужным…
Ответ №3:
Вы можете создать новый фрейм данных с полным столбцом «time», а затем выполнить .fillna()
из исходного фрейма данных ( df
это ваш исходный фрейм данных):
r = range(df['time'].min(), df['time'].max() 1)
df_out = pd.DataFrame({'time': r, 'units': [np.nan]*len(r), 'cost': [np.nan]*len(r)}).set_index('time')
df_out = df_out.fillna(df.set_index('time'))
df_out['units'] = df_out['units'].fillna(2).astype(int)
df_out['cost'] = df_out['cost'].fillna(20).astype(int)
print(df_out)
С принтами:
units cost
time
0 4 10
1 2 10
2 2 20
3 4 20
4 1 20
5 3 10
6 1 20
7 2 20
8 2 20
9 2 10