Замените ближайшие значения на среднее (или минимальное/максимальное) и сохраните ровно две строки по идентификатору, если все значения по идентификатору равны

#pandas

Вопрос:

У меня есть фрейм данных, который выглядит так:

 df_segments = 

         id  seg_length
15  000b994d-1a6b-4698-a270-b0f671b1e612        16.3
11  000b994d-1a6b-4698-a270-b0f671b1e612         1.1
3   000b994d-1a6b-4698-a270-b0f671b1e612         1.1
7   000b994d-1a6b-4698-a270-b0f671b1e612        16.3
31  016490a8-8740-4205-bfe4-c9fe45e853d3         1.0
27  016490a8-8740-4205-bfe4-c9fe45e853d3         1.4
19  016490a8-8740-4205-bfe4-c9fe45e853d3         1.4
23  016490a8-8740-4205-bfe4-c9fe45e853d3         1.0
39  05290fe1-ead2-462b-bbec-a7669eed7883         1.1
35  05290fe1-ead2-462b-bbec-a7669eed7883         1.4
47  05290fe1-ead2-462b-bbec-a7669eed7883         1.1
43  05290fe1-ead2-462b-bbec-a7669eed7883         1.4
63  0537a9e3-09c4-459c-a6e4-25694cfbacbd         1.1
59  0537a9e3-09c4-459c-a6e4-25694cfbacbd         1.4
51  0537a9e3-09c4-459c-a6e4-25694cfbacbd         1.4
55  0537a9e3-09c4-459c-a6e4-25694cfbacbd         1.1
71  05577c2e-da7d-4753-bba6-66762385e159         1.0
67  05577c2e-da7d-4753-bba6-66762385e159         5.4
79  05577c2e-da7d-4753-bba6-66762385e159         1.0
75  05577c2e-da7d-4753-bba6-66762385e159         5.4
1475  5a104c86-327e-466f-b14a-6953cacddcbb         0.5
1479  5a104c86-327e-466f-b14a-6953cacddcbb         0.5
1487  5a104c86-327e-466f-b14a-6953cacddcbb         0.5
1483  5a104c86-327e-466f-b14a-6953cacddcbb         0.5
2287  8e853797-a7f3-4605-8848-f6b211f9b055         2.1
2283  8e853797-a7f3-4605-8848-f6b211f9b055         2.1
2279  8e853797-a7f3-4605-8848-f6b211f9b055         2.1
2275  8e853797-a7f3-4605-8848-f6b211f9b055         2.1
3351  c1120018-c626-4c1b-81a5-476ce38f346b         0.6
3347  c1120018-c626-4c1b-81a5-476ce38f346b         1.2
3359  c1120018-c626-4c1b-81a5-476ce38f346b         0.5
3355  c1120018-c626-4c1b-81a5-476ce38f346b         1.2
 

Все id они имеют четыре ряда. Для большинства id удаление дубликатов приводит к появлению двух строк. Но в течение нескольких id секунд может произойти одно из двух:

  1. Либо все строки равны, и в этом случае drop_duplicates() получится одна строка.
  2. drop_duplicates() с результатом в три или для строк, потому что все значения seg_length разные.

Однако все seg_length они имеют длину сторон в прямоугольнике (или очень близко к нему) и квадратах. Итак, я хотел бы сделать следующие вещи:

О. Если все строки по идентификатору имеют одинаковое seg_length значение, сохраните две строки.

B. Замените два самых больших (соответственно, самых маленьких) значения (по идентификатору) на их среднее значение. Другими словами:

 df_segments = 

         id  seg_length
3351  c1120018-c626-4c1b-81a5-476ce38f346b         0.6
3347  c1120018-c626-4c1b-81a5-476ce38f346b         1.2
3359  c1120018-c626-4c1b-81a5-476ce38f346b         0.5
3355  c1120018-c626-4c1b-81a5-476ce38f346b         1.2
 

стал бы:

 df_segments = 

         id  seg_length
3351  c1120018-c626-4c1b-81a5-476ce38f346b         0.55
3347  c1120018-c626-4c1b-81a5-476ce38f346b         1.2
3359  c1120018-c626-4c1b-81a5-476ce38f346b         0.55
3355  c1120018-c626-4c1b-81a5-476ce38f346b         1.2
 

В качестве альтернативы, используйте min/max , если это проще:

 df_segments = 

         id  seg_length
3351  c1120018-c626-4c1b-81a5-476ce38f346b         0.6
3347  c1120018-c626-4c1b-81a5-476ce38f346b         1.2
3359  c1120018-c626-4c1b-81a5-476ce38f346b         0.6
3355  c1120018-c626-4c1b-81a5-476ce38f346b         1.2
 

Я пытался использовать np.where и определять условия, но безрезультатно. Я также попытался создать отдельный фрейм данных с идентификаторами, количество которых не равнялось 2, после удаления дубликатов из исходного фрейма данных, df_segments но я оказался в той же ситуации.

Если у кого-то есть идея, я был бы благодарен за понимание.

Ответ №1:

Если я хорошо понимаю, вы хотите усреднить значения 2 на 2 в каждом идентификаторе. Это также происходит, чтобы сделать то, что вы хотите, когда оно в 4 раза превышает одно и то же значение.

 >>> averages = df.groupby('id')['seg_length'].apply(
... lambda s: s.sort_values().groupby([0, 0, 1, 1]).mean()
... )
>>> averages
id                                     
000b994d-1a6b-4698-a270-b0f671b1e612  0     1.10
                                      1    16.30
016490a8-8740-4205-bfe4-c9fe45e853d3  0     1.00
                                      1     1.40
05290fe1-ead2-462b-bbec-a7669eed7883  0     1.10
                                      1     1.40
0537a9e3-09c4-459c-a6e4-25694cfbacbd  0     1.10
                                      1     1.40
05577c2e-da7d-4753-bba6-66762385e159  0     1.00
                                      1     5.40
5a104c86-327e-466f-b14a-6953cacddcbb  0     0.50
                                      1     0.50
8e853797-a7f3-4605-8848-f6b211f9b055  0     2.10
                                      1     2.10
c1120018-c626-4c1b-81a5-476ce38f346b  0     0.55
                                      1     1.20
Name: seg_length, dtype: float64
 

Если вы хотите сохранить исходную форму, вы можете использовать transform (на обоих groupby ):

 >>> replaced_seglengths = df.groupby('id')['seg_length'].transform(
... lambda s: s.sort_values().groupby([0, 0, 1, 1]).transform('mean')
... )
>>> replaced_seglengths
15       1.10
11       1.10
3       16.30
7       16.30
31       1.00
27       1.00
19       1.40
23       1.40
39       1.10
35       1.10
47       1.40
43       1.40
63       1.10
59       1.10
51       1.40
55       1.40
71       1.00
67       1.00
79       5.40
75       5.40
1475     0.50
1479     0.50
1487     0.50
1483     0.50
2287     2.10
2283     2.10
2279     2.10
2275     2.10
3351     0.55
3347     0.55
3359     1.20
3355     1.20
 

Наконец, замените столбец в фрейме данных:

 >>> df['seg_length'] = replaced_seglengths
>>> df
                                        id  seg_length
15    000b994d-1a6b-4698-a270-b0f671b1e612        1.10
11    000b994d-1a6b-4698-a270-b0f671b1e612        1.10
3     000b994d-1a6b-4698-a270-b0f671b1e612       16.30
7     000b994d-1a6b-4698-a270-b0f671b1e612       16.30
31    016490a8-8740-4205-bfe4-c9fe45e853d3        1.00
27    016490a8-8740-4205-bfe4-c9fe45e853d3        1.00
19    016490a8-8740-4205-bfe4-c9fe45e853d3        1.40
23    016490a8-8740-4205-bfe4-c9fe45e853d3        1.40
39    05290fe1-ead2-462b-bbec-a7669eed7883        1.10
35    05290fe1-ead2-462b-bbec-a7669eed7883        1.10
47    05290fe1-ead2-462b-bbec-a7669eed7883        1.40
43    05290fe1-ead2-462b-bbec-a7669eed7883        1.40
63    0537a9e3-09c4-459c-a6e4-25694cfbacbd        1.10
59    0537a9e3-09c4-459c-a6e4-25694cfbacbd        1.10
51    0537a9e3-09c4-459c-a6e4-25694cfbacbd        1.40
55    0537a9e3-09c4-459c-a6e4-25694cfbacbd        1.40
71    05577c2e-da7d-4753-bba6-66762385e159        1.00
67    05577c2e-da7d-4753-bba6-66762385e159        1.00
79    05577c2e-da7d-4753-bba6-66762385e159        5.40
75    05577c2e-da7d-4753-bba6-66762385e159        5.40
1475  5a104c86-327e-466f-b14a-6953cacddcbb        0.50
1479  5a104c86-327e-466f-b14a-6953cacddcbb        0.50
1487  5a104c86-327e-466f-b14a-6953cacddcbb        0.50
1483  5a104c86-327e-466f-b14a-6953cacddcbb        0.50
2287  8e853797-a7f3-4605-8848-f6b211f9b055        2.10
2283  8e853797-a7f3-4605-8848-f6b211f9b055        2.10
2279  8e853797-a7f3-4605-8848-f6b211f9b055        2.10
2275  8e853797-a7f3-4605-8848-f6b211f9b055        2.10
3351  c1120018-c626-4c1b-81a5-476ce38f346b        0.55
3347  c1120018-c626-4c1b-81a5-476ce38f346b        0.55
3359  c1120018-c626-4c1b-81a5-476ce38f346b        1.20
3355  c1120018-c626-4c1b-81a5-476ce38f346b        1.20
 

Комментарии:

1. Это именно то, что я искал! Спасибо!

Ответ №2:

использовать np.select([conditions],[solutions])

условия

 condition1=df2.groupby('id')['seg_length'].apply(lambda x:x.duplicated(keep=False))
condition2=df2.groupby('id')['seg_length'].apply(lambda x:~x.duplicated(keep=False))
 

Решение

 sol1=df2['seg_length']
sol2=(df2.loc[condition2,'seg_length'].sum(0))/2

df2['newseg_length']=np.select([condition1,condition2],[sol1,sol2])

                     

          id                                      seg_length  newseg_length
3351  c1120018-c626-4c1b-81a5-476ce38f346b         0.6           0.55
3347  c1120018-c626-4c1b-81a5-476ce38f346b         1.2           1.20
3359  c1120018-c626-4c1b-81a5-476ce38f346b         0.5           0.55
3355  c1120018-c626-4c1b-81a5-476ce38f346b         1.2           1.20
 

Комментарии:

1. Спасибо. Это решило часть 2 проблемы.