使用索引为pandas DataFrame中的特定单元格设置值


477

我创建了一个Pandas DataFrame

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

并得到这个

    y
NaN NaN
B NaN NaN
Na


然后,我想为特定的单元格赋值,例如行“ C”和列“ x”。我期望得到这样的结果:

    y
NaN NaN
B NaN NaN
C 10 NaN

使用此代码:

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

但内容df没有改变。再次仅NaN在DataFrame中。

有什么建议么?


29
不要使用“链接索引”(df['x']['C']),请使用df.ix['x','C']
Yariv

3
索引访问的顺序必须为:dataframe[column (series)] [row (Series index)],而许多人(包括我自己)更习惯该dataframe[row][column]顺序。作为一个Matlab和R程序员后者感觉更直观的给我,但,显然不是熊猫的工作方式..
Zhubarb

1
我试过了,但是最后我添加了另一个行名x和另一个列名C。您必须先执行该行,然后再执行该列。因此df.ix ['C','x'] = 10
马修(Matthew)

5
@Yariv的评论。警告:从0.20.0开始,不建议使用.ix索引器,而建议使用更严格的.iloc和.loc索引器。pandas.pydata.org/pandas-docs/stable/generated/...。df.at看起来像是粘在身边。
jeffhale '18

Answers:


592

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.x的API。你什么意思?
smci 2013年

3
@smci:'x'是中的列名称dfdf.x返回Series带有列中的值的x。我将其更改为,df['x']因为该表示法可与任何列名一起使用(与点表示法不同),并且我认为更清晰。
unutbu

1
我知道,我以为您是在说df.x一种未知的新方法df.xs, df.ix
smci 2013年

df.xs(..., copy=True)返回一个副本,这是默认行为。df.xs(..., copy=False)返回原始。
smci

7
据维护人员说,这不是建议的设置值的方法。看到stackoverflow.com/a/21287235/1579844和我的答案。
Yariv

224

更新:该.set_value方法将不推荐使用.iat/.at是很好的替代品,不幸的是熊猫提供的文件很少


最快的方法是使用set_value。该方法比.ix方法快100倍。例如:

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


5
甚至比更好df['x']['C'] = 10
ALH 2015年

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

是的(熊猫0.16.2)
RukTech

是否可以使用它来将值设置为df=df.append(df.sum(numeric_only=True),ignore_index=True)
ctrl-alt-

94

您还可以使用条件查询,.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
第二列必须放在方括号中,否则所有列将被值覆盖。像这样:df.loc[df['age']==3, ['age-group']] = 'toddler'
Piizei

当<some_column_name>是我的索引(例如,unixtime索引)并且我试图添加尚未退出的时间戳(即新的时间戳读取)时,我无法使用此功能。有什么想法吗?
yeliabsalohcin

是否可以根据索引和单元格值更改值?
BND

@BND我不确定,但是您可以绕开这个明显的陷阱,而只是将索引列与另一个具有相同值的列复制?简短的答案是我不知道。
布莱尔

@yeliabsalohcin参见以上答案。
布莱尔23


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,两者都提供基于标签的查找。使用at,如果你只需要获取或在数据帧或系列设置一个值。来自padas doc
Rutrus '18

当索引元素为数字时,这对我有用。
克里斯托弗·约翰

这不适用于数字和字符串索引的混合。
Seanny123 '19

12

.iat/.at是很好的解决方案。假设您有一个简单的data_frame:

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

如果我们要修改单元格的值,则[0,"A"]可以使用以下解决方案之一:

  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

7

要设置值,请使用:

df.at[0, 'clm1'] = 0
  • 推荐的最快的设置变量的方法。
  • set_valueix已弃用。
  • 没有警告,与ilocloc

1
得出了完全相同的结论
prosti,


6

在我的示例中,我只是在选定的单元格中对其进行了更改

    for index, row in result.iterrows():
        if np.isnan(row['weight']):
            result.at[index, 'weight'] = 0.0

“结果”是带有“权重”列的dataField


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

将索引与条件一起使用的一种方法是,首先获取满足您条件的所有行的索引,然后简单地以多种方式使用这些行索引

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

示例条件如下

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

然后,您可以通过多种方式使用这些行索引,例如

  1. 将一列的值替换为conditional_index
df.loc[conditional_index , [col name]]= <new value>
  1. 将多列的值替换为conditional_index
df.loc[conditional_index, [col1,col2]]= <new value>
  1. 保存conditional_index的一个好处是,您可以将一列的值分配给具有相同行索引的另一列
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 s)
    • ...将其串联(13.1 s)
  • 首先将所有新行存储在另一个容器中,一次转换为新数据框,然后追加...
    • container =清单清单(2.0 s)
    • container =列表字典(1.9 s)
  • 预分配整个数据框,遍历新行和所有列,并使用
    • ...在(0.6 s)
    • ... 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',C]的NaN转换为值10

答案是..

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

替代代码是

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

-4

我也在寻找这个主题,并且提出了一种方法来遍历DataFrame并使用第二个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'])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.