У меня есть фрейм данных (панды), который я хочу преобразовать для отображения. Поэтому я хочу переместить некоторые части кадра данных в новые строки, как показано ниже:
col1 col2 col_to_shift col_not_to_shift1 col_not_to_shift2
0 a1 a2 a3 a4 a5
1 b1 b2 NaN b4 NaN
2 c1 c2 c3 c4 c5
Я хотел бы получить следующий фрейм данных, в котором создается новая строка для значения (если нет NaN
) в столбце для сдвига (уникального), дублируя описание данных, содержащееся в col1
и col2
, и сохраняя столбцы, которые мне не нужны. для смещения, даже если они содержат NaN:
col1 col2 col_to_shift col_not_to_shift1 col_not_to_shift2
0 a1 a2 a3 NaN NaN
1 a1 a2 NaN a4 a4
2 b1 b2 NaN b4 NaN
3 c1 c2 c3 NaN NaN
4 c1 c2 NaN c4 c4
Я попробовал посмотреть pd.shift
, но у меня не получилось.
Вот фрагмент кода для создания кадра данных:
data = {"col1": ['a1', 'b1', 'c1'], 'col2': ['a2', 'b2', 'c2'],
'col_to_shift': ['a3', np.NaN, 'c3'],
'col_not_to_shift1': ['a4', 'b4', 'c4'],
'col_not_to_shift2': ['a5', np.NaN, 'c5']}
df = pd.DataFrame(data)
Я пояснил, что это справедливо, потому что мой пример не полностью воспроизвел мой фрейм данных (в столбцах могут быть NaN, которые я не хочу сдвигать).
спасибо за разъяснение, тогда мой первый подход не сработает, а два других сработают (значок dropna='all'
важен)
По-прежнему здорово иметь другие варианты на случай, если чей-то фрейм данных не имеет NaN, как у меня, спасибо
Код
cols = ['col1', 'col2']
out = pd.concat([
df[cols + ['col_to_shift']].dropna(),
df[cols + ['col_not_to_shift']].dropna()
]).sort_index().reset_index(drop=True)
вне:
col1 col2 col_to_shift col_not_to_shift
0 a1 a2 a3 NaN
1 a1 a2 NaN a4
2 b1 b2 NaN b4
3 c1 c2 c3 NaN
4 c1 c2 NaN c4
Спасибо, это отлично работает, если col_not_to_shift
не содержит значения NaN, но это относится к моему фрейму данных, я обновил вопрос, чтобы отразить это.
Один из вариантов использования конката:
group = ['col1', 'col2']
cols = df.columns[df.columns.str.contains('not_to_shift')]
out = (pd.concat([df.drop(columns=cols).dropna(axis=0),
df[cols.union(group)].dropna(axis=0)
])
.sort_values(by=group, kind='stable')
)
Выход:
col1 col2 col_to_shift col_not_to_shift
0 a1 a2 a3 NaN
0 a1 a2 NaN a4
1 b1 b2 NaN b4
2 c1 c2 c3 NaN
2 c1 c2 NaN c4
Вариант с использованием индекса как группы (исходный индекс не сохраняется):
group = ['col1', 'col2']
not_shift = ['col_not_to_shift']
tmp = df.set_index(group)
out = (pd.concat([tmp.drop(columns=not_shift), tmp[not_shift]])
.dropna(how='all').sort_index(kind='stable')
.reset_index()
)
Или определив список столбцов для сдвига/не сдвига:
shift = ['col_to_shift']
not_shift = ['col_not_to_shift1', 'col_not_to_shift2']
out = (pd.concat([df.drop(columns=not_shift),
df.drop(columns=shift)
])
.dropna(subset=shift+not_shift, how='all')
.sort_index(kind='stable')
)
Выход:
col1 col2 col_to_shift col_not_to_shift1 col_not_to_shift2
0 a1 a2 a3 NaN NaN
0 a1 a2 NaN a4 a5
1 b1 b2 NaN b4 NaN
2 c1 c2 c3 NaN NaN
2 c1 c2 NaN c4 c5
С уточнением в вопросе второй вариант у меня работает так, как и ожидалось.
попробуй это
df1 = df[~df.col_to_shift.isnull()].drop(columns=['col_not_to_shift1', 'col_not_to_shift2'])
df2 = df[~df.col_to_shift.isnull()].drop(columns='col_to_shift')
pd.concat([df1, df2, df[df.col_to_shift.isnull()]], ignore_index=True).set_index(['col1', 'col2']).sort_index().reset_index()
Попробуй это:
((v:=df.set_index(['col1','col2']))
.set_axis([v.columns != 'col_to_shift',v.columns],axis=1)
.stack(level=0)
.droplevel(-1)
.reindex(v.columns,axis=1)
.reset_index())
Выход:
col1 col2 col_to_shift col_not_to_shift1 col_not_to_shift2
0 a1 a2 a3 NaN NaN
1 a1 a2 NaN a4 a5
2 b1 b2 NaN b4 NaN
3 c1 c2 c3 NaN NaN
4 c1 c2 NaN c4 c5
Можете ли вы уточнить, как это будет обобщаться, если у вас будет больше столбцов?