python - groupby - Cuente el número de resultados de escala de Likert de preguntas de columna múltiple en pandas
python group by agg (3)
Tengo el siguiente marco de datos:
Question1 Question2 Question3 Question4
User1 Agree Agree Disagree Strongly Disagree
User2 Disagree Agree Agree Disagree
User3 Agree Agree Agree Agree
¿Hay alguna manera de convertir el marco de datos enumerado anteriormente a lo siguiente?
Agree Disagree Strongly Disagree
Question1 2 1 0
Question2 2 1 0
Question3 2 1 0
Question4 1 1 1
Esto es similar a mi pregunta anterior: crear un marco de datos con preguntas agrupadas de tres columnas
Traté de ver las preguntas anteriores con pila / pivote pero no pude entenderlo. El marco de datos real tiene más de 20 preguntas y una escala Likert de totalmente de acuerdo, de acuerdo, neutral, en desacuerdo, totalmente en desacuerdo.
Con pd.get_dummies
pd.get_dummies(df.stack()).groupby(level=1).sum()
Agree Disagree Strongly Disagree
Question1 2 1 0
Question2 3 0 0
Question3 2 1 0
Question4 1 1 1
Llevarlo a otro nivel
Podemos usar numpy.bincount
para acelerar las cosas. Pero debemos prestar atención a las dimensiones
v = df.values
f, u = pd.factorize(v.ravel())
n, m = u.size, v.shape[1]
r = np.tile(np.arange(m), n)
b0 = np.bincount(r * n + f)
pad = np.zeros(n * m - b0.size, dtype=int)
b = np.append(b0, pad)
pd.DataFrame(b.reshape(m, n), df.columns, u)
Agree Disagree Strongly Disagree
Question1 2 1 0
Question2 3 0 0
Question3 2 1 0
Question4 1 1 1
Otra opción numpy
v = df.values
n, m = v.shape
f, u = pd.factorize(v.ravel())
pd.DataFrame(
np.eye(u.size, dtype=int)[f].reshape(n, m, -1).sum(0),
df.columns, u
)
Agree Disagree Strongly Disagree
Question1 2 1 0
Question2 3 0 0
Question3 2 1 0
Question4 1 1 1
Diferencia de velocidad
%%timeit
v = df.values
f, u = pd.factorize(v.ravel())
n, m = u.size, v.shape[1]
r = np.tile(np.arange(m), n)
b0 = np.bincount(r * n + f)
pad = np.zeros(n * m - b0.size, dtype=int)
b = np.append(b0, pad)
pd.DataFrame(b.reshape(m, n), df.columns, u)
1000 loops, best of 3: 194 µs per loop
%%timeit
v = df.values
n, m = v.shape
f, u = pd.factorize(v.ravel())
pd.DataFrame(
np.eye(u.size, dtype=int)[f].reshape(n, m, -1).sum(0),
df.columns, u
)
1000 loops, best of 3: 195 µs per loop
%timeit pd.get_dummies(df.stack()).groupby(level=1).sum()
1000 loops, best of 3: 1.2 ms per loop
Puede iterar sobre columnas con pd.Series.value_counts
. Si hace esto con aplicar, los índices se alinearán automáticamente:
df.apply(pd.Series.value_counts)
Out:
Question1 Question2 Question3 Question4
Agree 2.0 3.0 2.0 1
Disagree 1.0 NaN 1.0 1
Strongly Disagree NaN NaN NaN 1
Un poco de postprocesamiento:
df.apply(pd.Series.value_counts).fillna(0).astype(''int'')
Out:
Question1 Question2 Question3 Question4
Agree 2 3 2 1
Disagree 1 0 1 1
Strongly Disagree 0 0 0 1
df.apply(lambda x:x.value_counts()).fillna(0).astype(int)
# Question1 Question2 Question3 Question4
#Agree 2 3 2 1
#Disagree 1 0 1 1
#Strongly Disagree 0 0 0 1