Tengo un marco de datos como el siguiente y quiero mantener una de las mejores columnas de calificación aquí.

Marco de datos original:

skunumber   category    overallrating   rating  reviews
123          Cat1          1             1        20
124          cat1          2             2        23

Para eso estoy derritiendo luego el marco de datos y cambio el nombre de la calificación general a calificación. Finalmente, suelte los duplicados si los hay y nuevamente quiero convertir el formato original del marco de datos derretido.

El marco de datos fundido tiene este aspecto:

skunumber   category    attribute   attributeRawValue
123         Cat1      overallrating        1
124         cat1      overallrating        3
123         Cat1        rating             1
124         cat1        rating             2
123         Cat1        reviews            20
124         cat1        reviews            23

DataFrame se ve así después de cambiar el nombre de la calificación general a calificación y eliminar duplicados.

skunumber   category    attribute   attributeRawValue
123         Cat1        rating             1
124         cat1        rating             2
123         Cat1        reviews            20
124         cat1        reviews            23

Y finalmente quiero que el marco de datos vuelva a ser el original.

skunumber   category    rating  reviews
123          Cat1         1       20
124          cat1         2        23

Intenté realizar esto con la opción de pivote, esto funciona si tenemos una columna de índice pero aquí tengo 2 columnas.

Código de muestra:

messy = pd.DataFrame({'row' : ['A', 'B', 'C'], 
                  'a' : [1, 2, 3],
                  'b' : [4, 5, 6],
                  'c' : [7, 8, 9]})

tidy = pd.melt(messy, id_vars='row',     var_name='dimension',value_name='length')  

messy1 = tidy.pivot(index='row',columns='dimension',values='length')   

messy1.reset_index(inplace=True)
messy1.columns.name = '' 

En mi caso, intenté pasar el índice como ['skunumber', 'category'] no funcionó

Gracias

0
Somashekar Muniyappa 14 dic. 2016 a las 15:13

2 respuestas

La mejor respuesta

Creo que necesitas agregar otra columna al parámetro id_vars en melt:

df = df.rename(columns={'overallrating':'rating'})
tidy = pd.melt(df, 
               id_vars=['skunumber','category'],  
               var_name='dimension',
               value_name='length')  
tidy = tidy.drop_duplicates()
print (tidy)
   skunumber category dimension  length
0        123     Cat1    rating       1
1        124     cat1    rating       2
4        123     Cat1   reviews      20
5        124     cat1   reviews      23

messy1 = tidy.set_index(['skunumber','category','dimension'])
             .length
             .unstack()
             .reset_index()

messy1.columns.name = None
print (messy1)
   skunumber category  rating  reviews
0        123     Cat1       1       20
1        124     cat1       2       23

Otra solución más sencilla con stack , drop_duplicates ( de forma predeterminada, mantenga solo el valor first) y el último unstack:

df = df.rename(columns={'overallrating':'rating'})
tidy = df.set_index(['skunumber','category'])
         .stack()
         .drop_duplicates()
         .unstack()
         .reset_index()

print (tidy)
   skunumber category  rating  reviews
0        123     Cat1       1       20
1        124     cat1       2       23

Si trabaja con datos reales, puede obtener fácilmente:

ValueError: el índice contiene entradas duplicadas, no se puede reformar

Entonces la solución es abajo u otra respuesta:

df = pd.DataFrame({'category': ['Cat1', 'Cat1', 'cat1'],
                   'overallrating': [1, 5, 3], 
                   'skunumber': [123, 123, 124], 
                   'reviews': [20, 30, 23], 
                   'rating': [4, 2, 2]})

print (df)
  category  overallrating  rating  reviews  skunumber
0     Cat1              1       4       20        123
1     Cat1              5       2       30        123
2     cat1              3       2       23        124

Nedd groupby por columnas que crea nuevos index antes de reset_index (aquí skunumber y category) y agrega algunas funciones como mean, sum, max , min, first ...

df = df.rename(columns={'overallrating':'rating'})
tidy = df.groupby(['skunumber','category'])['rating'].max().unstack().reset_index()
print (tidy)
   skunumber category  rating  rating
0        123     Cat1       5       4
1        124     cat1       3       2

EDITAR por comentario:

Si los duplicados necesitan alguna función agregada como max, first, sum, mean con groupby:

print (df)
   skunumber category  overallrating  rating  reviews  color colorShade
0        123     Cat1              1       1       12  White        Red
1        123     Cat1              1       4       20   Pink      Green
2        124     cat1              2       2       23  Black       Blue

df = df.rename(columns={'overallrating':'rating', 'colorShade':'color'})
g = df.groupby(['skunumber','category'])

tidy1 = g['rating'].max().unstack()
print (tidy1)
                    rating  rating
skunumber category                
123       Cat1           1       4
124       cat1           2       2

tidy2 = g['color'].first().unstack()
print (tidy2)
                    color color
skunumber category             
123       Cat1      White   Red
124       cat1      Black  Blue

Y luego concat datos juntos:

df = pd.concat([tidy1, tidy2],axis=1).reset_index()
print (df)
   skunumber category  rating  rating  color color
0        123     Cat1       1       4  White   Red
1        124     cat1       2       2  Black  Blue

Otra solución con pd.lreshape:

tidy = pd.lreshape(df, {'rating':['rating','overallrating'], 'color':['color','colorShade']})
print (tidy)
  category  reviews  skunumber  color  rating
0     Cat1        1        123  White       1
1     Cat1       20        123   Pink       4
2     cat1       23        124  Black       2
3     Cat1        1        123    Red       1
4     Cat1       20        123  Green       1
5     cat1       23        124   Blue       2

tidy = tidy.drop_duplicates(['category','skunumber'])
print (tidy)
  category  reviews  skunumber  color  rating
0     Cat1        1        123  White       1
2     cat1       23        124  Black       2
2
jezrael 16 dic. 2016 a las 12:11

Necesita pivot_table para integrar varios objetos como su argumento index. Pero tenga en cuenta que si hay valores duplicados correspondientes a este conjunto de índices, entonces su agregación produciría los promedios que son por defecto (aggfunc=np.mean). Si desea sumar estos valores, debe hacerlo específicamente proporcionando aggfunc=np.sum.

piv_df = df.pivot_table(index=['skunumber', 'category'], columns=['attribute'], values=['attributeRawValue'])
piv_df.columns = piv_df.columns.droplevel(0)
piv_df.reset_index().rename_axis(None, 1)

enter image description here


Para obtener df:

data = StringIO(
'''
skunumber   category    overallrating   rating  reviews
123          Cat1          1             1        20
124          cat1          2             2        23
''')

df = pd.read_csv(data, delim_whitespace=True)
df = pd.melt(df, id_vars=['skunumber', 'category'], 
             var_name='attribute', value_name='attributeRawValue')
df.loc[df['attribute']=='overallrating', 'attribute'] = 'rating'
df.drop_duplicates()

enter image description here

1
Nickil Maveli 16 dic. 2016 a las 11:39