python - Encontrar filas comunes(intersección) en dos dataframes de Pandas
python-2.7 intersect (3)
En SQL, este problema podría ser resuelto por varios métodos:
select * from df1 where exists (select * from df2 where df2.user_id = df1.user_id)
union all
select * from df2 where exists (select * from df1 where df1.user_id = df2.user_id)
o join y luego unpivot (posible en el servidor SQL)
select
df1.user_id,
c.rating
from df1
inner join df2 on df2.user_i = df1.user_id
outer apply (
select df1.rating union all
select df2.rating
) as c
El segundo podría escribirse en pandas con algo como:
>>> df1 = pd.DataFrame({"user_id":[1,2,3], "rating":[10, 15, 20]})
>>> df2 = pd.DataFrame({"user_id":[3,4,5], "rating":[30, 35, 40]})
>>>
>>> df4 = df[[''user_id'', ''rating_1'']].rename(columns={''rating_1'':''rating''})
>>> df = pd.merge(df1, df2, on=''user_id'', suffixes=[''_1'', ''_2''])
>>> df3 = df[[''user_id'', ''rating_1'']].rename(columns={''rating_1'':''rating''})
>>> df4 = df[[''user_id'', ''rating_2'']].rename(columns={''rating_2'':''rating''})
>>> pd.concat([df3, df4], axis=0)
user_id rating
0 3 20
0 3 30
Supongamos que tengo dos dataframes de este formato (llámalos df1
y df2
):
+------------------------+------------------------+--------+
| user_id | business_id | rating |
+------------------------+------------------------+--------+
| rLtl8ZkDX5vH5nAx9C3q5Q | eIxSLxzIlfExI6vgAbn2JA | 4 |
| C6IOtaaYdLIT5fWd7ZYIuA | eIxSLxzIlfExI6vgAbn2JA | 5 |
| mlBC3pN9GXlUUfQi1qBBZA | KoIRdcIfh3XWxiCeV1BDmA | 3 |
+------------------------+------------------------+--------+
Estoy buscando obtener un marco de datos de todas las filas que tienen un user_id
común en df1
y df2
. (es decir, si un user_id
está en df1
y df2
, incluya las dos filas en el marco de datos de salida)
Puedo pensar en muchas formas de abordar esto, pero todos me parecen torpes. Por ejemplo, podríamos encontrar todos los user_id
s únicos en cada dataframe, crear un conjunto de cada uno, encontrar su intersección, filtrar los dos dataframes con el conjunto resultante y concatenar los dos dataframes filtrados.
Quizás ese sea el mejor enfoque, pero sé que Pandas es inteligente. ¿Hay una manera más simple de hacer esto? Miré la merge
pero no creo que eso sea lo que necesito.
Si lo entiendo correctamente, puede usar una combinación de Series.isin()
y DataFrame.append()
:
In [80]: df1
Out[80]:
rating user_id
0 2 0x21abL
1 1 0x21abL
2 1 0xdafL
3 0 0x21abL
4 4 0x1d14L
5 2 0x21abL
6 1 0x21abL
7 0 0xdafL
8 4 0x1d14L
9 1 0x21abL
In [81]: df2
Out[81]:
rating user_id
0 2 0x1d14L
1 1 0xdbdcad7
2 1 0x21abL
3 3 0x21abL
4 3 0x21abL
5 1 0x5734a81e2
6 2 0x1d14L
7 0 0xdafL
8 0 0x1d14L
9 4 0x5734a81e2
In [82]: ind = df2.user_id.isin(df1.user_id) & df1.user_id.isin(df2.user_id)
In [83]: ind
Out[83]:
0 True
1 False
2 True
3 True
4 True
5 False
6 True
7 True
8 True
9 False
Name: user_id, dtype: bool
In [84]: df1[ind].append(df2[ind])
Out[84]:
rating user_id
0 2 0x21abL
2 1 0xdafL
3 0 0x21abL
4 4 0x1d14L
6 1 0x21abL
7 0 0xdafL
8 4 0x1d14L
0 2 0x1d14L
2 1 0x21abL
3 3 0x21abL
4 3 0x21abL
6 2 0x1d14L
7 0 0xdafL
8 0 0x1d14L
Este es esencialmente el algoritmo que describió como "torpe", utilizando métodos de pandas
idiomáticos. Tenga en cuenta los índices de fila duplicados. Además, tenga en cuenta que esto no le dará el resultado esperado si df1
y df2
no tienen índices de filas superpuestas, es decir, si
In [93]: df1.index & df2.index
Out[93]: Int64Index([], dtype=''int64'')
De hecho, no dará el resultado esperado si sus índices de filas no son iguales.
Tengo entendido que esta pregunta se responde mejor en esta publicación .
Pero brevemente, la respuesta a la OP con este método es simplemente:
s1 = pd.merge(df1, df2, how=''inner'', on=[''user_id''])
Lo que da s1 con 5 columnas: user_id y las otras dos columnas de cada uno de df1 y df2.