#python #python-3.x #pandas #dataframe #numpy
Вопрос:
Воспроизводимый пример:
ex = [{"explode1": ["a", "e", "i"], "word": "US_12", "explode2": []},
{"explode1": [], "word": "US_34", "explode2": ["a", "e", "i"]},
{"explode1": ["a", "e", "i"], "word": "US_56", "explode2": ["o", "u"]}]
df = pd.DataFrame(ex)
Дает тебе
explode1 word explode2
0 [a, e, i] US_12 []
1 [] US_34 [a, e, i]
2 [a, e, i] US_56 [o, u]
Вы можете предположить, что существует также столбец explode3
и explode4
(исключен для краткости)
Кадр данных о предполагаемом результате:
exploded_alphabet word exploded_type
0 a US_12 explode1
1 e US_12 explode1
2 i US_12 explode1
3 a US_34 explode2
4 e US_34 explode2
5 i US_34 explode2
6 a US_54 explode1
7 e US_54 explode1
8 i US_54 explode1
9 o US_34 explode2
10 u US_34 explode2
Решение должно быть воспроизводимым с 4 столбцами, а не только с 2, упомянутыми выше (я не включил их в свой пример explode3
и explode4
для той же краткости).
Таким образом, общее количество строк будет равно количеству элементов во всех списках в explode1
, explode2
, explode3
и explode4
сглажено.
Мои усилия:
Честно говоря, я думаю, что должен быть более короткий питонический способ, а не взрывать каждый по отдельности, а затем взрывать те, которые имеют несколько типов.
df = df.explode("explode1")
df = df.explode("explode2")
Вышесказанное неверно. Так как это не приводит к одновременному взрыву строк. Он создает дубликаты, если список не пуст в нескольких столбцах расширения.
Другой-непифонический способ, при котором вы повторяете строки, создаете и назначаете новый столбец — это долго и легко сделать. Но эта проблема, вероятно, была решена по-другому.
Чем мой вопрос отличается от другого вопроса «взорвать несколько столбцов»?:
- Взрывая их по отдельности. Каждый элемент в этих столбцах создает новую строку (вероятно, это уже есть в SO).
- Присвойте значение в
exploded_type
— Не уверен, что это было решено на SO в сочетании с 1.
Ответ №1:
Используйте DataFrame.melt
до explode
для отмены, а затем удалите строки с пропущенными значениями (из пустых списков):
df = (df.melt('word', value_name='exploded_alphabet', var_name='exploded_type')
.explode("exploded_alphabet")
.dropna(subset=['exploded_alphabet'])
.reset_index(drop=True))
print (df)
word exploded_type exploded_alphabet
0 US_12 explode1 a
1 US_12 explode1 e
2 US_12 explode1 i
3 US_56 explode1 a
4 US_56 explode1 e
5 US_56 explode1 i
6 US_34 explode2 a
7 US_34 explode2 e
8 US_34 explode2 i
9 US_56 explode2 o
10 US_56 explode2 u
Ответ №2:
вы можете stack
и тогда explode
:
result = df.set_index('word').stack().explode().dropna().reset_index(
name='exploded_alphabet').rename(columns={'level_1': 'exploded_type'})
выход:
word exploded_type exploded_alphabet
0 US_12 explode1 a
1 US_12 explode1 e
2 US_12 explode1 i
3 US_34 explode2 a
4 US_34 explode2 e
5 US_34 explode2 i
6 US_56 explode1 a
7 US_56 explode1 e
8 US_56 explode1 i
9 US_56 explode2 o
10 US_56 explode2 u
Производительность:
for _ in range(20):
df = df.append(df)
len(df) # 3145728
%%timeit
(
df.set_index('word')
.stack().
explode().
dropna().
reset_index(name='exploded_alphabet').
rename(columns={'level_1': 'exploded_type'})
)
4.77 s ± 62.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
(
df.melt('word', value_name='exploded_alphabet', var_name='exploded_type')
.explode("exploded_alphabet")
.dropna(subset=['exploded_alphabet'])
)
6.68 s ± 224 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
explode_columns = ['explode1', 'explode2']
pd.melt(
frame=df,
id_vars='word',
value_vars=explode_columns,
var_name='exploded_type',
value_name='exploded_alphabet'
).explode('exploded_alphabet').dropna()
7.17 s ± 109 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Комментарии:
1.
NOTE: Not tested for large dataframes.
— хммм, так в чем же тогда причина таймингов для небольших данных?2. Хммм… в этом есть смысл! Позвольте мне протестировать большие фреймы данных и добавить результаты.
![]()
Ответ №3:
Вы можете использовать pd.melt
, чтобы сложить столбцы, а затем взорвать их.
explode_columns = ['explode1', 'explode2']
pd.melt(
frame=df,
id_vars='word',
value_vars=explode_columns,
var_name='exploded_type',
value_name='exploded_alphabet'
).explode('exploded_alphabet').dropna()
Он не сохраняет тот же порядок, что и выше, но строки одинаковы.