パンダのマップ、applymap、applyメソッドの違い


465

基本的な例でこれらのベクトル化方法をいつ使用するか教えてもらえますか?

私は見mapているSeries残りの部分であるのに対し、法DataFrame方法。applyapplymap方法について混乱しました。関数をDataFrameに適用する方法が2つあるのはなぜですか?繰り返しになりますが、使用法を説明する簡単な例はすばらしいでしょう。


5
私が間違っている場合は修正してください。ただし、これらの関数はすべて、それらが適用される要素に対するループを含んでいるため、ベクトル化メソッドではないと考えています。
Tanguy

1
ここでは違いを確認できません:gist.github.com/MartinThoma/e320cbb937afb4ff766f75988f1c65e6
Martin Thoma

回答:


533

Wes McKinneyによるPython for Data Analysisの本、pg。132(私はこの本を強くお勧めします):

もう1つのよくある操作は、1D配列の関数を各列または行に適用することです。DataFrameのapplyメソッドはまさにこれを行います:

In [116]: frame = DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [117]: frame
Out[117]: 
               b         d         e
Utah   -0.029638  1.081563  1.280300
Ohio    0.647747  0.831136 -1.549481
Texas   0.513416 -0.884417  0.195343
Oregon -0.485454 -0.477388 -0.309548

In [118]: f = lambda x: x.max() - x.min()

In [119]: frame.apply(f)
Out[119]: 
b    1.133201
d    1.965980
e    2.829781
dtype: float64

最も一般的な配列統計の多く(合計や平均など)はDataFrameメソッドであるため、applyを使用する必要はありません。

要素ごとのPython関数も使用できます。フレーム内の各浮動小数点値からフォーマットされた文字列を計算したいとします。あなたはapplymapでこれを行うことができます:

In [120]: format = lambda x: '%.2f' % x

In [121]: frame.applymap(format)
Out[121]: 
            b      d      e
Utah    -0.03   1.08   1.28
Ohio     0.65   0.83  -1.55
Texas    0.51  -0.88   0.20
Oregon  -0.49  -0.48  -0.31

applymapという名前の理由は、Seriesには要素ごとの関数を適用するためのマップメソッドがあるためです。

In [122]: frame['e'].map(format)
Out[122]: 
Utah       1.28
Ohio      -1.55
Texas      0.20
Oregon    -0.31
Name: e, dtype: object

まとめるapplyと、DataFrameの行/列ベースでapplymap機能し、DataFrameでmap要素ごとに機能し、Seriesで要素ごとに機能します。


31
厳密に言えば、applymap内部(rougly交換話す少しラップアップオーバー渡された関数のパラメータを適用を通じて実現されfunclambda x: [func(y) for y in x]、そして列方向を適用)
ALKO

5
説明ありがとう。以来mapapplymap作業要素単位の両方、私は一つの方法(いずれかを期待するmapか、applymapシリーズおよびデータフレームの両方に働くだろう)。おそらく他にも設計上の考慮事項があり、ウェスマッキーニーは2つの異なる方法を考え出すことにしました。
マリオン2013年

2
どういうわけか私のコピーの129ページにあります。第二版などのレーベルはありません。
ジョディ2016年

1
パンダの機能とapplymap一緒に行う方法はありgroupbyますか?
everestial007 2017

グループ化された列ごとのデータに関数を適用する方法は?
hhh 2018

83

比較mapapplymapおよび:コンテキストが重要apply

最初の大きな違い:DEFINITION

  • map シリーズのみで定義
  • applymap DataFramesでのみ定義されています
  • apply 両方に定義されています

2番目の大きな違い:入力引数

  • mapdicts Series、、または呼び出し可能を受け入れます
  • applymapapply呼び出し可能オブジェクトのみを受け入れる

第三の主な違い:BEHAVIOR

  • map シリーズの要素ごと
  • applymap データフレームの要素ごとです
  • apply要素ごとにも機能しますが、より複雑な操作と集計に適しています。動作と戻り値は関数によって異なります。

4番目の大きな違い(最も重要な違い):ユースケース

  • map あるドメインから別のドメインに値をマッピングするためのものなので、パフォーマンスが最適化されます( df['A'].map({1:'a', 2:'b', 3:'c'})
  • applymap 複数の行/列にわたる要素ごとの変換に適しています(たとえば、 df[['A', 'B', 'C']].applymap(str.strip)
  • apply(例えば、ベクトル化することはできません任意の関数を適用するためのものですdf['sentences'].apply(nltk.sent_tokenize)

まとめ

ここに画像の説明を入力してください

脚注

  1. map辞書/シリーズが渡されると、その辞書/シリーズのキーに基づいて要素がマップされます。欠損値はNaNとして出力に記録されます。
  2. applymap最近のバージョンでは、一部の操作用に最適化されています。場合によってapplymapapply、わずかに速くなります。私の提案は、両方をテストし、より適切に機能するものを使用することです。

  3. map要素ごとのマッピングと変換用に最適化されています。辞書またはシリーズを含む操作により、パンダはより高速なコードパスを使用してパフォーマンスを向上させることができます。

  4. Series.apply集計操作のスカラーを返し、それ以外の場合はSeriesを返します。同様にDataFrame.apply。メモapplyなどの特定のnumpyの関数で呼び出されたときにもfastpathsを有するmeansum

70

これらの回答にはすばらしい情報がありますが、どの方法が配列と要素のどちらで機能するかを明確に要約するために、独自の情報を追加しています。jeremiahbuddhaは主にこれを行いましたが、Series.applyについては言及しませんでした。コメントする担当者がいません。

  • DataFrame.apply 行または列全体を一度に操作します。

  • DataFrame.applymapSeries.applySeries.map一度に一つの要素を操作します。

Series.applyとの機能には多くのオーバーラップがありますSeries.map。つまり、ほとんどの場合、どちらでも機能します。ただし、若干の違いはありますが、それらのいくつかはosaの回答で説明されています。


38

他の回答に加えて、Seriesそこにもマップ適用があります

ApplyはDataFrameをシリーズから作成できます。ただし、マップはシリーズを別のシリーズのすべてのセルに配置するだけであり、これはおそらく望んでいることではありません。

In [40]: p=pd.Series([1,2,3])
In [41]: p
Out[31]:
0    1
1    2
2    3
dtype: int64

In [42]: p.apply(lambda x: pd.Series([x, x]))
Out[42]: 
   0  1
0  1  1
1  2  2
2  3  3

In [43]: p.map(lambda x: pd.Series([x, x]))
Out[43]: 
0    0    1
1    1
dtype: int64
1    0    2
1    2
dtype: int64
2    0    3
1    3
dtype: int64
dtype: object

また、「Webサーバーに接続する」などの副作用のある関数がある場合は、applyわかりやすくするためだけに使用します。

series.apply(download_file_for_every_element) 

Map関数だけでなく、辞書や他のシリーズも使用できます。順列を操作したいとしましょう。

取る

1 2 3 4 5
2 1 4 5 3

この順列の二乗は

1 2 3 4 5
1 2 5 3 4

を使用して計算できmapます。自己申告が文書化されているかどうかは不明ですが、で機能し0.15.1ます。

In [39]: p=pd.Series([1,0,3,4,2])

In [40]: p.map(p)
Out[40]: 
0    0
1    1
2    4
3    2
4    3
dtype: int64

3
また、.apply()を使用すると、関数にkwargsを渡すことができますが、.map()はできません。
neilxdims

19

@jeremiahbuddhaは、applymapが要素単位で機能するのに対し、applyは行/列で機能すると述べました。しかし、要素ごとの計算に適用を使用できるようです...

    frame.apply(np.sqrt)
    Out[102]: 
                   b         d         e
    Utah         NaN  1.435159       NaN
    Ohio    1.098164  0.510594  0.729748
    Texas        NaN  0.456436  0.697337
    Oregon  0.359079       NaN       NaN

    frame.applymap(np.sqrt)
    Out[103]: 
                   b         d         e
    Utah         NaN  1.435159       NaN
    Ohio    1.098164  0.510594  0.729748
    Texas        NaN  0.456436  0.697337
    Oregon  0.359079       NaN       NaN

29
これで良いキャッチ。これがあなたの例で機能する理由は、np.sqrtがufuncであるためです。つまり、配列を指定すると、配列の各要素にsqrt関数がブロードキャストされます。したがって、applyが各列にnp.sqrtをプッシュすると、np.sqrtは列の各要素に対してそれ自体が機能するため、applymapと基本的に同じ結果が得られます。
jeremiahbuddha 2014年

11

指摘したかったのですが、私はこれに少し苦労しました。

def f(x):
    if x < 0:
        x = 0
    elif x > 100000:
        x = 100000
    return x

df.applymap(f)
df.describe()

これはデータフレーム自体を変更しないため、再割り当てする必要があります

df = df.applymap(f)
df.describe()

1
dfで何かをした後で、再割り当てする必要があるかどうかわからないことがあります。それはほとんど私にとって試行錯誤ですが、私はそれがどのように機能するかについての論理があると思います(私はそれを逃しています)。
16:19のマリオン

2
通常、pandasデータフレームは、再割り当てするdf = modified_dfか、inplace=Trueフラグを設定した場合にのみ変更されます。また、データフレームを参照によって関数に渡し、関数がデータフレームを変更すると、データフレームも変化します
muon

1
これは完全に真実ではない、と考える.ix.whereなどわからない完全な説明は、あなたが再割り当てていないときに必要なときに何のためにあるのか。
Thanos

10

おそらく最も単純な説明は、applyとapplymapの違いです。

applyは列全体をパラメータとして取り、結果をこの列に割り当てます

applymapは、個別のセル値をパラメーターとして取り、結果をこのセルに割り当てます。

注意:applyが単一の値を返す場合、割り当て後は列ではなくこの値が得られ、最終的には行列ではなく行のみが得られます。


3

私の理解:

機能の観点から:

関数に列/行内で比較する必要がある変数がある場合は、を使用します apply

例:lambda x: x.max()-x.mean()

関数を各要素に適用する場合:

1>列/行が見つかった場合は、 apply

2>データフレーム全体に適用する場合は、 applymap

majority = lambda x : x > 17
df2['legal_drinker'] = df2['age'].apply(majority)

def times10(x):
  if type(x) is int:
    x *= 10 
  return x
df2.applymap(times10)

コードをテストできるように、わかりやすくするためにdf2も提供してください。
Ashish Anand

1

cs95の回答に基づく

  • map シリーズのみで定義
  • applymap DataFramesでのみ定義されています
  • apply 両方に定義されています

いくつかの例を挙げてください

In [3]: frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [4]: frame
Out[4]:
            b         d         e
Utah    0.129885 -0.475957 -0.207679
Ohio   -2.978331 -1.015918  0.784675
Texas  -0.256689 -0.226366  2.262588
Oregon  2.605526  1.139105 -0.927518

In [5]: myformat=lambda x: f'{x:.2f}'

In [6]: frame.d.map(myformat)
Out[6]:
Utah      -0.48
Ohio      -1.02
Texas     -0.23
Oregon     1.14
Name: d, dtype: object

In [7]: frame.d.apply(myformat)
Out[7]:
Utah      -0.48
Ohio      -1.02
Texas     -0.23
Oregon     1.14
Name: d, dtype: object

In [8]: frame.applymap(myformat)
Out[8]:
            b      d      e
Utah     0.13  -0.48  -0.21
Ohio    -2.98  -1.02   0.78
Texas   -0.26  -0.23   2.26
Oregon   2.61   1.14  -0.93

In [9]: frame.apply(lambda x: x.apply(myformat))
Out[9]:
            b      d      e
Utah     0.13  -0.48  -0.21
Ohio    -2.98  -1.02   0.78
Texas   -0.26  -0.23   2.26
Oregon   2.61   1.14  -0.93


In [10]: myfunc=lambda x: x**2

In [11]: frame.applymap(myfunc)
Out[11]:
            b         d         e
Utah    0.016870  0.226535  0.043131
Ohio    8.870453  1.032089  0.615714
Texas   0.065889  0.051242  5.119305
Oregon  6.788766  1.297560  0.860289

In [12]: frame.apply(myfunc)
Out[12]:
            b         d         e
Utah    0.016870  0.226535  0.043131
Ohio    8.870453  1.032089  0.615714
Texas   0.065889  0.051242  5.119305
Oregon  6.788766  1.297560  0.860289

0

FOMO:

次の例はapply、にapplymap適用されていDataFrameます。

map関数は、シリーズにのみ適用するものです。map DataFrameには適用できません。

覚えておく applyべきこと applymapは、何でもできることですが、eXtraがありapplyます。オプションます。

Xファクターのオプションは次のとおりaxisresult_typeどこresult_typeときにのみ機能しますaxis=1(列のため)。

df = DataFrame(1, columns=list('abc'),
                  index=list('1234'))
print(df)

f = lambda x: np.log(x)
print(df.applymap(f)) # apply to the whole dataframe
print(np.log(df)) # applied to the whole dataframe
print(df.applymap(np.sum)) # reducing can be applied for rows only

# apply can take different options (vs. applymap cannot)
print(df.apply(f)) # same as applymap
print(df.apply(sum, axis=1))  # reducing example
print(df.apply(np.log, axis=1)) # cannot reduce
print(df.apply(lambda x: [1, 2, 3], axis=1, result_type='expand')) # expand result

補足として、Series map関数はPythonと混同しないでくださいmap関数。

1つ目は値をマップするためにシリーズに適用され、2つ目はイテラブルのすべてのアイテムに適用されます。


最後に、dataframe applyメソッドとgroupby applyメソッドを混同しないでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.