データフレームの列を効率的に処理するには、combine_first、combine、updateを使用します

くさび

パンダを使用してデータを処理するとき、データの1つの列を別の列に置き換えることがよくあります。たとえば、列AおよびBは、列Aで空でないデータを処理せず、列Aで空であるデータを列Bに対応するデータで置き換えます。このタイプの需要は多くの人が遭遇すると推定されていますが、もちろん他にももっと複雑なものがあります。

この種の要求を解決するには、低効率で適用したり、ベクトル化された場所を使用したりするなど、多くの方法があります。そこで今回は、いくつかの非常に単純で同等に効率的な方法を見てみましょう。

Combine_first

このメソッドは特にnull値を処理するために使用されます。使用法を見てみましょう

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
"""

使用方法は非常に簡単です。1つ目は2つのSeriesオブジェクトです。s1とs2と呼ばれ、s1.combine_first(s2)はs1の空のデータをs2に置き換えることを意味します。すべてが空の場合、結果は空のみになります。もちろん、このメソッドは適切に動作しませんが、新しいSeriesオブジェクトを返します

さらに、この方法の理想的な前提は、2つのSeriesオブジェクトのインデックスが一貫していることです。これは、置換が場所を指定するインデックスに基づいているためです。

たとえば、s1のインデックス1のデータが空の場合、s2のインデックス1のデータが置換に使用されます。ただし、s2にインデックス1のデータがない場合は、置き換えられません。また、s2にはインデックス100のデータがあり、s1にはないデータがあると想定されている場合、結果はインデックス100のデータがもう1つあります。

実演してみましょう

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
"""

説明すると、最初に置き換えるのは、s1の値が空のデータで、空でない場合、処理は行われません。インデックス "b"と "c"であるs1には2つの空のデータがあり、s2のインデックス "b"と "c"を持つデータが置き換えられます。ただし、s2にはインデックス "b"のデータがありますが、インデックス "c"のデータはないため、置き換えられる値は1つだけです。

さらに、末尾にインデックスeのデータがさらにあることがわかります、はい、s2のデータがs1にない場合は、直接追加されると言います。

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
"""

s2には、インデックス「e」と「f」のデータがあるが、s1にはないので、直接追加します。もちろん、s1のデータがs2にない場合、s1も直接保持されます。両方ある場合は、s1のデータが空かどうかを確認し、空の場合は、s2のインデックスに対応するデータで置き換えます。空でない場合は、s1を保持、つまり置き換えないでください。

もちろん、ほとんどの場合、同じDataFrameの2つの列を処理します。同じDataFrameの2つの列の場合、それらのインデックスは明らかに同じであるため、単純に上から下に配置されているため、あまり大したことはありません。 。

組み合わせる

Combineは、関数を指定する必要があることを除いて、combine_firstに似ています。

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
"""

匿名関数を指定しました。パラメーターaおよびbは、対応する各データをdf ["A"]およびdf ["B"]で表します。aが空でない場合はaを返し、それ以外の場合はbを返します。

したがって、combine_firstの効果を達成するために、combineを使用していることがわかります。Combine_firstは特にnull値を置き換えますが、結合によりロジックを自分で指定できます。Combine_firstの機能だけでなく、他の機能も実現できます

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
"""

コンバインの機能はまだ非常に強力ですが、もちろんインデックスに対しても動作します。実際、combineとCombine_firstは最初に内部でインデックスを処理します。2つのSeriesオブジェクトのインデックスが同じでない場合、最初に一貫性があります。

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的索引变得一致之后,依次进行操作。

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
"""

もう一度コンバインを振り返って

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的元素就没有必要分析了,显然是保留大的那个

したがって、その文では、combineとCombine_firstの場合、同じインデックスの要素を比較しています。2つのSeriesオブジェクトのインデックスが異なる場合は、最初に和集合が取得され、次に再インデックスが作成されてから比較されます。別の栗を与える:

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

したがって、2つのメソッドCombineおよびCombine_firstを使用する場合、インデックスを覚えておく必要があります。そうしないと、トラップが発生する可能性があります。実際、パンダを含む他の多くの操作があり、それらはすべて単純に左から右または上から下ではなく、インデックスに基づいています

しかし、その文でも、DataFrameの2つの列を操作することが多く、それらのインデックスは同じであるため、あまり深く考える必要はありません。

もちろん、Seriesオブジェクトに加えて、これらの2つのメソッドは、df1.combine(df2、func)などのDataFrameオブジェクトをターゲットにして同じ列を置き換えることもできますが、あまり一般的ではありません。興味がある場合は、自分で調べることができます。主にSeriesオブジェクトに作用します

更新

更新は比較的残忍です。見てみましょう。

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
"""

まず、このメソッドがローカルで操作されていることがわかります。関数は、s1の要素をs2の要素に置き換え、s2の要素が空でない限り、それを置き換えます。

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
"""

したがって、この関数は更新と呼ばれ、更新を意味します。s1の要素をs2の要素で置き換えますが、s2の要素が空の場合、「新しいバージョン」がまだ出ていないと考えられ、古いバージョンがまだ使用されているため、s1の3は置き換えられていません。

したがって、updateとCombine_firstは似ていますが、違いは次のとおりです。

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

さらに、combine_firstの実行中に、インデックス作成の問題を繰り返し強調しましたが、s1とs2のインデックスが異なる場合、結果の要素の数は多くなります。ただし、ローカルで操作されるため、つまりs1をローカルで直接変更するため、更新は異なります。したがって、s1の要素数は変化しません。

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
"""

s2にインデックス「a」と「b」を持つ要素がない場合、「新しいバージョン」が表示されていないと見なすことができるため、元の値は更新および保持されません。ただし、s2にはインデックス「c」と「d」を持つ要素があるため、「新しいバージョン」がある場合は更新します。したがって、s1は[1 2 3 4]から[1 2 11 22]に変更されました。s2のインデックス 'e'および 'f'を持つ要素は、s1には 'e'のようにインデックスがないため、s1とは何の関係もありません。 、「f」の要素。s2に「新しいバージョン」を提供しても意味がありません。したがって、更新の使用はs1でローカルに実行されます。s1のインデックスと要素数は、操作の前後で変化しません。

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

おすすめ

転載: www.cnblogs.com/traditional/p/12727997.html