#python #pandas
Вопрос:
У меня есть df, который выглядит так :
df = pd.DataFrame(data={
'id': ["idx1"],
'test_A': ["ABC", ],
'test_B': ["X"],
'test_C': ["ABC / XYZ"],
'test_D': ["ABC / JKL / XYZ"]})
Это пример для одной строки, но есть тысячи строк.
Я хочу разнести каждое значение, где в этих четырех «тестовых» столбцах есть несколько значений, т. Е. Я хочу, чтобы каждый из них дублировал строку для каждого из «тестов», которая одинакова, и если их много (разделено»/»), я тоже хочу дублировать. Я хочу «X», если дублирование ничего не содержит.
Конечно, есть много других столбцов, для которых значения не имеют значения для дублирования: они должны оставаться неизменными. Я не уверен, как это объяснить, но вот пример вывода, который я хочу получить для предоставленных мной входных данных:
df = pd.DataFrame(data={
'id': ["idx1", "idx1", "idx1"],
'test_A': ["ABC", "X", "X"],
'test_B': ["X", "X", "X"],
'test_C': ["ABC", "XYZ", "X"],
'test_D': ["ABC", "XYZ", "JKL"]})
Ответ №1:
Вот альтернатива, использующая вспомогательную функцию:
def split(df):
return (df.apply(lambda c: c.str.split(' / ')) # split cells
.apply(lambda x: x.explode().reset_index(drop=True)) # explode
.fillna({c: 'X' for c in df.filter(like='test_').columns}) # fill missing test with X
.ffill() # fill non-test columns
)
## single row
split(df)
## multiple rows
df.groupby('id').apply(split).droplevel(0)
выход:
id test_A test_B test_C test_D
0 idx1 ABC X ABC ABC
1 idx1 X X XYZ JKL
2 idx1 X X X XYZ
вывод на лучшем примере @jezrael:
id test_A test_B test_C test_D
0 idx1 ABC X ABC ABC
1 idx1 X X XYZ JKL
2 idx1 X X X XYZ
0 idx2 SSD "ABC aa ABC
1 idx2 X JKL X JKL
2 idx2 X XYZ X X
Ответ №2:
Образец:
df = pd.DataFrame(data={
'id': ["idx1", 'idx0'],
'test_A': ["ABC",'SSD' ],
'test_B': ["X", 'ABC / JKL / XYZ'],
'test_C': ["ABC / XYZ", 'aa'],
'test_D': ["ABC / JKL / XYZ", 'ABC / JKL']})
Идея состоит в том , чтобы сначала изменить DataFrame.melt
форму, затем использовать Series.str.split
и DataFrame.explode
и в последний раз использовать GroupBy.cumcount
счетчик со idx
столбцом, используемым для сортировки, и в последний раз изменить DataFrame.set_index
форму и Series.unstack
:
df1 = df.melt('id', ignore_index=False)
df1['value'] = df1['value'].str.split(' / ')
df1 = df1.explode('value').rename_axis('idx').reset_index()
g = df1.groupby(['idx','id','variable']).cumcount()
df1 = (df1.set_index([g,'idx','id','variable'])['value']
.unstack(fill_value='X')
.sort_index(level=1)
.reset_index(level=2)
.reset_index(drop=True)
.rename_axis(None, axis=1))
print (df1)
id test_A test_B test_C test_D
0 idx1 ABC X ABC ABC
1 idx1 X X XYZ JKL
2 idx1 X X X XYZ
3 idx0 SSD ABC aa ABC
4 idx0 X JKL X JKL
5 idx0 X XYZ X X