tablas seleccionar para leer funciones datos columnas python pandas numpy join

python - seleccionar - funciones de pandas para leer datos a tablas



La mejor manera de unirse/fusionarse por rango en pandas (5)

Considere que su marco de datos A es

A = pd.DataFrame([[0,2],[1,3],[2,4],[3,5],[4,6]],columns=[''A_id'', ''A_value''])

y el marco de datos B es

B = pd.DataFrame([[0,1,2,''a''],[1,4,9,''b''],[2,2,5,''c''],[3,6,7,''d''],[4,8,9,''e'']],columns=[''B_id'', ''B_low'', ''B_high'', ''B_name''])

usando esto a continuación obtendrá la salida deseada

A = A[(A[''A_value'']>=B[''B_low''])&(A[''A_value'']<=B[''B_high''])]

Con frecuencia uso pandas para fusionar (unir) usando una condición de rango.

Por ejemplo, si hay 2 marcos de datos:

A (A_id, A_value)

B (B_id, B_low, B_high, B_name)

que son grandes y aproximadamente del mismo tamaño (digamos que 2M registra cada uno).

Me gustaría hacer una unión interna entre A y B, por lo que A_value estaría entre B_low y B_high.

Usando la sintaxis SQL que sería:

SELECT * FROM A,B WHERE A_value between B_low and B_high

y eso sería realmente fácil, corto y eficiente.

Mientras tanto, en los pandas, la única forma (que no está usando los bucles que encontré) es creando una columna ficticia en ambas tablas, unir en ella (equivalente a la unión cruzada) y luego filtrar las filas innecesarias. Eso suena pesado y complejo:

A[''dummy''] = 1 B[''dummy''] = 1 Temp = pd.merge(A,B,on=''dummy'') Result = Temp[Temp.A_value.between(Temp.B_low,Temp.B_high)]

Otra solución que tuve es aplicar a cada uno de los valores de A una función de búsqueda en B usando la máscara B[(x>=B.B_low) & (x<=B.B_high)] , pero también suena ineficiente y podría requieren optimización de índice.

¿Existe una forma más elegante y / o eficiente de realizar esta acción?


No estoy seguro de que sea más eficiente, sin embargo, puede usar sql directamente (desde el módulo sqlite3, por ejemplo) con pandas (inspirados en esta pregunta ) como:

conn = sqlite3.connect(":memory:") df2 = pd.DataFrame(np.random.randn(10, 5), columns=["col1", "col2", "col3", "col4", "col5"]) df1 = pd.DataFrame(np.random.randn(10, 5), columns=["col1", "col2", "col3", "col4", "col5"]) df1.to_sql("df1", conn, index=False) df2.to_sql("df2", conn, index=False) qry = "SELECT * FROM df1, df2 WHERE df1.col1 > 0 and df1.col1<0.5" tt = pd.read_sql_query(qry,conn)

Puede adaptar la consulta según sea necesario en su aplicación


No sé qué tan eficiente es, pero alguien escribió un contenedor que le permite usar la sintaxis SQL con objetos pandas. Eso se llama pandasql . La documentación indica explícitamente que las uniones son compatibles. Esto podría ser al menos más fácil de leer ya que la sintaxis SQL es muy legible.


Tomemos un ejemplo simple:

df=pd.DataFrame([2,3,4,5,6],columns=[''A''])

devoluciones

A 0 2 1 3 2 4 3 5 4 6

ahora definamos un segundo marco de datos

df2=pd.DataFrame([1,6,2,3,5],columns=[''B_low'']) df2[''B_high'']=[2,8,4,6,6]

resultados en

B_low B_high 0 1 2 1 6 8 2 2 4 3 3 6 4 5 6

aquí vamos; y queremos que la salida sea el índice 3 y el valor A 5

df.where(df[''A'']>=df2[''B_low'']).where(df[''A'']<df2[''B_high'']).dropna()

resultados en

A 3 5.0


Preparar
Considere los marcos de datos A y B

A = pd.DataFrame(dict( A_id=range(10), A_value=range(5, 105, 10) )) B = pd.DataFrame(dict( B_id=range(5), B_low=[0, 30, 30, 46, 84], B_high=[10, 40, 50, 54, 84] )) A A_id A_value 0 0 5 1 1 15 2 2 25 3 3 35 4 4 45 5 5 55 6 6 65 7 7 75 8 8 85 9 9 95 B B_high B_id B_low 0 10 0 0 1 40 1 30 2 50 2 30 3 54 3 46 4 84 4 84

numpy
La forma más fácil es utilizar transmisiones con numpy .
Buscamos que cada instancia de A_value sea ​​mayor o igual que B_low mientras que al mismo tiempo A_value es menor o igual que B_high .

a = A.A_value.values bh = B.B_high.values bl = B.B_low.values i, j = np.where((a[:, None] >= bl) & (a[:, None] <= bh)) pd.DataFrame( np.column_stack([A.values[i], B.values[j]]), columns=A.columns.append(B.columns) ) A_id A_value B_high B_id B_low 0 0 5 10 0 0 1 3 35 40 1 30 2 3 35 50 2 30 3 4 45 50 2 30

Para abordar los comentarios y dar algo parecido a una unión izquierda, agregué la parte de A que no coincide.

pd.DataFrame( np.column_stack([A.values[i], B.values[j]]), columns=A.columns.append(B.columns) ).append( A[~np.in1d(np.arange(len(A)), np.unique(i))], ignore_index=True, sort=False ) A_id A_value B_id B_low B_high 0 0 5 0.0 0.0 10.0 1 3 35 1.0 30.0 40.0 2 3 35 2.0 30.0 50.0 3 4 45 2.0 30.0 50.0 4 1 15 NaN NaN NaN 5 2 25 NaN NaN NaN 6 5 55 NaN NaN NaN 7 6 65 NaN NaN NaN 8 7 75 NaN NaN NaN 9 8 85 NaN NaN NaN 10 9 95 NaN NaN NaN