Use combine_first, combine, update para procesar eficientemente las columnas en el DataFrame

Cuña

Cuando usamos pandas para procesar datos, a menudo encontramos reemplazar una columna de datos por otra. Por ejemplo, las columnas A y B no procesan los datos que no están vacíos en la columna A, y reemplazan los datos que están vacíos en la columna A con los datos correspondientes a la columna B. Se estima que muchas personas encuentran este tipo de demanda, por supuesto, hay otras más complejas.

Hay muchas maneras de resolver este tipo de demanda, como aplicar con baja eficiencia, o usar loc vectorizado, etc. Así que esta vez echamos un vistazo a algunos métodos muy simples e igualmente eficientes.

combinar_primero

Este método se usa específicamente para tratar valores nulos, echemos un vistazo al uso

import pandas as pd

df = pd.DataFrame(
    {"A": ["001", None, "003", None, "005"],
     "B": ["1", "2", "3", "4", "5"]}
)
print(df)
"""
      A  B
0   001  1
1  None  2
2   003  3
3  None  4
4   005  5
"""

# 我们现在需求如下,如果A列中的数据不为空,那么不做处理。
# 为空,则用B列中对应的数据进行替换
df["A"] = df["A"].combine_first(df["B"])
print(df)
"""
     A  B
0  001  1
1    2  2
2  003  3
3    4  4
4  005  5
"""

El método de uso es muy simple. El primero son dos objetos de la serie. Supongamos que se llama s1 y s2, luego s1.combine_first (s2) significa reemplazar los datos vacíos en s1 con s2. Todos están vacíos, entonces el resultado solo puede estar vacío. Por supuesto, este método no funciona en su lugar, pero devolverá un nuevo objeto Serie

Además, la premisa ideal de este método es que los índices de los dos objetos de la Serie son consistentes, porque el reemplazo se basa en el índice para especificar la ubicación

Por ejemplo, si los datos con el índice 1 en s1 están vacíos, los datos con el índice 1 en s2 se utilizarán para su reemplazo. Pero si no hay datos del índice 1 en s2, entonces no serán reemplazados. Y, si se supone que hay datos con índice 100 en s2, pero no en s1, el resultado será uno más con índice 100.

Demostremos

import pandas as pd

s1 = pd.Series(["001", None, None, "004"], index=['a', 'b', 'c', 'd'])
s2 = pd.Series(["2", "3", "4"], index=['b', 'd', "e"])

print(s1)
"""
a     001
b    None
c    None
d     004
dtype: object
"""
print(s2)
"""
b    2
d    3
e    4
dtype: object
"""

print(s1.combine_first(s2))
"""
a    001
b      2
c    NaN
d    004
e      4
dtype: object
"""

Para explicar, lo primero que se debe reemplazar son los datos con valor vacío en s1. Si no está vacío, no se realiza ningún procesamiento. Hay dos datos vacíos en s1, que son los índices "b" y "c", luego los datos con los índices "b" y "c" en s2 serán reemplazados. Pero hay datos con el índice "b" en s2, pero no hay datos con el índice "c", por lo que solo se puede reemplazar un valor.

Además, vemos que hay más datos con el índice e al final. Sí, decimos que si los datos en s2 no están en s1, se agregarán directamente.

import pandas as pd

s1 = pd.Series(['1', '2', '3', '4'], index=['a', 'b', 'c', 'd'])
s2 = pd.Series(['11', '22', '33'], index=['d', 'e', 'f'])

print(s1.combine_first(s2))
"""
a     1
b     2
c     3
d     4
e    22
f    33
dtype: object
"""

Vemos que en s2, hay datos con los índices 'e' y 'f', pero no en s1, por lo que lo agregamos directamente. Por supuesto, si los datos en s1 no están en s2, entonces s1 también se guardará directamente. Si hay ambos, entonces vea si los datos de s1 están vacíos, si está vacío, luego reemplácelos con los datos correspondientes al índice de s2, si no está vacío, mantenga s1, es decir, no lo reemplace.

Por supuesto, en la mayoría de los casos, estamos tratando con dos columnas del mismo DataFrame. Para dos columnas en el mismo DataFrame, sus índices son obviamente los mismos, por lo que es simplemente de arriba a abajo, no habrá demasiadas campanas y silbatos. .

combinar

Combinar es similar a combine_first, excepto que necesita especificar una función.

import pandas as pd

df = pd.DataFrame(
    {"A": ["001", None, "003", None, "005"],
     "B": ["1", "2", "3", "4", "5"]}
)
print(df)
"""
      A  B
0   001  1
1  None  2
2   003  3
3  None  4
4   005  5
"""

df["A"] = df["A"].combine(df["B"], lambda a, b: a if pd.notna(a) else b)
print(df)
"""
     A  B
0  001  1
1    2  2
2  003  3
3    4  4
4  005  5
"""

Especificamos una función anónima, y ​​los parámetros ayb representan cada dato correspondiente en df ["A"] y df ["B"]. Si a no está vacío, devuelva a, de lo contrario devuelva b.

Entonces vemos que usamos combine para lograr el efecto de combine_first. combine_first reemplaza específicamente los valores nulos, pero combine nos permite especificar la lógica nosotros mismos. Podemos realizar la función de combine_first, pero también otras funciones

import pandas as pd

s1 = pd.Series([1, 22, 3, 44])
s2 = pd.Series([11, 2, 33, 4])

# 哪个元素大就保留哪一个
print(s1.combine(s2, lambda a, b: a if a > b else b))
"""
0    11
1    22
2    33
3    44
dtype: int64
"""

# 两个元素进行相乘
print(s1.combine(s2, lambda a, b: a * b))
"""
0     11
1     44
2     99
3    176
dtype: int64
"""

La función de combinar todavía es muy poderosa, por supuesto, también se opera contra el índice. De hecho, combine y combine_first primero procesará el índice internamente. Si los índices de los dos objetos de la Serie no son iguales, primero serán consistentes.

import pandas as pd

s1 = pd.Series([1, 22, 3, 44], index=['a', 'b', 'c', 'd'])
s2 = pd.Series([11, 2, 33, 4], index=['c', 'd', 'e', 'f'])

# 先对两个索引取并集
index = s1.index.union(s2.index)
print(index)  # Index(['a', 'b', 'c', 'd', 'e', 'f'], dtype='object')

# 然后通过reindex,获取指定索引的元素,当然索引不存在就用NaN代替
s1 = s1.reindex(index)
s2 = s2.reindex(index)
print(s1)
"""
a     1.0
b    22.0
c     3.0
d    44.0
e     NaN
f     NaN
dtype: float64
"""
print(s2)
"""
a     NaN
b     NaN
c    11.0
d     2.0
e    33.0
f     4.0
dtype: float64
"""
# 在将s1和s2的索引变得一致之后,依次进行操作。

Mira hacia atrás en combine_first

import pandas as pd

s1 = pd.Series([1, 22, 3, 44], index=['a', 'b', 'c', 'd'])
s2 = pd.Series([11, 2, 33, 4], index=['a', 'b', 'c', 'e'])
print(s1.combine_first(s2))
"""
a     1.0
b    22.0
c     3.0
d    44.0
e     4.0
dtype: float64
"""
# 一开始的话可能有人会好奇为什么类型变了,但是现在显然不会有疑问了
# 因为s1和s2的索引不一致,index='e'在s1中不存在,index='d'在s2中不存在
# 而reindex如果指定不存在索引,则用NaN代替
# 而如果出现了NaN,那么类型就由整型变成了浮点型。
# 但两个Series对象的index如果一样,那么reindex的结果也还是和原来一样,由于没有NaN,那么类型就不会变化

# 所以我们可以自己实现一个combine_first,当然pandas内部也是这么做的
s1 = s1.reindex(['a', 'b', 'c', 'd', 'e'])
s2 = s2.reindex(['a', 'b', 'c', 'd', 'e'])
print(s1)
"""
a     1.0
b    22.0
c     3.0
d    44.0
e     NaN
dtype: float64
"""
print(s2)
"""
a    11.0
b     2.0
c    33.0
d     NaN
e     4.0
dtype: float64
"""

# s1不为空,否则用s2替换
print(s1.where(pd.notna(s1), s2))
"""
a     1.0
b    22.0
c     3.0
d    44.0
e     4.0
dtype: float64
"""

Mira de nuevo a combinar

import pandas as pd

s1 = pd.Series([1, 22, 3, 44], index=['a', 'b', 'c', 'd'])
s2 = pd.Series([11, 2, 33, 4], index=['c', 'd', 'e', 'f'])

print(s1.combine(s2, lambda a, b: a if a > b else b))
"""
a     NaN
b     NaN
c    11.0
d    44.0
e    33.0
f     4.0
dtype: float64
"""
# 为什么出现这个结果,相信你很容易就分析出来
# reindex之后:
# s1的数据变成[1.0, 22.0, 33.0, 44.0, NaN, NaN]
# s2的数据变成[NaN, NaN, 11.0, 2.0, 33.0, 4.0]
# 然后依次比较,1.0 > NaN为False,那么保留b,而b为NaN, 所以结果的第一个元素为NaN,同理第二个也是如此。
# 同理最后两个元素,和NaN比较也是False,还是保留b,那么最后两个元素则是33.0和4.0
# 至于index为c、d的元素就没有必要分析了,显然是保留大的那个

Aún así, esa oración, para combine y combine_first, están comparando elementos del mismo índice.Si los índices de los dos objetos de la Serie son diferentes, entonces la unión se tomará primero, luego se reindexará y luego se comparará. Dar otra castaña:

import pandas as pd

s1 = pd.Series([1, 2, 3, 4])
s2 = pd.Series([1, 2, 3, 4])

# 两个元素是否相等,相等返回True,否则返回False
print(s1.combine(s2, lambda a, b: True if a == b else False))
"""
0    True
1    True
2    True
3    True
dtype: bool
"""

s2.index = [0, 1, 3, 2]
print(s1.combine(s2, lambda a, b: True if a == b else False))
"""
0     True
1     True
2    False
3    False
dtype: bool
"""

# 当我们将s2的索引变成了[0, 1, 3, 2]结果就不对了
print(s1.index.union(s2.index))  # Int64Index([0, 1, 2, 3], dtype='int64')
# 此时reindex的结果,s1还是1、2、3、4,但是s2则变成了1、2、4、3

Entonces, al usar los dos métodos combine y combine_first, debemos recordar el índice, de lo contrario, puede causar una trampa. De hecho, hay muchas otras operaciones, incluidos los pandas, todas se basan en el índice, no simplemente de izquierda a derecha o de arriba a abajo

Pero aún así esa oración, a menudo operamos en las dos columnas en el DataFrame, y sus índices son los mismos, por lo que no es necesario pensar demasiado.

Por supuesto, además del objeto Serie, estos dos métodos también pueden apuntar a objetos DataFrame, como: df1.combine (df2, func), para reemplazar la misma columna, pero no es muy común, si está interesado, puede estudiarlo usted mismo. Actuamos principalmente en objetos de la serie

actualizar

La actualización es relativamente brutal, echemos un vistazo.

import pandas as pd

s1 = pd.Series([1, 2, 3, 4])
s2 = pd.Series([11, 22, 33, 44])

s1.update(s2)
print(s1)
"""
0    11
1    22
2    33
3    44
dtype: int64
"""

En primer lugar, vemos que este método se opera localmente. La función es reemplazar el elemento de s1 con el elemento de s2, y mientras el elemento en s2 no esté vacío, entonces reemplácelo.

import pandas as pd

s1 = pd.Series([1, 2, 3, 4])
s2 = pd.Series([11, 22, None, 44])

s1.update(s2)
print(s1)
"""
0    11
1    22
2     3
3    44
dtype: int64
"""

Entonces, esta función se llama actualización, que significa actualización. Reemplace el elemento en s1 con el elemento en s2, pero si el elemento en s2 está vacío, puede pensar que la 'nueva versión' no ha salido, entonces la versión anterior todavía se usa, por lo que el 3 en s1 no ha sido reemplazado.

Así que update y combine_first son similares, pero sus diferencias son:

  • combine_first:如果s1中的值为空,用s2的值替换,否则保留s1的值
  • update:如果s2中的值不为空,那么替换s1,否则保留s1的值

Además, durante combine_first, enfatizamos repetidamente el problema de la indexación: si los índices de s1 y s2 son diferentes, el número de elementos del resultado resultante será mayor. Pero la actualización es diferente, ya que se opera localmente, es decir, modifica directamente s1 localmente. Por lo tanto, el número de elementos en s1 no cambiará.

import pandas as pd

s1 = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
s2 = pd.Series([11, 22, 33, 44], index=['c', 'd', 'e', 'f'])

s1.update(s2)
print(s1)
"""
a     1
b     2
c    11
d    22
dtype: int64
"""

No hay elementos con el índice 'a' y 'b' en s2, entonces se puede considerar que la 'nueva versión' no aparece, por lo que el valor original no se actualiza y conserva. Pero hay elementos con el índice 'c' y 'd' en s2, así que si hay una 'nueva versión', actualícela. Entonces s1 ha cambiado de [1 2 3 4] a [1 2 11 22]. En cuanto a los elementos con índice 'e' y 'f' en s2, no tienen nada que ver con s1, porque s1 no tiene ningún índice como 'e' , El elemento de 'f', es inútil proporcionar la 'nueva versión' en s2. Por lo tanto, el uso de la actualización se realiza localmente en s1. El índice y el número de elementos de s1 no cambiarán antes y después de la operación.

当然update也适用于对两个DataFrame进行操作,有兴趣可以自己去了解。

Supongo que te gusta

Origin www.cnblogs.com/traditional/p/12727997.html
Recomendado
Clasificación