#python #pandas #dataframe
Вопрос:
В моем фрейме данных есть несколько столбцов, представляющих конкретные измерения для разных образцов, и количество строк (точек измерения) для каждого образца не одинаковое. например
df=
p1 v1 dv1 p9 v9 dv9 p21 v21 dv21 p26 v26 r26 dv26
0 0.977966 0.000544 NaN 0.928902 0.000000 NaN 1.140129 0.000000 NaN 1.002083 0.000000 106.478206 NaN
1 1.022041 0.001087 0.000543 0.953850 0.000000 0.000000 1.175056 0.000153 0.000153 1.079422 0.000208 98.849199 0.000208
2 1.050316 0.001268 0.000181 0.984619 0.000000 0.000000 1.204163 0.000153 0.000000 1.140961 0.000208 93.517657 0.000000
3 1.082748 0.001268 0.000000 1.010399 0.000261 0.000261 1.224953 0.000153 0.000000 1.249901 0.000208 85.366761 0.000000
4 1.109360 0.001268 0.000000 1.031189 0.000261 0.000000 1.247406 0.000153 0.000000 1.314766 0.000208 81.155126 0.000000
5 1.127655 0.001268 0.000000 1.056969 0.000261 0.000000 1.277344 0.000306 0.000153 1.459465 0.000417 73.108982 0.000209
6 1.160087 0.001268 0.000000 1.086075 0.000261 0.000000 1.302292 0.000459 0.000153 1.629112 0.000624 65.495804 0.000208
7 1.209152 0.001268 0.000000 1.117676 0.000392 0.000131 1.328072 0.000459 0.000000 1.658218 0.000624 64.346184 0.000000
8 1.259048 0.001268 0.000000 1.151772 0.000392 0.000000 1.370483 0.000612 0.000153 1.748863 0.000624 61.011068 0.000000
9 1.283165 0.001268 0.000000 1.180878 0.000392 0.000000 1.399590 0.000612 0.000000 1.920174 0.000624 55.567881 0.000000
10 1.362167 0.001268 0.000000 1.227448 0.000392 0.000000 1.426201 0.000612 0.000000 2.064041 0.000833 51.694710 0.000209
11 1.446991 0.001449 0.000181 1.278175 0.000392 0.000000 1.475266 0.000612 0.000000 2.252815 0.000833 47.362966 0.000000
12 1.473602 0.001630 0.000181 1.297302 0.000522 0.000130 1.541794 0.000765 0.000153 2.432442 0.000833 43.865383 0.000000
13 1.667366 0.001630 0.000000 1.316429 0.000522 0.000000 1.639923 0.000765 0.000000 2.614563 0.000833 40.809879 0.000000
14 1.837845 0.001630 0.000000 1.344704 0.000652 0.000130 1.712273 0.000919 0.000153 2.812485 0.000833 37.937980 0.000000
15 2.042419 0.001630 0.000000 1.412063 0.000783 0.000131 1.861130 0.000919 0.000000 2.984627 0.000833 35.749861 0.000000
16 2.222878 0.001630 0.000000 1.476929 0.000783 0.000000 2.029114 0.001531 0.000612 3.014565 0.001041 35.394825 0.000208
17 2.256142 0.001630 0.000000 1.497719 0.000913 0.000130 2.052398 0.001531 0.000000 3.169243 0.001041 33.667346 0.000000
18 2.422463 0.001630 0.000000 1.672356 0.001305 0.000392 2.163834 0.001531 0.000000 3.354691 0.001041 31.806208 0.000000
19 2.602089 0.001630 0.000000 1.833687 0.001566 0.000261 2.343460 0.001837 0.000306 3.386292 0.001041 31.509391 0.000000
20 2.634522 0.001630 0.000000 1.857803 0.001696 0.000130 2.496475 0.001837 0.000000 3.565086 0.001041 29.929152 0.000000
21 2.821633 0.001812 0.000181 1.880257 0.001696 0.000000 2.683586 0.001990 0.000153 3.772987 0.001041 28.279981 0.000000
Я хочу создать новый фрейм данных, содержащий значения строк, соответствующие dv1>0>, dv9>0>.и т.д. Здесь я хочу отфильтровать все соответствующие столбцы одного и того же образца (p1 v1 и т. Д.), Когда условие удовлетворяет (dv>0) и показывает значения соответствующей строки, например, когда dv1>>0, он должен показывать значения строки p1, v1 и dv1 аналогично, когда dv9>>>0 он должен посеять соответствующие строки p9, v9 и dv9.
когда я подаю df_new=df[df.dv1>0] #filter value >0
заявку , она применяется ко всем столбцам
Что я могу сделать для достижения этой цели? Любая помощь в этом отношении высоко ценится.
результат желания должен быть таким
Ответ №1:
Есть вариант с wide_to_long
, если вы знаете все префиксы:
out = (pd.wide_to_long(df.reset_index(), # temporary make index
stubnames=['p','v','dv','r'], # the prefixes
i='index', j='enum')
.query('dv>0') # filter here
.reset_index('index', drop=True) # remove the old index
)
out = (out.set_index(out.groupby('enum').cumcount(), append=True) # enumerate within each suffix 1, 9, etc
.unstack('enum').sort_index(level=[1,0], axis=1) # unstack to get long
.dropna(how='all', axis=1) # drop empty columns
)
out.columns = [f'{x}{y}' for x,y in out.columns] # rename columns
Ответ №2:
Комбинация некоторых вспомогательных функций pyjanitor, в частности pivot_longer и pivot_wider, может помочь в процессе изменения формы :
# pip install pyjanitor
import pandas as pd
import janitor as jn
# reshape based on a regex
# the part of the column associated with .value
# stays as the header,
# while the other part goes to `num` column
# you do not need to know all the prefixes
# as long as your regex is correct
outcome = (df.pivot_longer(names_to=('.value', 'num'),
names_pattern = r"([a-z] )(d )")
.query('dv > 0')
# cumcount used here to get a unique index
# when flipping back to wide form
.assign(counter = lambda df: df.groupby('num').cumcount())
# wrapper around `pivot`, makes collapsing levels a bit easier
.pivot_wider(index='counter', names_from='num', names_sep='')
.drop(columns='counter')
.dropna(how='all', axis = 1)
)
outcome
p1 p21 p26 p9 v1 v21 v26 v9 dv1 dv21 dv26 dv9 r26
0 1.022041 1.175056 1.079422 1.010399 0.001087 0.000153 0.000208 0.000261 0.000543 0.000153 0.000208 0.000261 98.849199
1 1.050316 1.277344 1.459465 1.117676 0.001268 0.000306 0.000417 0.000392 0.000181 0.000153 0.000209 0.000131 73.108982
2 1.446991 1.302292 1.629112 1.297302 0.001449 0.000459 0.000624 0.000522 0.000181 0.000153 0.000208 0.000130 65.495804
3 1.473602 1.370483 2.064041 1.344704 0.001630 0.000612 0.000833 0.000652 0.000181 0.000153 0.000209 0.000130 51.694710
4 2.821633 1.541794 3.014565 1.412063 0.001812 0.000765 0.001041 0.000783 0.000181 0.000153 0.000208 0.000131 35.394825
5 NaN 1.712273 NaN 1.497719 NaN 0.000919 NaN 0.000913 NaN 0.000153 NaN 0.000130 NaN
6 NaN 2.029114 NaN 1.672356 NaN 0.001531 NaN 0.001305 NaN 0.000612 NaN 0.000392 NaN
7 NaN 2.343460 NaN 1.833687 NaN 0.001837 NaN 0.001566 NaN 0.000306 NaN 0.000261 NaN
8 NaN 2.683586 NaN 1.857803 NaN 0.001990 NaN 0.001696 NaN 0.000153 NaN 0.000130 NaN
Чтобы фрейм данных выглядел так же, как в вашем файле Excel, вы можете отсортировать столбцы:
outcome.sort_index(axis = 1,
key = lambda df: df.str.extract("(d )", expand=False)
.astype(int))
p1 v1 dv1 p9 v9 dv9 p21 v21 dv21 p26 v26 dv26 r26
0 1.022041 0.001087 0.000543 1.010399 0.000261 0.000261 1.175056 0.000153 0.000153 1.079422 0.000208 0.000208 98.849199
1 1.050316 0.001268 0.000181 1.117676 0.000392 0.000131 1.277344 0.000306 0.000153 1.459465 0.000417 0.000209 73.108982
2 1.446991 0.001449 0.000181 1.297302 0.000522 0.000130 1.302292 0.000459 0.000153 1.629112 0.000624 0.000208 65.495804
3 1.473602 0.001630 0.000181 1.344704 0.000652 0.000130 1.370483 0.000612 0.000153 2.064041 0.000833 0.000209 51.694710
4 2.821633 0.001812 0.000181 1.412063 0.000783 0.000131 1.541794 0.000765 0.000153 3.014565 0.001041 0.000208 35.394825
5 NaN NaN NaN 1.497719 0.000913 0.000130 1.712273 0.000919 0.000153 NaN NaN NaN NaN
6 NaN NaN NaN 1.672356 0.001305 0.000392 2.029114 0.001531 0.000612 NaN NaN NaN NaN
7 NaN NaN NaN 1.833687 0.001566 0.000261 2.343460 0.001837 0.000306 NaN NaN NaN NaN
8 NaN NaN NaN 1.857803 0.001696 0.000130 2.683586 0.001990 0.000153 NaN NaN NaN NaN
Ответ №3:
Вы можете сделать это:
df_new = df[df['dv1']>0][['p1', 'v1', 'dv1']]