Tengo un marco de datos de la siguiente manera

d = {'Movie' : ['The Shawshank Redemption', 'The Godfather'],
        'FirstName1': ['Tim', 'Marlon'],
        'FirstName2': ['Morgan', 'Al'],
        'LastName1': ['Robbins', 'Brando'],
        'LastName2': ['Freeman', 'Pacino'],
        'ID1': ['TM', 'MB'],
        'ID2': ['MF', 'AP']
        }
df = pd.DataFrame(d)
df

enter image description here

Me gustaría reorganizarlo en un marco de datos de 4 columnas, convirtiendo Firstname1, LastName1, FirstName2, LastName2, ID1, ID2 en 3 filas de columnas como FirstName, LastName, ID y luego la columna movie se repite de la siguiente manera. ingrese la descripción de la imagen aquí

En sql lo hacemos de la siguiente manera

select Movie as Movie, FirstName1 as FirstName, LastName1 as LastName, ID1 as ID from table
union
select Movie as Movie, FirstName2 as FirstName, LastName2 as LastName, ID2 as ID from table

¿Podemos lograrlo usando pandas?

3
Prince Francis 10 may. 2019 a las 09:06

4 respuestas

La mejor respuesta

Si es posible, número en los nombres de columna más como 9 use Series.str.extract para obtener enteros con valores anteriores a MultiIndex a columnas, por lo que es posible DataFrame.stack:

df = df.set_index('Movie')
df1 = df.columns.to_series().str.extract('([a-zA-Z]+)(\d+)')
df.columns = pd.MultiIndex.from_arrays([df1[0], df1[1].astype(int)])

df = df.rename_axis((None, None), axis=1).stack().reset_index(level=1, drop=True).reset_index()
print (df)
                      Movie FirstName  ID LastName
0  The Shawshank Redemption       Tim  TM  Robbins
1  The Shawshank Redemption    Morgan  MF  Freeman
2             The Godfather    Marlon  MB   Brando
3             The Godfather        Al  AP   Pacino

Si no usa la indexación para obtener los últimos valores de los nombres de columnas con todos los anteriores y pasar a MultiIndex.from_arrays:

df = df.set_index('Movie')
df.columns = pd.MultiIndex.from_arrays([df.columns.str[:-1], df.columns.str[-1].astype(int)])
df = df.stack().reset_index(level=1, drop=True).reset_index()
print (df)
                      Movie FirstName  ID LastName
0  The Shawshank Redemption       Tim  TM  Robbins
1  The Shawshank Redemption    Morgan  MF  Freeman
2             The Godfather    Marlon  MB   Brando
3             The Godfather        Al  AP   Pacino
3
jezrael 10 may. 2019 a las 06:33

Creo que una manera fácil de hacer esto es usar la función de copia de Pandas. Puede copiar las columnas "Película", "Nombre", "Apellido", "ID" en una nueva tabla. Luego elimine las columnas que no necesita en su primera columna. También puede crear una nueva tabla para la otra.

new = d['Movie', 'FirstName', 'LastName', 'ID].copy
0
Moschte 10 may. 2019 a las 06:20

Intente a continuación:

d1 = df.filter(regex="1$|Movie").rename(columns=lambda x: x[:-1])
d2 = df.filter(regex="2$|Movie").rename(columns=lambda x: x[:-1])
pd.concat([d1, d2]).rename({'Movi':'Movie'})
0
hacker315 10 may. 2019 a las 06:47
df = df.set_index('Movie')
df.columns = pd.MultiIndex.from_tuples([(col[:-1], col[-1:]) for col in df.columns])

df.stack()

#                           FirstName  ID LastName
#Movie                                            
#The Shawshank Redemption 1       Tim  TM  Robbins
#                         2    Morgan  MF  Freeman
#The Godfather            1    Marlon  MB   Brando
#                         2        Al  AP   Pacino

¡Usa el poder de MultiIndex! Con from_tuples crea un DataFrame que tiene una columna para FirstNames, dividida en FirstName1 y FirstName2 (ver más abajo) y similar para ID y LastName. Con stack lo conviertes en filas para cada uno. Antes de hacer esto, haga Movie el Índice para excluirlo de lo que está haciendo. Puede usar reset_index() para recuperar todo como columnas, pero no estoy seguro si quieres eso.


Antes de stack:

#                         FirstName         LastName           ID    
#                                 1       2        1        2   1   2
#Movie                                                               
#The Shawshank Redemption       Tim  Morgan  Robbins  Freeman  TM  MF
#The Godfather               Marlon      Al   Brando   Pacino  MB  AP
2
Jondiedoop 10 may. 2019 a las 06:21