我创建了一个熊猫数据框
df = DataFrame(index=['A','B','C'], columns=['x','y'])
并得到了这个
x y A NaN NaN B NaN NaN C NaN NaN
现在,我想为特定单元格分配一个值,例如行 C
和列 x
。我希望得到这个结果:
x y A NaN NaN B NaN NaN C 10 NaN
使用此代码:
df.xs('C')['x'] = 10
但是,df
的内容没有改变。数据框再次仅包含 NaN
。
有什么建议么?
df['x']['C']
),使用 df.ix['x','C']
。
dataframe[column (series)] [row (Series index)]
,而很多人(包括我自己)更习惯于dataframe[row][column]
的顺序。作为一名 Matlab 和 R 程序员,后者对我来说感觉更直观,但这显然不是 Pandas 的工作方式。
RukTech's answer、df.set_value('C', 'x', 10)
远远快于我在下面建议的选项。但是,它是 slated for deprecation。
展望未来,recommended method is .iat/.at
。
为什么 df.xs('C')['x']=10
不起作用:
df.xs('C')
默认情况下,返回数据的新数据框 with a copy,因此
df.xs('C')['x']=10
仅修改此新数据框。
df['x']
返回 df
数据框的视图,因此
df['x']['C'] = 10
修改 df
本身。
警告:有时很难预测操作是否返回副本或视图。为此,docs recommend avoiding assignments with "chained indexing"。
所以推荐的替代方案是
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
更新:.set_value
方法将是 deprecated。 .iat/.at
是很好的替代品,不幸的是 pandas 提供的文档很少
最快的方法是使用 set_value。此方法比 .ix
方法快约 100 倍。例如:
df.set_value('C', 'x', 10)
df['x']['C'] = 10
还要好。
df=df.append(df.sum(numeric_only=True),ignore_index=True)
?
您还可以使用 .loc
进行条件查找,如下所示:
df.loc[df[<some_column_name>] == <condition>, [<another_column_name>]] = <value_to_add>
其中 <some_column_name
是您要检查 <condition>
变量的列,而 <another_column_name>
是您要添加到的列(可以是新列或已经存在的列)。 <value_to_add>
是您要添加到该列/行的值。
此示例不适用于手头的问题,但对于想要根据条件添加特定值的人可能很有用。
df.loc[df['age']==3, ['age-group']] = 'toddler'
尝试使用 df.loc[row_index,col_indexer] = value
None
,但是,Pandas 期望该列已经存在;否则它可能会设置错误的值 - 在我的情况下,它是 NaN
导致其他问题。如果该列不存在,Pandas 会给出一个隐藏的 AttributeError
,我只能在调试期间读取它。
设置值的推荐方式(根据维护者)是:
df.ix['x','C']=10
使用“链式索引”(df['x']['C']
) 可能会导致问题。
看:
https://stackoverflow.com/a/21287235/1579844
http://pandas.pydata.org/pandas-docs/dev/indexing.html#indexing-view-versus-copy
https://github.com/pydata/pandas/pull/6031
要设置值,请使用:
df.at[0, 'clm1'] = 0
设置变量的最快推荐方法。
set_value, ix 已被弃用。
没有警告,不像 iloc 和 loc
.iat/.at
是很好的解决方案。假设你有这个简单的 data_frame:
A B C
0 1 8 4
1 3 9 6
2 22 33 52
如果我们想修改单元格 [0,"A"]
的值,您可以使用其中一种解决方案:
df.iat[0,0] = 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
我会建议:
df.loc[index_position, "column_name"] = some_value
在我的示例中,我只是在选定的单元格中更改它
for index, row in result.iterrows():
if np.isnan(row['weight']):
result.at[index, 'weight'] = 0.0
“结果”是一个数据字段,列“权重”
以下是所有用户提供的针对整数和字符串索引的数据帧的有效解决方案的摘要。
df.iloc
、df.loc
和 df.at
适用于两种类型的数据帧,df.iloc
仅适用于行/列整数索引,df.loc
和 df.at
支持使用列名和/或整数索引设置值.
当指定的索引不存在时,df.loc
和 df.at
都会将新插入的行/列附加到现有数据框中,但 df.iloc
会引发 "IndexError: positional indexers are out-of-bounds"
。在 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
避免使用链式索引进行赋值
您正在处理将导致 SettingWithCopy
warning 的 assignment with chained indexing。应该通过一切手段避免这种情况。
您的分配将不得不求助于一个单独的 .loc[]
或 .iloc[]
切片,如 explained here。因此,在您的情况下:
df.loc['C', 'x'] = 10
您可以使用 .iloc
。
df.iloc[[2], [0]] = 10
df.loc()
本身支持的 df.iloc[[2:8], [0]] = [2,3,4,5,6,7]
。
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
参考:
pandas.DataFrame.iat
pandas.DataFrame.at
将索引与条件一起使用的一种方法是首先获取满足条件的所有行的索引,然后以多种方式简单地使用这些行索引
conditional_index = df.loc[ df['col name'] <condition> ].index
示例条件就像
==5, >10 , =="Any string", >= DateTime
然后您可以通过多种方式使用这些行索引,例如
替换 conditional_index 的一列的值
df.loc[conditional_index , [col name]]= <new value>
替换条件索引的多列值
df.loc[conditional_index, [col1,col2]]= <new value>
保存 conditional_index 的一个好处是您可以将一列的值分配给具有相同行索引的另一列
df.loc[conditional_index, [col1,col2]]= df.loc[conditional_index,'col name']
这一切都是可能的,因为 .index 返回一个索引数组, .loc 可以将其用于直接寻址,因此它避免了一次又一次的遍历。
我测试过,输出 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)
请注意,这是为单个单元格设置值。对于向量 loc
和 iloc
应该是更好的选择,因为它们是向量化的。
Soo,您的问题是将 ['x',C] 处的 NaN 转换为值 10
答案是..
df['x'].loc['C':]=10
df
替代代码是
df.loc['C', 'x']=10
df
如果想将 df 位置 (0,0) 中的单元格更改为字符串,例如 '"236"76"'
,则以下选项将起作用:
df[0][0] = '"236"76"'
# %timeit df[0][0] = '"236"76"'
# 938 µs ± 83.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
df.at[0, 0] = '"236"76"'
# %timeit df.at[0, 0] = '"236"76"'
#15 µs ± 2.09 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
df.iat[0, 0] = '"236"76"'
# %timeit df.iat[0, 0] = '"236"76"'
# 41.1 µs ± 3.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
df.loc[0, 0] = '"236"76"'
# %timeit df.loc[0, 0] = '"236"76"'
# 5.21 ms ± 401 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
df.iloc[0, 0] = '"236"76"'
# %timeit df.iloc[0, 0] = '"236"76"'
# 5.12 ms ± 300 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
如果时间相关,使用 pandas.DataFrame.at
是最快的方法。
df.loc['c','x']=10
这将更改第 c 行和第 x 列的值。
如果您不想更改整行的值,而只想更改某些列的值:
x = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
x.iloc[1] = dict(A=10, B=-10)
除了上面的答案,这里是一个基准,比较了将数据行添加到现有数据帧的不同方法。它表明使用 at 或 set-value 是大型数据帧(至少对于这些测试条件)最有效的方法。
为每一行创建新的数据框并... ...附加它(13.0 s)...连接它(13.1 s)
...附加它(13.0 秒)
...连接它(13.1 s)
首先将所有新行存储在另一个容器中,转换为新的数据框一次并追加... 容器 = 列表列表(2.0 秒) 容器 = 列表字典(1.9 秒)
容器 = 列表列表(2.0 秒)
容器 = 列表字典(1.9 秒)
预分配整个数据帧,迭代新行和所有列并使用 ... at (0.6 s) ... set_value (0.4 s) 填充
... 在(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))
我也在搜索这个主题,我整理了一种方法来遍历 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'])
df.x
这样的东西。你什么意思?'x'
是df
中列的名称。df.x
返回一个Series
,其中包含x
列中的值。我将其更改为df['x']
,因为此表示法适用于任何列名(与点表示法不同),而且我认为更清晰。df.x
是与df.xs, df.ix
并列的一些未知的新方法df_temp.iat[0, df_temp.columns.get_loc('Cash')] = df_temp['Cash'].iloc[0] + start_val