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:
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>
¿Cómo representar una grid de preguntas en un marco de datos?
De los datos en cuestión hay que sacar los elementos necesarios...
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:
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']
Aplicar la misma metodología para encontrar las respuestas sería:
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.
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.
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]]
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
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP