data    field   bcorr
0   A   cs1 0.8
1   A   cs2 0.9
2   A   cs3 0.7
3   A   pq1 0.4
4   A   pq2 0.6
5   A   pq3 0.5
6   B   cs1 0.8
7   B   cs2 0.9
8   B   cs3 0.7
9   B   pq1 0.4
10  B   pq2 0.6
11  B   pq3 0.5

Dla wszystkich danych A i B w kolumnie data oddziel pola cs i pq z kolumny field, a następnie zagreguj, aby uzyskać 2 maksymalna wartość bcorr.

Przykładowy wynik byłby taki:

data    field   bcorr
0   A   cs1 0.8
1   A   cs2 0.9
4   A   pq2 0.6
5   A   pq3 0.5
6   B   cs1 0.8
7   B   cs2 0.9
10  B   pq2 0.6
11  B   pq3 0.5

W tym celu jedną z opcji jest zrobienie tego podczas tworzenia listy rekordów, która oczywiście będzie miała dużą złożoność.

Po drugie, chcę to zrobić z ramką danych pandas, gdzie użyłem groupby w kolumnie data, a następnie zastosowałem startswith, aby uzyskać źródło field, a następnie zastosowałem max

-2
ggupta 14 styczeń 2022, 11:59

4 odpowiedzi

Najpierw wyodrębnij wspólną część każdego pola (pierwsze litery), a następnie posortuj wartości (największe wartości idą w dół). Na koniec pogrupuj według kolumny data i serii field, a następnie zachowaj dwie ostatnie wartości (najwyższe):

field = df['field'].str.extract('([^\d]+)', expand=False)
out = df.sort_values('bcorr').groupby(['data', field]).tail(2).sort_index()
print(out)

# Output
   data field  bcorr
0     A   cs1    0.8
1     A   cs2    0.9
4     A   pq2    0.6
5     A   pq3    0.5
6     B   cs1    0.8
7     B   cs2    0.9
10    B   pq2    0.6
11    B   pq3    0.5

Jeśli pole ma tylko dwie stałe litery do określenia pola, możesz użyć df['field'].str[:2] zamiast df['field'].str.extract(...).

0
Corralien 14 styczeń 2022, 12:10

Możesz groupby w kolumnie pola daty i podciągu za pomocą str[:2], który przechwytuje znaki do drugiego i użyj head(2).

head zwraca pierwsze n wierszy, więc będziesz musiał wcześniej posortować dane.

df.sort_values(by=['data','bcorr'],ascending=False).groupby(['data',df.field.str[:2]]).head(2).sort_index()

  data field  bcorr
0     A   cs1    0.8
1     A   cs2    0.9
4     A   pq2    0.6
5     A   pq3    0.5
6     B   cs1    0.8
7     B   cs2    0.9
10    B   pq2    0.6
11    B   pq3    0.5

Podążając za powyższą logiką, używając tail(2) i sortując dane na odwrót, otrzymujesz ten sam wynik:

df.sort_values(by=['data','bcorr']).groupby(['data',df.field.str[:2]]).tail(2).sort_index()

EDYTUJ Jeśli chcesz uogólnić, aby zezwolić na dowolną liczbę niecyfrowych znaków w kolumnie pola, możesz użyć str.replace, aby zastąpić wszystkie znaki numeryczne pustymi w groupby:

df.sort_values(by=['data','bcorr']).groupby(['data',df.field.str.replace(r"[0-9]",'')]).tail(2).sort_index()
0
sophocles 14 styczeń 2022, 12:30
Nie uzyskanie maksymalnego bcorr
 – 
ggupta
14 styczeń 2022, 12:07
Zredagowałem odpowiedź. wcześniej istniała potrzeba sortowania wartości.
 – 
sophocles
14 styczeń 2022, 12:09
Byłoby wspaniale, gdybyśmy mogli uogólnić część df.field.str[:2]. nie zadziała, jeśli mamy pole zaczynające się od cs, abc.
 – 
ggupta
14 styczeń 2022, 12:19
Nie, nie będzie, jeśli masz więcej niż 2 postacie do zgrupowania. ale jeśli to masz, możesz grupować tylko używając znaków niecyfrowych, co powinno działać
 – 
sophocles
14 styczeń 2022, 12:21
Zredagowałem odpowiedź, aby zapewnić elastyczność, uprzejmie spójrz. Możesz również rzucić okiem na odpowiedź @Corralien, która również pozwala na tę elastyczność.
 – 
sophocles
14 styczeń 2022, 12:30

Oto jeden sposób:

(i) Utwórz nową kolumnę field_name z field, wybierając pierwsze elementy i użyj groupby na data i field_name i użyj nlargest, aby znaleźć dwie największe wartości dla każdej grupy do stworzenia serii temp

(ii) Używając indeksu temp utworzonego w (i), filtruj df

(iii) Przypisz temp do kolumny bcorr filtrowanej Dataframe z (ii)

temp = df.assign(field_name=df['field'].str[:2]).groupby(['data','field_name'])['bcorr'].nlargest(2).droplevel([0,1]).sort_index()
out = df.loc[temp.index]
out['bcorr'] = temp

Wynik:

   data field  bcorr
0     A   cs1    0.8
1     A   cs2    0.9
4     A   pq2    0.6
5     A   pq3    0.5
6     B   cs1    0.8
7     B   cs2    0.9
10    B   pq2    0.6
11    B   pq3    0.5
-1
enke 14 styczeń 2022, 12:12

Wierzę, że to jest coś, co próbujesz osiągnąć

import pandas as pd

df = {'data': ['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B'],
      'fie': ['cs1', 'cs2', 'cs3', 'pq1', 'pq2', 'pq3', 'cs1', 'cs2', 'cs3', 'pq1', 'pq2', 'pq3'],
      'bcorr': [0.8, 0.9, 0.7, 0.4, 0.6, 0.5, 0.8, 0.9, 0.7, 0.4, 0.6, 0.5]}

df = {'data': df['data'], 'fie_c': [x[:2] for x in df['fie']], 'fie_n': [x[2] for x in df['fie']],
      'bcorr': df['bcorr']}
df = pd.DataFrame(data=df)
df = df.sort_values('bcorr', ascending=False).groupby(by=['data', 'fie_c']).head(2).sort_values('data')
df['fie'] = df[['fie_c', 'fie_n']].apply(lambda x: '{}{}'.format(x[0], x[1]), axis=1)
df = df.drop(columns=['fie_c', 'fie_n'])
df = df[['data', 'fie', 'bcorr']]
print(df)

Wynik

   data  fie  bcorr
1     A  cs2    0.9
0     A  cs1    0.8
4     A  pq2    0.6
5     A  pq3    0.5
7     B  cs2    0.9
6     B  cs1    0.8
10    B  pq2    0.6
11    B  pq3    0.5

Zwróć uwagę, że kilka pierwszych linii może być bardziej przejrzystych, ale skupiłem się na linii

df = df.sort_values('bcorr', ascending=False).groupby(by=['data', 'fie_c']).head(2).sort_values('data')

Który wykonuje większość ważnej pracy.

-1
Trilokinath Modi 14 styczeń 2022, 15:46