#python #pandas
#python #панды
Вопрос:
У меня есть следующий фрейм данных pandas с индексом слева:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
A17 a b 1 AUG) NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
nn6 c d 2 POS) e f 2 Hi)
AZV NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
JFK a b 4 UUI) c v 8 Yo) t f 9 po)
Я хочу изменить его форму, чтобы:
0 1 2 3
A17 a b 1 AUG)
nn6 c d 2 POS)
nn6 e f 2 Hi)
AZV NaN NaN NaN NaN
JFK a b 4 UUI)
JFK c v 8 Yo)
JFK t f 9 po
Я пробовал reshape()
и использовал itertools
итерацию по столбцам, но, похоже, до сих пор не могу ее получить.
По сути, каждый раз, когда встречается a), затем переходите на новую строку. Реальная таблица содержит более 150 столбцов.
Спасибо
Комментарии:
1. Всегда ли значения кратны четырем?
Ответ №1:
Другой вариант, который не требует перебора строк (который может быть очень медленным, если их много), — это выполнить следующее
[ins] In [1]: df
Out[1]:
0 1 2 3 4 5 6 7
A17 a b 1 AUG) NaN NaN NaN NaN
nn6 c d 2 POS) e f 2 HI)
AVZ NaN NaN NaN NaN NaN NaN NaN
[ins] In [2]: joined = df.apply(lambda x: ' '.join([str(xi) for xi in x]), axis=1)
[ins] In [4]: split = joined.str.split(')', expand=True).reset_index(drop=False).melt(id_vars='index')
[ins] In [6]: split.drop('variable', axis=1, inplace=True)
[ins] In [7]: split
Out[7]:
index value
0 A17 a b 1 AUG
1 nn6 c d 2 POS
2 AVZ nan nan nan nan nan nan nan
3 A17 nan nan nan nan
4 nn6 e f 2 HI
5 AVZ None
6 A17 None
7 nn6
8 AVZ None
[ins] In [8]: sel = split['value'].str.strip().str.len() > 0
[ins] In [9]: split = split.loc[sel, :]
[ins] In [9]: split
Out[9]:
index value
0 A17 a b 1 AUG
1 nn6 c d 2 POS
2 AVZ nan nan nan nan nan nan nan
3 A17 nan nan nan nan
4 nn6 e f 2 HI
[ins] In [10]: out = split['value'].str.strip().str.split(' ', expand=True)
[ins] In [11]: out.index = split['index']
[ins] In [12]: out
Out[12]:
0 1 2 3 4 5 6
index
A17 a b 1 AUG None None None
nn6 c d 2 POS None None None
AVZ nan nan nan nan nan nan nan
A17 nan nan nan nan None None None
nn6 e f 2 HI None None None
а затем нужно отбросить с 4-го по 6-й столбец, что очень просто.
Я добавил некоторые выходные данные, чтобы вы могли видеть, что происходит на каждом шаге.
Комментарии:
1. Спасибо, протестировано на df с 10 000 строк и> 800 столбцов. Сработало быстро.
2. Apply перебирает строки, он не использует операции на основе набора. удивлен, что это решение сработало быстро
3. @Manakin, обратите внимание на аргумент оси. Apply работает со столбцами, рассматривая каждый из них как серию. Таким образом, количество циклов определяется количеством столбцов, а не строк.
Ответ №2:
Я думаю, что эффективным способом объединения значений было бы разделить фрейм данных на 4 равные части и повторно объединить его по индексу.
Проблема здесь заключается в именах столбцов, которые мы можем динамически переименовывать внутри оператора concat.
import numpy as np
lst = np.array_split([i for i in range(len(df.columns))],4)
[array([0, 1, 2, 3]),
array([4, 5, 6, 7]),
array([ 8, 9, 10, 11]),
array([12, 13, 14])]
dfs = pd.concat( [
df.iloc[:,i].rename(columns=
dict(zip(df.iloc[:,i].columns,range(4)))
)
for i in lst
]).dropna(how='all')
print(dfs)
0 1 2 3
A17 a b 1.0 AUG)
nn6 c d 2.0 POS)
JFK a b 4.0 UUI)
nn6 e f 2.0 Hi)
JFK c v 8.0 Yo)
JFK t f 9.0 po)
единственная разница здесь в том, что вам не хватает строки из желаемого результата из-за того, что она является na.
мы можем выполнить объединение с combine_first
, чтобы получить дельту между двумя фреймами данных.
dfs = dfs.combine_first(df.iloc[:,:0])
print(dfs)
0 1 2 3
A17 a b 1.0 AUG)
AZV NaN NaN NaN NaN
JFK a b 4.0 UUI)
JFK c v 8.0 Yo)
JFK t f 9.0 po)
nn6 c d 2.0 POS)
nn6 e f 2.0 Hi)
Ответ №3:
Есть и другие варианты, такие как нарезка столбцов и добавление, но это довольно просто.
output = []
for index, row in df.iterrows():
r = row.dropna().values
if len(r) <= 4:
output.append([index,*r])
else:
for x in np.reshape(r, (int(len(r)/4),4)):
output.append([index,*x])
pd.DataFrame(output).set_index(0)