インデックスを使用して、pandas DataFrameの特定のセルに値を設定します


478

Pandas DataFrameを作成しました

df = DataFrame(index=['A','B','C'], columns=['x','y'])

そしてこれを手に入れました

    xy
NaN NaN
B NaN NaN
C NaN NaN


次に、特定のセル、たとえば行「C」と列「x」に値を割り当てたいと思います。私はそのような結果を得ることを期待していました:

    xy
NaN NaN
B NaN NaN
C 10 NaN

このコードで:

df.xs('C')['x'] = 10

の内容はdf変更されていません。これもNaNDataFrameにのみ存在します。

助言がありますか?


29
「連鎖索引付け」(df['x']['C'])を使用しないでくださいdf.ix['x','C']
Yariv 14年

3
インデックスアクセスの順序は次のようにする必要があります。dataframe[column (series)] [row (Series index)]一方、多くの人(自分自身を含む)はこのdataframe[row][column]順序に慣れています。MATLABおよびRプログラマーとして私には、より直感的にそれは明らかにパンダが動作する方法はない..です後者フィール
Zhubarb

1
私はそれを試してみましたが、結局別の行名xと別の列名Cを追加することになりました。最初に行、次に列を実行する必要があります。so df.ix ['C'、 'x'] = 10
マシュー

5
@Yarivのコメントへ。警告:0.20.0以降、.ixインデクサーは廃止され、より厳密な.ilocおよび.locインデクサーが採用されました。pandas.pydata.org/pandas-docs/stable/generated/…。df.atは固執しているようです。
jeffhale

回答:


593

RukTechの回答、はdf.set_value('C', 'x', 10)、以下に提案したオプションよりもはるかに高速です。ただし、非推奨となる予定です

今後、推奨される方法は.iat/.atです。


なぜdf.xs('C')['x']=10機能しないのですか?

df.xs('C')デフォルトでは、データのコピーを含む新しいデータフレーム返すため、

df.xs('C')['x']=10

この新しいデータフレームのみを変更します。

df['x']dfデータフレームのビューを返すので、

df['x']['C'] = 10

df自分自身を改変します。

警告:オペレーションがコピーまたはビューを返すかどうかを予測することが難しい場合があります。このため、ドキュメントでは「連鎖インデックス」を使用した割り当てを避けることを推奨しています。


したがって、推奨される代替策は

df.at['C', 'x'] = 10

これ変更しませんdf


In [18]: %timeit df.set_value('C', 'x', 10)
100000 loops, best of 3: 2.9 µs per loop

In [20]: %timeit df['x']['C'] = 10
100000 loops, best of 3: 6.31 µs per loop

In [81]: %timeit df.at['C', 'x'] = 10
100000 loops, best of 3: 9.2 µs per loop

以下のようなものはありませんdf.xAPIが。どういう意味?
smci 2013年

3
@smci:はの'x'列の名前ですdf。columnの値を持つdf.xa Seriesを返しますxdf['x']この表記は(ドット表記とは異なり)すべての列名で機能し、より明確になるので、これをに変更します。
unutbu 2013年

1
私は、それを知っていた私は、あなたが言っていたと思ったdf.xと一緒にいくつかの未知の新しい方法だったdf.xs, df.ix
SMCI

df.xs(..., copy=True)コピーを返します。これがデフォルトの動作です。df.xs(..., copy=False)オリジナルを返します。
smci 2013年

7
メンテナーによると、これは値を設定するための推奨される方法ではありません。stackoverflow.com/a/21287235/1579844と私の回答を参照してください。
Yariv 14年

225

更新:.set_valueメソッドは廃止される予定です.iat/.at良い代替品ですが、残念ながらパンダはほとんどドキュメントを提供していません


これを行う最も速い方法は、set_valueを使用することです。この方法は、.ix方法よりも約100倍高速です。例えば:

df.set_value('C', 'x', 10)


5
それよりも優れていdf['x']['C'] = 10 ます。
ALH

6
1000ループ、最高3:ループあたり195 µs "df ['x'] ['C'] = 10" 1000ループ、最高3:ループあたり310 µs "df.ix ['C'、 'x'] = 10 インチ1000ループ、最高3:189 µs /ループ "df.xs( 'C'、copy = False)['x'] = 10" 1000ループ、最高3:7.22 µs /ループ "df.set_value ( 'C'、 'x'、10) "
propjk007

1
これは、データフレームに新しい行/列を追加するためにも機能しますか?
st.ph.n 2016

はい(パンダ0.16.2の場合)
RukTech

これを使用して値をaに設定することは可能df=df.append(df.sum(numeric_only=True),ignore_index=True)ですか?
ctrl-alt-delete

95

次のようにして、条件付きルックアップを使用することもでき.locます。

df.loc[df[<some_column_name>] == <condition>, [<another_column_name>]] = <value_to_add>

ここ<some_column_nameで、は<condition>変数をチェックする列であり、<another_column_name>追加先の列です(新しい列または既存の列にすることができます)。<value_to_add>その列/行に追加する値です。

この例は、目の前の質問では正確に機能しませんが、条件に基づいて特定の値を追加したい場合に役立つことがあります。


8
2番目の列は括弧で囲む必要があります。そうしないと、すべての列が値で上書きされます。このように:df.loc[df['age']==3, ['age-group']] = 'toddler'
Piizei

<some_column_name>がインデックス(unixtimeインデックスなど)で、まだ存在しないタイムスタンプ(つまり、新しいタイムスタンプの読み取り)を追加しようとすると、これを機能させることができません。何かご意見は?
yeliabsalohcin

インデックスとセル値に基づいて値を変更することは可能ですか?
BND

@BNDわかりませんが、この明らかな落とし穴を回避することができますが、同じ値を持つ別の列でインデックス列を複製するだけですか?簡単に言えば、私にはわかりません。
Blairg23、

@yeliabsalohcin上記の回答を参照してください。
Blairg23

40

(メンテナによると)値を設定するための推奨される方法は次のとおりです。

df.ix['x','C']=10

'連鎖索引付け'(df['x']['C'])を使用すると、問題が発生する可能性があります。

見る:



完璧に動作します!いつか廃止される予定ですが!
Pavlos Ponos

35

使ってみてください df.loc[row_index,col_indexer] = value


6
Stack Overflowへようこそ!投稿を編集して、コードの機能と問題を解決する理由を詳しく説明してください。通常、コードが含まれているだけの回答(たとえそれが機能していても)は、通常、OPが問題を理解するのに役立ちません。推測だけの回答は投稿しないことをお勧めします。良い答えは、なぜOPの問題を解決できるかについてもっともらしい理由があります。
SuperBiasedMan

22

これは私のために働いた唯一のものです!

df.loc['C', 'x'] = 10

詳細については、.loc こちらをご覧ください。


たの.loc置き換え.iat/.at
ガブリエルフェア

1
atと同様にloc、どちらもラベルベースのルックアップを提供します。atDataFrameまたはSeriesで単一の値を取得または設定する必要があるだけの場合に使用します。Padas Doc
Rutrus 2018

インデックス要素が数値の場合、これはうまくいきました。
クリストファージョン

これは、数値インデックスと文字列インデックスが混在している場合は機能しません。
Seanny123

12

.iat/.at良い解決策です。次の単純なdata_frameがあるとします。

   A   B   C
0  1   8   4 
1  3   9   6
2  22 33  52

セルの値を変更したい場合、[0,"A"]uはこれらのソリューションの1つを使用できます。

  1. df.iat[0,0] = 2
  2. df.at[0,'A'] = 2

そして、これはを使用iatしてcellの値を取得および設定する方法の完全な例です:

def prepossessing(df):
  for index in range(0,len(df)): 
      df.iat[index,0] = df.iat[index,0] * 2
  return df

前のy_train:

    0
0   54
1   15
2   15
3   8
4   31
5   63
6   11

y_train iatは、各セルの値に2を乗算するように変更する、事前に推測された関数を呼び出した後です。

     0
0   108
1   30
2   30
3   16
4   62
5   126
6   22


6

使用できます.iloc

df.iloc[[2], [0]] = 10

このメソッドはいくつかの値をサポートしていないようです。たとえばdf.iloc[[2:8], [0]] = [2,3,4,5,6,7]、メソッドdf.loc()がネイティブにサポートしている値です。
strpeter 2017年

1
完全に機能し、非推奨の警告はありません!
Pavlos Ponos


4

set_value() 廃止予定です。

リリース0.23.4から、Pandasは「未来を発表します」...

>>> df
                   Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        245.0
2      Chevrolet Malibu        190.0
>>> df.set_value(2, 'Prices (U$)', 240.0)
__main__:1: FutureWarning: set_value is deprecated and will be removed in a future release.
Please use .at[] or .iat[] accessors instead

                   Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        245.0
2      Chevrolet Malibu        240.0

このアドバイスを考慮して、これらを使用する方法のデモを次に示します。

  • 行/列の整数位置

>>> df.iat[1, 1] = 260.0
>>> df
                   Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        260.0
2      Chevrolet Malibu        240.0
  • 行/列ラベル

>>> df.at[2, "Cars"] = "Chevrolet Corvette"
>>> df
                  Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        260.0
2    Chevrolet Corvette        240.0

参照:


3

以下は、整数と文字列でインデックスが付けられたデータフレームに対して、すべてのユーザーが提供する有効なソリューションの概要です。

df.iloc、df.locおよびdf.atは両方のタイプのデータフレームで機能し、df.ilocは行/列の整数インデックスでのみ機能し、df.locおよびdf.atは列名および/または整数インデックスを使用した値の設定をサポートします。

指定されたインデックスが存在しない場合、df.locとdf.atの両方が既存のデータフレームに新しく挿入された行/列を追加しますが、df.ilocは「IndexError:位置インデクサーが範囲外です」を発生させます。Python 2.7および3.7でテストされた実際の例は次のとおりです。

import numpy as np, pandas as pd

df1 = pd.DataFrame(index=np.arange(3), columns=['x','y','z'])
df1['x'] = ['A','B','C']
df1.at[2,'y'] = 400

# rows/columns specified does not exist, appends new rows/columns to existing data frame
df1.at['D','w'] = 9000
df1.loc['E','q'] = 499

# using df[<some_column_name>] == <condition> to retrieve target rows
df1.at[df1['x']=='B', 'y'] = 10000
df1.loc[df1['x']=='B', ['z','w']] = 10000

# using a list of index to setup values
df1.iloc[[1,2,4], 2] = 9999
df1.loc[[0,'D','E'],'w'] = 7500
df1.at[[0,2,"D"],'x'] = 10
df1.at[:, ['y', 'w']] = 8000

df1
>>> df1
     x     y     z     w      q
0   10  8000   NaN  8000    NaN
1    B  8000  9999  8000    NaN
2   10  8000  9999  8000    NaN
D   10  8000   NaN  8000    NaN
E  NaN  8000  9999  8000  499.0

3

私はテストしましたが、出力はdf.set_value少し高速ですが、公式の方法df.atは非推奨の最速の方法のように見えます。

import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.rand(100, 100))

%timeit df.iat[50,50]=50 # ✓
%timeit df.at[50,50]=50 #  ✔
%timeit df.set_value(50,50,50) # will deprecate
%timeit df.iloc[50,50]=50
%timeit df.loc[50,50]=50

7.06 µs ± 118 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
5.52 µs ± 64.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
3.68 µs ± 80.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
98.7 µs ± 1.07 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
109 µs ± 1.42 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

これは単一のセルの値を設定していることに注意してください。ベクターについてlociloc、彼らはベクトル化されているので、より良い選択肢でなければなりません。


3

条件付きインデックスを使用する1つの方法は、まず条件を満たすすべての行のインデックスを取得してから、それらの行インデックスを複数の方法で使用することです

conditional_index = df.loc[ df['col name'] <condition> ].index

条件の例は

==5, >10 , =="Any string", >= DateTime

次に、これらの行インデックスをさまざまな方法で使用できます

  1. conditional_indexの1つの列の値を置き換える
df.loc[conditional_index , [col name]]= <new value>
  1. conditional_indexの複数の列の値を置き換える
df.loc[conditional_index, [col1,col2]]= <new value>
  1. conditional_indexを保存すると、1つの列の値を、同じ行インデックスを持つ別の列に割り当てることができます。
df.loc[conditional_index, [col1,col2]]= df.loc[conditional_index,'col name']

.indexは.locが直接アドレス指定で使用できるインデックスの配列を返すので、これはすべて可能です。


行の変更についてはどうですか?
FabioSpaghetti、

ただ使用します。df.loc[conditional_index、] = <新しい値>条件を満たす行のすべての列の新しい値を置き換えます
Atta Jutt


1

上記の回答に加えて、既存のデータフレームにデータ行を追加するさまざまな方法を比較するベンチマークがあります。これは、atまたはset-valueを使用することが、(少なくともこれらのテスト条件では)大きなデータフレームに対して最も効率的な方法であることを示しています。

  • 行ごとに新しいデータフレームを作成し、...
    • ...追加します(13.0秒)
    • ...連結する(13.1 s)
  • すべての新しい行を最初に別のコンテナーに保存し、一度新しいデータフレームに変換して追加します...
    • コンテナ=リストのリスト(2.0秒)
    • コンテナ=リストの辞書(1.9秒)
  • データフレーム全体を事前に割り当て、新しい行とすべての列を反復処理し、
    • ...(0.6秒)
    • ... set_value(0.4秒)

テストでは、100,000行と1,000列とランダムなnumpy値で構成される既存のデータフレームが使用されました。このデータフレームに、100の新しい行が追加されました。

コードは以下を参照してください:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 21 16:38:46 2018

@author: gebbissimo
"""

import pandas as pd
import numpy as np
import time

NUM_ROWS = 100000
NUM_COLS = 1000
data = np.random.rand(NUM_ROWS,NUM_COLS)
df = pd.DataFrame(data)

NUM_ROWS_NEW = 100
data_tot = np.random.rand(NUM_ROWS + NUM_ROWS_NEW,NUM_COLS)
df_tot = pd.DataFrame(data_tot)

DATA_NEW = np.random.rand(1,NUM_COLS)


#%% FUNCTIONS

# create and append
def create_and_append(df):
    for i in range(NUM_ROWS_NEW):
        df_new = pd.DataFrame(DATA_NEW)
        df = df.append(df_new)
    return df

# create and concatenate
def create_and_concat(df):
    for i in range(NUM_ROWS_NEW):
        df_new = pd.DataFrame(DATA_NEW)
        df = pd.concat((df, df_new))
    return df


# store as dict and 
def store_as_list(df):
    lst = [[] for i in range(NUM_ROWS_NEW)]
    for i in range(NUM_ROWS_NEW):
        for j in range(NUM_COLS):
            lst[i].append(DATA_NEW[0,j])
    df_new = pd.DataFrame(lst)
    df_tot = df.append(df_new)
    return df_tot

# store as dict and 
def store_as_dict(df):
    dct = {}
    for j in range(NUM_COLS):
        dct[j] = []
        for i in range(NUM_ROWS_NEW):
            dct[j].append(DATA_NEW[0,j])
    df_new = pd.DataFrame(dct)
    df_tot = df.append(df_new)
    return df_tot




# preallocate and fill using .at
def fill_using_at(df):
    for i in range(NUM_ROWS_NEW):
        for j in range(NUM_COLS):
            #print("i,j={},{}".format(i,j))
            df.at[NUM_ROWS+i,j] = DATA_NEW[0,j]
    return df


# preallocate and fill using .at
def fill_using_set(df):
    for i in range(NUM_ROWS_NEW):
        for j in range(NUM_COLS):
            #print("i,j={},{}".format(i,j))
            df.set_value(NUM_ROWS+i,j,DATA_NEW[0,j])
    return df


#%% TESTS
t0 = time.time()    
create_and_append(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
create_and_concat(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
store_as_list(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
store_as_dict(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
fill_using_at(df_tot)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
fill_using_set(df_tot)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

0

行全体ではなく一部の列のみの値を変更する場合:

x = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
x.iloc[1] = dict(A=10, B=-10)


0

Soo、['x'、C]のNaNを値10に変換するための質問

答えは..

df['x'].loc['C':]=10
df

代替コードは

df.loc['C':'x']=10
df

-4

私もこのトピックを検索していて、DataFrameを反復処理して、2番目のDataFrameのルックアップ値で更新する方法をまとめました。これが私のコードです。

src_df = pd.read_sql_query(src_sql,src_connection)
for index1, row1 in src_df.iterrows():
    for index, row in vertical_df.iterrows():
        src_df.set_value(index=index1,col=u'etl_load_key',value=etl_load_key)
        if (row1[u'src_id'] == row['SRC_ID']) is True:
            src_df.set_value(index=index1,col=u'vertical',value=row['VERTICAL'])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.