Encontrar filas comunes (intersección) en dos marcos de datos Pandas
Supongamos que tengo dos dataframes de este formato (llámelos df1
y df2
):
+------------------------+------------------------+--------+
| user_id | business_id | rating |
+------------------------+------------------------+--------+
| rLtl8ZkDX5vH5nAx9C3q5Q | eIxSLxzIlfExI6vgAbn2JA | 4 |
| C6IOtaaYdLIT5fWd7ZYIuA | eIxSLxzIlfExI6vgAbn2JA | 5 |
| mlBC3pN9GXlUUfQi1qBBZA | KoIRdcIfh3XWxiCeV1BDmA | 3 |
+------------------------+------------------------+--------+
Estoy buscando un dataframe de todas las filas que tienen un user_id
común en df1
y df2
. (IE. si user_id
está en df1
y df2
, incluya las dos filas en el dataframe de salida)
Se me ocurren muchas maneras de abordar esto, pero todas me parecen torpes. Por ejemplo, podríamos encontrar todos los user_id
ú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.
Tal vez ese sea el mejor enfoque, pero sé que Pandas es inteligente. ¿Hay una forma más sencilla de hacer esto? He mirado merge
pero no creo que eso sea lo que necesito.
3 answers
Mi entendimiento es que esta pregunta es mejor respondida en este post.
Pero brevemente, la respuesta al OP con este método es simplemente:
s1 = pd.merge(df1, df2, how='inner', on=['user_id'])
Que da s1 con 5 columnas: user_id y las otras dos columnas de cada uno de df1 y df2.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:53
Si te entiendo correctamente, puedes 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 describiste como "torpe", usando métodos idiomáticos pandas
. Observe los índices de fila duplicados. Además, tenga en cuenta que esto no le dará la salida esperada si df1
y df2
no tienen índices de fila superpuestos, es decir, si
In [93]: df1.index & df2.index
Out[93]: Int64Index([], dtype='int64')
De hecho, no dará la salida esperada si sus índices de fila no son iguales.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-27 15:01:29
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 SQL server)
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-27 14:57:15