TransWikia.com

¿Cómo representar una grid de preguntas en un marco de datos?

Stack Overflow en español Asked on August 26, 2021

Tengo json que representa una cuadrícula de preguntas y respuestas de los formularios de Google y me gustaria extraerlo en una dataframe:

{'question': 'To what extent are the following factors considerations in your choice of flight? ', 'answers': [None, 7, [[514996986, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['The airline/company you fly with'], None, None, None, None, None, None, None, [1]], [396483948, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['The departure airport'], None, None, None, None, None, None, None, [1]], [971070641, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['Duration of flight/route'], None, None, None, None, None, None, None, [1]], [1685960105, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['Price'], None, None, None, None, None, None, None, [1]], [231217486, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['Baggage policy'], None, None, None, None, None, None, None, [1]], [940990935, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['Environmental impacts'], None, None, None, None, None, None, None, [1]]]]}

Representa:

introducir la descripción de la imagen aquí

Me gustaria ponerlo en una dataframe con

QID    Questions    Answer_1    Answer_2    Answer_3    Answer_4    Answer_5                                                                        
0      To what extent are the following factors considerations in your choice of flight?    'Very important consideration'    'Important consideration'    'Neutral'    'Not an important consideration'    'Do not consider'
0_S01  'The airline/company you fly with'
0_S02  'The departure airport'
0_S03  'Duration of flight/route'
0_S04  'Baggage policy'
...

Hasta hoy intenté crear nombres de columna
:

>>> li = ['Answer{i}' for i in range(0,len(l))]
>>> columns = ['QID', 'Questions', itertools.chain.from_iterable(li)]
>>> pd.DataFrame(columns)
                                                0
0                                             QID
1                                       Questions
2  <itertools.chain object at 0x000001E2F41DC188>

One Answer

¿Cómo representar una grid de preguntas en un marco de datos?

De los datos en cuestión hay que sacar los elementos necesarios...

Consiguiendo preguntas:

Analizando el diccionario que contiene toda la información

data = {'question': 'To what extent are the following factors considerations in your choice of flight? ', 'answers': [None, 7, [[514996986, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['The airline/company you fly with'], None, None, None, None, None, None, None, [1]], [396483948, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['The departure airport'], None, None, None, None, None, None, None, [1]], [971070641, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['Duration of flight/route'], None, None, None, None, None, None, None, [1]], [1685960105, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['Price'], None, None, None, None, None, None, None, [1]], [231217486, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['Baggage policy'], None, None, None, None, None, None, None, [1]], [940990935, [['Very important consideration'], ['Important consideration'], ['Neutral'], ['Not an important consideration'], ['Do not consider']], 0, ['Environmental impacts'], None, None, None, None, None, None, None, [1]]]]}

Uno se da cuenta de un par de cosas:

  • Las preguntas siguen una frecuencia de aparición en todo el diccionario

Vamos a empezar descartando el valor de la llave ["question"], debido a que ahí no están las preguntas. En la otra llave ["Answers"] podemos descartar los primeros dos valores de la lista:

print(data["answers"][2][0])

Con esto visualizamos que tambén podemos descartar el primer y segundo valor de esta lista, ya que el primer valor es un número y el segundo una lista con las pregunta. Por otro lado (literalmente), podemos ver que se pueden descartar todos los None y otros valores nulos. Con esto obtenemos la primera pregunta:

print(data["answers"][2][0][3])

muestra:

['The airline/company you fly with']

Si seguimos analizando a data nos daremos cuenta que todas las preguntas está en la cuarta ubicación de una lista contenida en la primera lista de data (el tercer elemento). Entonces podemos obtener todas las preguntas con una expresión generadora:

[data["answers"][2][x][3] for x in range(len(data["answers"][2]))] 

Pero, nos surge un problema, cada pregunta está contenida en una lista individual. Lo más optimo es usar reduce() de functools:

from functools import reduce

questions = reduce(lambda a,b: a + b,[data["answers"][2][x][3] for x in range(len(data["answers"][2]))])

print(questions) muestra:

['The airline/company you fly with', 'The departure airport', 'Duration of flight/route', 'Price', 'Baggage policy', 'Environmental impacts']

Consiguiendo respuestas:

Aplicar la misma metodología para encontrar las respuestas sería:

  1. Más tardado
  2. Innecesario
  3. Relativamente díficil

Al final de cuentas, todos las preguntas van a tener las mismas respuestas. Por lo tanto, no es necesario encontrarlas todas, si no encontrarlas una vez y repetirlas.

Es mucho más fácil manejar todo en una lista, para después montar bien el DataFrame.

Buscando las primeras preguntas:

Analizando a data nuevamente, nos vamos a dar cuenta que la secuencia de indices [2][0][1] ubica a una lista con todas las respuestas. Lastimosamente, también está contenidas individualmente en listas. Se puede usar reduce() para solucionar esto, pero también hay que multiplicarlas para que hayan respuestas para todas las preguntas. Podemos hacer las dos cosas a la vez:

ind_answers = data["answers"][2][0][1]
answers = []
for i in range(len(ind_answers)):
    answers.append(reduce(lambda a,b: a + b,[ind_answers[i] for x in range(len(questions))]))

mostraría:

[['Very important consideration', 'Very important consideration', 'Very important consideration', 'Very important consideration', 'Very important consideration', 'Very important consideration'], ['Important consideration', 'Important consideration', 'Important consideration', 'Important consideration', 'Important consideration', 'Important consideration'], ['Neutral', 'Neutral', 'Neutral', 'Neutral', 'Neutral', 'Neutral'], ['Not an important consideration', 'Not an important consideration', 'Not an important consideration', 'Not an important consideration', 'Not an important consideration', 'Not an important consideration'], ['Do not consider', 'Do not consider', 'Do not consider', 'Do not consider', 'Do not consider', 'Do not consider']]

Antes de seguir hay que parar y analizar que pasó aquí.

¿Qué acaba de pasar?

La variable ind_answers es la encargada de almacenar la primera ocurrrencía de las preguntas en data. En esta expresión: answers.append(reduce(lambda a,b: a + b,[ind_answers[i] for x in range(len(questions))])) se está añadiendo la lista reducida que da como resultado la multiplicación de los valores de ind_answers. Por lo tanto se obtienen, cinco listas con seis respuestas.

Cargando el DataFrame:

La manera más fácil en mi opinión es cargar el DataFrame desde un diccionario.

¿Pero, por qué?

Al cargar el DataFrame desde un diccionario puedes especificar directamente el nombre de las columnas y el contenido de las columnas con una lista. Para hacer esto hay que montar un diccionario con este tipo de estructura:

{"Nombre de la columna":[Valores,de,la,columna]}

Este diccionario se estaría montando de la siguiente manera:

dict_ = {"Questions": questions,"Answer_1":answers[0],"Answer_2":answers[1],"Answer_3":answers[2],"Answer_4":answers[3],"Answer_5":answers[4]}
df = pd.DataFrame(dict_)

Si hacemos print(df) para ver el resultado, veríamos

                          Questions                      Answer_1  ...                        Answer_4         Answer_5
0  The airline/company you fly with  Very important consideration  ...  Not an important consideration  Do not consider
1             The departure airport  Very important consideration  ...  Not an important consideration  Do not consider
2          Duration of flight/route  Very important consideration  ...  Not an important consideration  Do not consider
3                             Price  Very important consideration  ...  Not an important consideration  Do not consider
4                    Baggage policy  Very important consideration  ...  Not an important consideration  Do not consider
5             Environmental impacts  Very important consideration  ...  Not an important consideration  Do not consider

[6 rows x 6 columns]

Me gustaria ponerlo en una dataframe con

QID    Questions    Answer_1    Answer_2    Answer_3    Answer_4    Answer_5                                                                        
0      To what extent are the following factors considerations in your choice of flight?    'Very important consideration'    'Important consideration'    'Neutral'    'Not an important consideration'    'Do not consider'
0_S01  'The airline/company you fly with'
0_S02  'The departure airport'
0_S03  'Duration of flight/route'
0_S04  'Baggage policy'
...

Usemos los mismo métodos de obtención para las preguntas y respuestas, solo que esta vez vamos a montar el DataFrame de diferente manera.

Obteniendo la información de data:

Las preguntas se obtendrían igual, si notas la única diferencia es que esta vez se debe de incluir la pregunta que está en data["question"]:

questions = reduce(lambda a,b: a + b,[data["answers"][2][x][3] for x in range(len(data["answers"][2]))])
questions.insert(0,data["question"])

con print(questions) mostraría:

['To what extent are the following factors considerations in your choice of flight? ', 'The airline/company you fly with', 'The departure airport', 'Duration of flight/route', 'Price', 'Baggage policy', 'Environmental impacts']

Ahora hay que variar la manera de obtener las respuestas, por suerte para bien. Ahora es mucho más fácil:

¿Como se consiguen los espacios en blanco?

A la hora de montar el diccionario se deben de usar listas con la misma longitud. La solución que le veo a esto es usar un relleno, sea None o bien un espacio en blanco "".

fill = [None for x in range(len(questions) - 1)]

Para hacer todo un marcco de preguntas hay que conseguir las pregunta en su primera ocurrencia, luego multplicar entre sí y sumar con fill (el relleno):

ind_answers = data["answers"][2][0][1]
answers = []
for i in range(len(ind_answers)):
    answers.append(ind_answers[i] + fill)

Dentro del cilo for se pueden hacer ambos procedimientos. Nuestras preguntas quedarían así:

[['Very important consideration', None, None, None, None, None, None], ['Important consideration', None, None, None, None, None, None], ['Neutral', None, None, None, None, None, None], ['Not an important consideration', None, None, None, None, None, None], ['Do not consider', None, None, None, None, None, None]]

Montando el diccionario y DataFrame:

Bien se puede montar el diccionario de la misma forma, solo que esta vez a la hora de montar el DataFrame habría que cambiar la manera en que se indexa verticalmente este.

indexing = ["QID"] + ["0_S0{}".format(i) for i in range(1,len(questions))]
dict_ = {"Questions":questions,"Answer_1":answers[0],"Answer_2":answers[1],"Answer_3":answers[2],"Answer_4":answers[3],"Answer_5":answers[4]}
df = pd.DataFrame(dict_,index = indexing)

Redactando el final de esta respuesta, me dí cuenta que se ve mejor con los espacios en blanco en vez de los None. Entonces hice este cambio:

fill = ["" for x in range(len(questions) - 1)]

Por lo tanto, con print(df) se vería esto:

                                               Questions  ...         Answer_5
QID    To what extent are the following factors consi...  ...  Do not consider
0_S01                   The airline/company you fly with  ...
0_S02                              The departure airport  ...
0_S03                           Duration of flight/route  ...
0_S04                                              Price  ...
0_S05                                     Baggage policy  ...
0_S06                              Environmental impacts  ...

[7 rows x 6 columns]

Muy probablemente se vea diferente si estás usando un cuaderno, u otra herramienta de visualización.

Espero te haya servido de algo, saludos.

Correct answer by user166844 on August 26, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP