2 votos

Reemplazar varias coordenadas por su valor medio agrupado por multiíndice Pandas

Tengo una tabla con algunos datos que son obtenidos por un GPS, en mi tabla tengo esta estructura:

        Date    Time    Latitude    Longitude   Accuracy    Weather Visibility  ViewPoint   Species Bearing Distance    Count
29/12/2018  10:20:45    39.85528    -5.36466    1.500000001 Soleado Buena   Otero 4 Anser anser 210 600 70
29/12/2018  10:23:32    39.85528    -5.36466    1.500000001 Soleado Buena   Otero 4 Anser anser 260 900 20
29/12/2018  10:24:17    39.85528    -5.36466    1.500000001 Soleado Buena   Otero 4 Larus fuscus    230 500 2
29/12/2018  10:05:16    39.85528    -5.36466    1.299999952 Soleado Buena   Otero 4 Fulica atra 100 450 60
29/12/2018  10:09:47    39.85528    -5.36466    1.299999952 Soleado Buena   Otero 4 Anser anser 160 560 110
29/12/2018  10:12:41    39.85528    -5.36466    1.299999952 Soleado Buena   Otero 4 Anas penelope   160 560 200
29/12/2018  10:17:33    39.85528    -5.36466    1.299999952 Soleado Buena   Otero 4 Anser anser 194 560 45
29/12/2018  10:20:01    39.85528    -5.36466    1.299999952 Soleado Buena   Otero 4 Anser anser 200 560 60
29/12/2018  08:50:07    39.86689    -5.35504    2.000000001 Soleado Buena   Otero 5 Anser anser 0   0   
29/12/2018  08:55:49    39.866885   -5.355045   1.500000001 Soleado Buena   Otero 5 Anas penelope   200 550 60

Necesito obtener las coordenadas medias (para mejorar el error del GPS) por el punto de vista y la fecha. Así, para la Fecha 1, voy a tener una coordenada media para el ViewPoint1 (Otero1), y otras coordenadas medias para cada ViewPoint. Más adelante, en la siguiente Fecha, voy a tener la misma estructura, pero el ViewPoint puede estar ligeramente desplazado de una fecha a otra, por eso necesito agrupar también por Fecha y no sólo por el ViewPoint.

Puedo aplicar el groupby y obtengo casi lo que necesito:

df.groupby(['Date', 'ViewPoint'], as_index=True)['Latitude', 'Longitude'].mean()

Lo que arroja esta salida:

                       Latitude Longitude
Date        ViewPoint
2016-12-29  Otero 0 39.859567   -5.399055
            Otero 1 39.871807   -5.385762
            Otero 3 39.853757   -5.381488
            Otero 4 39.855280   -5.364660
            Otero 5 39.866887   -5.354937
            Otero 9 39.830826   -5.356414
            OteroX  39.854657   -5.391452
2017-01-10  Otero 0 39.858376   -5.395767
            Otero 1 39.871402   -5.385639
            Otero 2 39.874892   -5.379403
            Otero 4 39.855324   -5.364828
            Otero 5 39.866883   -5.355035
            Otero 9 39.830876   -5.356457

Entonces, lo que me falta es cómo sustituir los valores medios de cada fila de la tabla original, por sus valores medios en la misma combinación "Fecha" y "Punto de vista"

1voto

Anton8000 Puntos 165

No tengo datos para probar, pero esto debería funcionar:

df = pd.merge(left=df, right=aa, how='left', left_on=['Date','Viewpoint'], right_on=['Date','Viewpoint'])

(Después de crear aa como lo hace en su respuesta:

dfmean = mean_coords.swaplevel()
aa = dfmean.reset_index()

)

A continuación, elimine las antiguas columnas de lat long y cambie el nombre de las nuevas:

df.drop(['Latitude', 'Longitude'], axis=1, inplace=True)
df.rename(columns = {'Latitude_y':'Latitude','Longitude_y':'Longitude'}, inplace=True)

(O bien, elimínelos antes de la fusión y no tendrá que cambiar el nombre de los nuevos)

0voto

Matt Puntos 153

Quiero publicar mi solución por si algún día hay alguien con mi mismo problema.

Estoy seguro de que debe haber una forma directa de resolver con una orden de pandas, pero a falta de esa solución conseguí la mía:

Después de la agrupación para obtener la coordenada media de ViewPoint y la fecha que hice para unsawp el índice:

dfmean = mean_coords.swaplevel()
aa = dfmean.reset_index()

Y me dan esta estructura:

ViewPoint   Date        Latitude    Longitude
0   Otero 0 2016-12-29  39.859567   -5.399055
1   Otero 1 2016-12-29  39.871807   -5.385762
2   Otero 3 2016-12-29  39.853757   -5.381488
3   Otero 4 2016-12-29  39.855280   -5.364660
4   Otero 5 2016-12-29  39.866887   -5.354937
5   Otero 9 2016-12-29  39.830826   -5.356414

Luego ejecuto el DataFrame con iterrow y construyo un dict (¡me encantan los dicts!) con la media de Lat y Lon para ViewPoint y Date:

coords = {}

for index, row in dfmean.iterrows():

    coords[index] =  {'Lat': row[0], 'Lon': row[1]}

Ahora, puedo ejecutar la tabla principal con iterrow de nuevo y construir un índice dentro del bucle basado en el ViewPoint y la Fecha, estos índices son las claves si el dict que construimos antes, por lo que sólo tenemos que reasignar el Lat y Lon con los valores Lat y Lon (la media que queremos) que sotre en nuestro dict:

for index, row in df.iterrows():
    ix = (index[1], index[0])
    df.at[index,'Latitude'] = coords[ix]['Lat']
    df.at[index,'Longitude'] = coords[ix]['Lon']

Funciona. De todas formas, agradecería que alguien me mostrara una forma más elegante (y pitónica) de hacerlo.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X