Đặt giá trị cho ô cụ thể trong gấu trúc DataFrame bằng chỉ mục


478

Tôi đã tạo một DataFrame Pandas

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

và có được điều này

    xy
Một NaN NaN
B NaN NaN
C NaN NaN


Sau đó, tôi muốn gán giá trị cho ô cụ thể, ví dụ cho hàng 'C' và cột 'x'. Tôi đã mong đợi để có được kết quả như vậy:

    xy
Một NaN NaN
B NaN NaN
C 10 NaN

với mã này:

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

nhưng nội dung dfkhông thay đổi. Nó lại chỉ NaNlà s trong DataFrame.

Bất kỳ đề xuất?


29
Không sử dụng 'lập chỉ mục chuỗi' ( df['x']['C']), sử dụng df.ix['x','C'].
Yariv

3
Thứ tự truy cập chỉ mục cần phải là : dataframe[column (series)] [row (Series index)], trong khi nhiều người (bao gồm cả bản thân tôi) đã quen với dataframe[row][column]đơn hàng hơn. Là một lập trình viên Matlab và R, tôi cảm thấy trực quan hơn với tôi nhưng dường như đó không phải là cách Pandas hoạt động ..
Zhubarb

1
Tôi đã thử điều đó, nhưng cuối cùng tôi đã thêm một tên hàng x và một tên cột khác C. bạn phải thực hiện hàng trước sau đó là cột. vì vậy df.ix ['C', 'x'] = 10
Matthew

5
Gửi bình luận của @ Yariv. Cảnh báo: Bắt đầu từ 0.20.0, bộ chỉ mục .ix không được dùng nữa, có lợi cho các bộ chỉ mục .iloc và .loc chặt chẽ hơn. pandas.pydata.org/pandas-docs/urdy/generated/ ,. df.at trông giống như nó đang dính xung quanh.
jeffhale

Câu trả lời:


593

Câu trả lời của RukTech , df.set_value('C', 'x', 10)nhanh và xa hơn các tùy chọn tôi đã đề xuất dưới đây. Tuy nhiên, nó đã được dự kiến ​​sẽ khấu hao .

Đi về phía trước, phương pháp được đề nghị là.iat/.at .


Tại sao df.xs('C')['x']=10không hoạt động:

df.xs('C')theo mặc định, trả về một khung dữ liệu mới với một bản sao của dữ liệu, vì vậy

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

chỉ sửa đổi khung dữ liệu mới này.

df['x']trả về một khung nhìn của khung dfdữ liệu, vì vậy

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

dftự sửa đổi .

Cảnh báo : Đôi khi rất khó để dự đoán nếu một hoạt động trả về một bản sao hoặc một khung nhìn. Vì lý do này, các tài liệu khuyên bạn nên tránh các bài tập với "lập chỉ mục chuỗi" .


Vì vậy, sự thay thế được đề nghị là

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

không sửa đổi 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

Không có thứ như df.xtrong API . Bạn có ý gì?
smci

3
@smci: 'x'là tên của một cột trong df. df.xtrả về a Seriesvới các giá trị trong cột x. Tôi sẽ đổi nó thành df['x']ký hiệu này sẽ hoạt động với bất kỳ tên cột nào (không giống như ký hiệu dấu chấm) và tôi nghĩ là rõ ràng hơn.
unutbu

1
Tôi biết rằng, tôi nghĩ rằng bạn đang nói df.xlà một phương pháp mới chưa biết cùng vớidf.xs, df.ix
smci

df.xs(..., copy=True)trả về một bản sao và đó là hành vi mặc định. df.xs(..., copy=False)trả lại bản gốc.
smci

7
Theo các nhà bảo trì, đây không phải là cách được đề xuất để đặt giá trị. Xem stackoverflow.com/a/21287235/1579844 và câu trả lời của tôi.
Yariv

225

Cập nhật: .set_valuePhương pháp sẽ không được chấp nhận . .iat/.atlà sự thay thế tốt, tiếc là gấu trúc cung cấp ít tài liệu


Cách nhanh nhất để làm điều này là sử dụng set_value . Phương pháp này nhanh hơn ~ 100 lần so với .ixphương pháp. Ví dụ:

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


5
Nó thậm chí còn tốt hơn df['x']['C'] = 10 .
ALH

6
1000 vòng lặp, tốt nhất là 3: 195 Vòng trên mỗi vòng "df ['x'] ['C'] = 10" 1000 vòng, tốt nhất là 3: 310 Tiếng vang trên mỗi vòng "df.ix ['C', 'x'] = 10 "1000 vòng lặp, tốt nhất là 3: 189 Vòng trên mỗi vòng" df.xs ('C', sao chép = Sai) ['x'] = 10 "1000 vòng, tốt nhất là 3: 7.22 vòng trên mỗi vòng" df.set_value ('C', 'x', 10) "
propjk007

1
điều này cũng hoạt động để thêm một hàng / col mới vào khung dữ liệu?
st.ph.n

Đúng vậy (đối với gấu trúc 0.16.2)
RukTech

Có thể sử dụng điều này để đặt giá trị thành a df=df.append(df.sum(numeric_only=True),ignore_index=True)?
ctrl-alt-xóa

95

Bạn cũng có thể sử dụng tra cứu có điều kiện bằng cách sử dụng .locnhư đã thấy ở đây:

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

nơi <some_column_namelà cột bạn muốn kiểm tra sự <condition>biến chống lại và <another_column_name>là cột bạn muốn thêm vào (có thể là một cột mới hoặc một trong đó đã tồn tại). <value_to_add>là giá trị bạn muốn thêm vào cột / hàng đó.

Ví dụ này không hoạt động chính xác với câu hỏi trong tay, nhưng nó có thể hữu ích cho ai đó muốn thêm một giá trị cụ thể dựa trên một điều kiện.


8
cột thứ hai cần được đặt trên ngoặc, nếu không tất cả các cột sẽ được ghi đè bằng giá trị. Như thế này:df.loc[df['age']==3, ['age-group']] = 'toddler'
Piizei

Tôi không thể làm việc này khi <some_column_name> là chỉ mục của tôi (chỉ số unixtime nói) và tôi đang cố gắng thêm dấu thời gian chưa thoát ra (ví dụ: cách đọc dấu thời gian mới). Có suy nghĩ gì không?
yeliabsalohcin

Có thể thay đổi một giá trị dựa trên chỉ số và giá trị ô không?
BND

@BND Tôi không chắc, nhưng bạn có thể khắc phục được cạm bẫy rõ ràng này mà chỉ cần sao chép cột chỉ mục với một cột khác có cùng giá trị? Câu trả lời ngắn gọn là tôi không biết.
Blairg23

@yeliabsalohcin xem câu trả lời trên.
Blairg23

40

Cách được đề xuất (theo các nhà bảo trì) để đặt giá trị là:

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

Sử dụng 'lập chỉ mục chuỗi' ( df['x']['C']) có thể dẫn đến các vấn đề.

Xem:



hoạt động hoàn hảo! mặc dù đôi khi nó sẽ bị phản đối
Pavlos Ponos

35

Hãy thử sử dụng df.loc[row_index,col_indexer] = value


6
Chào mừng bạn đến với Stack Overflow! Vui lòng xem xét chỉnh sửa bài đăng của bạn để thêm giải thích về những gì mã của bạn làm và lý do tại sao nó sẽ giải quyết vấn đề. Một câu trả lời chủ yếu chỉ chứa mã (ngay cả khi nó hoạt động) thường không giúp OP hiểu vấn đề của họ. Bạn cũng không nên đăng câu trả lời nếu đó chỉ là phỏng đoán. Một câu trả lời tốt sẽ có lý do chính đáng cho lý do tại sao nó có thể giải quyết vấn đề của OP.
SuperBiasedMan

22

Đây là điều duy nhất làm việc cho tôi!

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

Tìm hiểu thêm về .loc đây .


đã .locthay thế .iat/.at?
Hội chợ Gabriel

1
atTương tự như vậy loc, trong đó cả hai đều cung cấp tra cứu dựa trên nhãn. Sử dụng atnếu bạn chỉ cần lấy hoặc đặt một giá trị trong DataFrame hoặc Sê-ri. Từ padas doc
Rutrus

Rất vui vì điều này làm việc cho tôi khi các yếu tố chỉ số của tôi là số.
Christopher John

Điều này không làm việc cho một hỗn hợp các chỉ số số và chuỗi.
Seanny123

12

.iat/.atlà giải pháp tốt. Giả sử bạn có data_frame đơn giản này:

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

Nếu chúng ta muốn sửa đổi giá trị của ô [0,"A"]u, bạn có thể sử dụng một trong những giải pháp đó:

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

Và đây là một ví dụ đầy đủ về cách sử dụng iatđể lấy và đặt giá trị của ô:

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

y_train trước:

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

y_train sau khi gọi hàm preossessing iatsẽ thay đổi để nhân giá trị của mỗi ô với 2:

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

8

Để đặt giá trị, sử dụng:

df.at[0, 'clm1'] = 0
  • Phương pháp được đề xuất nhanh nhất để thiết lập các biến.
  • set_value, ix đã bị phản đối
  • Không cảnh báo, không giống ilocloc

1
Tôi đã đi đến kết luận chính xác như vậy .
prosti

6

bạn có thể sử dụng .iloc.

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

Phương thức này dường như không hỗ trợ một số giá trị, ví dụ df.iloc[[2:8], [0]] = [2,3,4,5,6,7]phương thức df.loc()nào thực sự hữu ích.
strpeter

1
hoạt động hoàn hảo, không có cảnh báo khấu hao!
Pavlos Ponos

6

Trong ví dụ của tôi, tôi chỉ thay đổi nó trong ô đã chọn

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

'kết quả' là một DataField với cột 'weight'


4

set_value() bị phản đối

Bắt đầu từ phiên bản 0.23.4, Pandas " thông báo tương lai " ...

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

Xem xét lời khuyên này, đây là một minh họa về cách sử dụng chúng:

  • theo vị trí số nguyên hàng / cột

>>> 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
  • theo nhãn hàng / cột

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

Người giới thiệu:


3

Dưới đây là tóm tắt về các giải pháp hợp lệ được cung cấp bởi tất cả người dùng, cho các khung dữ liệu được lập chỉ mục theo số nguyên và chuỗi.

df.iloc, df.loc và df.at hoạt động cho cả hai loại khung dữ liệu, df.iloc chỉ hoạt động với các chỉ số nguyên hàng / cột, df.loc và df.at hỗ trợ cài đặt giá trị bằng tên cột và / hoặc chỉ số nguyên .

Khi chỉ mục được chỉ định không tồn tại, cả df.loc và df.at sẽ nối các hàng / cột mới được chèn vào khung dữ liệu hiện có, nhưng df.iloc sẽ đưa ra "IndexError: bộ chỉ mục vị trí nằm ngoài giới hạn". Một ví dụ hoạt động được thử nghiệm trong Python 2.7 và 3.7 như sau:

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

Tôi đã thử nghiệm và đầu ra df.set_valuenhanh hơn một chút, nhưng phương pháp chính thức có df.atvẻ như là cách không nhanh nhất để làm điều đó.

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)

Lưu ý điều này là thiết lập giá trị cho một ô. Đối với các vectơ locilocnên là lựa chọn tốt hơn vì chúng được vector hóa.


3

Một cách để sử dụng chỉ mục với điều kiện trước tiên là lấy chỉ mục của tất cả các hàng thỏa mãn điều kiện của bạn và sau đó chỉ cần sử dụng các chỉ mục hàng đó theo nhiều cách

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

Điều kiện ví dụ giống như

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

Sau đó, bạn có thể sử dụng các chỉ mục hàng này theo nhiều cách như

  1. Thay thế giá trị của một cột cho cond condition_index
df.loc[conditional_index , [col name]]= <new value>
  1. Thay thế giá trị của nhiều cột cho cond condition_index
df.loc[conditional_index, [col1,col2]]= <new value>
  1. Một lợi ích khi lưu điều kiện_index là bạn có thể gán giá trị của một cột cho một cột khác có cùng chỉ mục hàng
df.loc[conditional_index, [col1,col2]]= df.loc[conditional_index,'col name']

Điều này hoàn toàn có thể bởi vì .index trả về một mảng chỉ mục mà .loc có thể sử dụng với địa chỉ trực tiếp để tránh giao dịch lặp đi lặp lại.


Thay đổi hàng thì sao?
FabioSpaghetti

chỉ cần sử dụng, df.loc [cond điều_index,] = <giá trị mới> Nó sẽ thay thế giá trị mới trong tất cả các cột của hàng thỏa mãn điều kiện
Atta Jutt

2

df.loc['c','x']=10 Điều này sẽ thay đổi giá trị của hàng thứ c và cột x .


1

Ngoài các câu trả lời ở trên, đây là một điểm chuẩn so sánh các cách khác nhau để thêm các hàng dữ liệu vào một khung dữ liệu đã có sẵn. Nó cho thấy rằng sử dụng at hoặc set-value là cách hiệu quả nhất cho các datafram lớn (ít nhất là cho các điều kiện thử nghiệm này).

  • Tạo khung dữ liệu mới cho mỗi hàng và ...
    • ... nối nó (13.0 giây)
    • ... nối nó (13.1 s)
  • Trước tiên, lưu trữ tất cả các hàng mới trong một container khác, chuyển đổi sang khung dữ liệu mới một lần và nối thêm ...
    • container = danh sách danh sách (2.0 s)
    • container = từ điển danh sách (1.9 s)
  • Phân bổ toàn bộ khung dữ liệu, lặp lại trên các hàng mới và tất cả các cột và điền vào bằng cách sử dụng
    • ... tại (0,6 giây)
    • ... set_value (0,4 giây)

Đối với thử nghiệm, một khung dữ liệu hiện có bao gồm 100.000 hàng và 1.000 cột và các giá trị numpy ngẫu nhiên đã được sử dụng. Đối với khung dữ liệu này, 100 hàng mới đã được thêm vào.

Mã xem bên dưới:

#!/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

Nếu bạn muốn thay đổi giá trị không phải cho toàn bộ hàng, mà chỉ cho một số cột:

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

0

Từ phiên bản 0.21.1 bạn cũng có thể sử dụng .atphương thức. Có một số khác biệt so với .locnhư đã đề cập ở đây - gấu trúc .at so với .loc , nhưng nó nhanh hơn khi thay thế giá trị đơn


0

Soo, câu hỏi của bạn để chuyển đổi NaN tại ['x', C] thành giá trị 10

câu trả lời là..

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

mã thay thế là

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

-4

Tôi cũng đang tìm kiếm chủ đề này và tôi đưa ra một cách để lặp lại thông qua DataFrame và cập nhật nó với các giá trị tra cứu từ DataFrame thứ hai. Đây là mã của tôi.

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'])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.