Pandas tạo điều kiện tạo một cột loạt / cột dữ liệu


314

Tôi có một khung dữ liệu dọc theo các dòng dưới đây:

    Type       Set
1    A          Z
2    B          Z           
3    B          X
4    C          Y

Tôi muốn thêm một cột khác vào khung dữ liệu (hoặc tạo một chuỗi) có cùng độ dài với khung dữ liệu (= số lượng bản ghi / hàng bằng nhau) sẽ đặt màu xanh lục nếu Set = 'Z' và 'red' nếu Set = nếu không .

Cách tốt nhất để làm điều này là gì?

Câu trả lời:


712

Nếu bạn chỉ có hai lựa chọn để chọn từ:

df['color'] = np.where(df['Set']=='Z', 'green', 'red')

Ví dụ,

import pandas as pd
import numpy as np

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
df['color'] = np.where(df['Set']=='Z', 'green', 'red')
print(df)

sản lượng

  Set Type  color
0   Z    A  green
1   Z    B  green
2   X    B    red
3   Y    C    red

Nếu bạn có nhiều hơn hai điều kiện thì sử dụngnp.select . Ví dụ, nếu bạn muốn colortrở thành

  • yellow khi nào (df['Set'] == 'Z') & (df['Type'] == 'A')
  • mặt khác bluekhi(df['Set'] == 'Z') & (df['Type'] == 'B')
  • mặt khác purplekhi(df['Type'] == 'B')
  • cách khác black,

sau đó sử dụng

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
conditions = [
    (df['Set'] == 'Z') & (df['Type'] == 'A'),
    (df['Set'] == 'Z') & (df['Type'] == 'B'),
    (df['Type'] == 'B')]
choices = ['yellow', 'blue', 'purple']
df['color'] = np.select(conditions, choices, default='black')
print(df)

mang lại

  Set Type   color
0   Z    A  yellow
1   Z    B    blue
2   X    B  purple
3   Y    C   black

1
không hoạt động nếu tôi đặt hai điều kiện bên trong mệnh đề với và
Amol Sharma

2
df ['color'] = list (np.where (df ['Set'] == 'Z', 'green', 'red')) sẽ chặn cảnh báo gấu trúc: Một giá trị đang cố gắng được đặt trên một bản sao của một lát cắt từ DataFrame. Hãy thử sử dụng .loc [row_indexer, col_indexer] = value thay vào đó
denson

3
'xanh' và 'đỏ' cũng có thể được thay thế bằng số học cột. ví dụ ,df['foo'] = np.where(df['Set']=='Z', df['Set'], df['Type'].shift(1))
Alejandro

np.where tạo một cột mới? Tôi đã sử dụng mã này và khi tôi thực hiện df.color.head () tôi nhận được: đối tượng 'numpy.ndarray' không có thuộc tính 'đầu'
vvv

3
Thật xấu hổ tôi không thể nâng cao điều này nhiều lần. Một upvote dường như không đủ.
Harper

120

Danh sách hiểu là một cách khác để tạo một cột khác có điều kiện. Nếu bạn đang làm việc với các ký tự đối tượng trong các cột, như trong ví dụ của bạn, việc hiểu danh sách thường vượt trội hơn hầu hết các phương thức khác.

Danh sách ví dụ hiểu:

df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]

kiểm tra% thời gian:

import pandas as pd
import numpy as np

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
%timeit df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]
%timeit df['color'] = np.where(df['Set']=='Z', 'green', 'red')
%timeit df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')

1000 loops, best of 3: 239 µs per loop
1000 loops, best of 3: 523 µs per loop
1000 loops, best of 3: 263 µs per loop

4
Lưu ý rằng, với dataframes lớn hơn nhiều (nghĩ pd.DataFrame({'Type':list('ABBC')*100000, 'Set':list('ZZXY')*100000})-Kích thước), numpy.wherevượt trội hơn map, nhưng hiểu danh sách là vua (khoảng 50% nhanh hơn numpy.where).
đen

3
Phương pháp hiểu danh sách có thể được sử dụng nếu điều kiện cần thông tin từ nhiều cột? Tôi đang tìm kiếm một cái gì đó như thế này (điều này không hoạt động):df['color'] = ['red' if (x['Set'] == 'Z') & (x['Type'] == 'B') else 'green' for x in df]
Mappi

2
Thêm iterrow vào khung dữ liệu, sau đó bạn có thể truy cập nhiều cột qua hàng: ['red' if (hàng ['Set'] == 'Z') & (hàng ['Type'] == 'B') khác 'xanh 'cho chỉ mục, hàng trong df.iterrows ()]
cheekybastard

1
Lưu ý giải pháp tốt đẹp này sẽ không hoạt động nếu bạn cần lấy các giá trị thay thế từ một chuỗi khác trong khung dữ liệu, chẳng hạn nhưdf['color_type'] = np.where(df['Set']=='Z', 'green', df['Type'])
Paul Rougieux

@cheekybastard Hoặc không, vì .iterrows()nổi tiếng là chậm chạp và DataFrame không nên được sửa đổi trong khi lặp.
AMC

21

Một cách khác để đạt được điều này là

df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')

Cách tiếp cận tốt, điều này có thể được ghi nhớ để có hiệu quả nhanh hơn (trong các bộ dữ liệu lớn hơn), mặc dù sẽ cần một bước bổ sung.
Yaakov Bressler

21

Đây là một cách khác để lột da con mèo này, sử dụng từ điển để ánh xạ các giá trị mới vào các phím trong danh sách:

def map_values(row, values_dict):
    return values_dict[row]

values_dict = {'A': 1, 'B': 2, 'C': 3, 'D': 4}

df = pd.DataFrame({'INDICATOR': ['A', 'B', 'C', 'D'], 'VALUE': [10, 9, 8, 7]})

df['NEW_VALUE'] = df['INDICATOR'].apply(map_values, args = (values_dict,))

Nó trông như thế nào:

df
Out[2]: 
  INDICATOR  VALUE  NEW_VALUE
0         A     10          1
1         B      9          2
2         C      8          3
3         D      7          4

Cách tiếp cận này có thể rất mạnh mẽ khi bạn có nhiều ifelsecâu lệnh -type để thực hiện (nghĩa là nhiều giá trị duy nhất cần thay thế).

Và tất nhiên bạn luôn có thể làm điều này:

df['NEW_VALUE'] = df['INDICATOR'].map(values_dict)

Nhưng cách tiếp cận đó chậm hơn gấp ba lần so với applycách tiếp cận từ trên cao, trên máy của tôi.

Và bạn cũng có thể làm điều này, bằng cách sử dụng dict.get:

df['NEW_VALUE'] = [values_dict.get(v, None) for v in df['INDICATOR']]

Tôi thích câu trả lời này vì nó cho thấy cách thực hiện nhiều lần thay thế các giá trị
Monica Heddneck

Nhưng cách tiếp cận đó chậm hơn ba lần so với cách tiếp cận áp dụng từ phía trên, trên máy của tôi. Làm thế nào bạn điểm chuẩn những? Từ các phép đo nhanh của tôi, .map()giải pháp nhanh hơn ~ 10 lần .apply().
AMC

Cập nhật: Trên 100.000.000 hàng, 52 giá trị chuỗi, .apply()mất 47 giây, so với chỉ 5,91 giây .map().
AMC

19

Cách sau chậm hơn các cách tiếp cận được tính thời gian ở đây , nhưng chúng ta có thể tính toán cột phụ dựa trên nội dung của nhiều cột và hơn hai giá trị có thể được tính cho cột phụ.

Ví dụ đơn giản chỉ sử dụng cột "Đặt":

def set_color(row):
    if row["Set"] == "Z":
        return "red"
    else:
        return "green"

df = df.assign(color=df.apply(set_color, axis=1))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C  green

Ví dụ với nhiều màu sắc hơn và nhiều cột được tính đến:

def set_color(row):
    if row["Set"] == "Z":
        return "red"
    elif row["Type"] == "C":
        return "blue"
    else:
        return "green"

df = df.assign(color=df.apply(set_color, axis=1))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C   blue

Chỉnh sửa (21/06/2019): Sử dụng plydata

Cũng có thể sử dụng plydata để làm những việc này (điều này dường như còn chậm hơn so với việc sử dụng assignapply, mặc dù).

from plydata import define, if_else

Đơn giản if_else:

df = define(df, color=if_else('Set=="Z"', '"red"', '"green"'))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C  green

Lồng nhau if_else:

df = define(df, color=if_else(
    'Set=="Z"',
    '"red"',
    if_else('Type=="C"', '"green"', '"blue"')))

print(df)                            
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B   blue
3   Y    C  green

10

Có thể điều này đã có thể với các bản cập nhật mới hơn của Pandas, nhưng tôi nghĩ rằng sau đây là câu trả lời ngắn nhất và có thể là tốt nhất cho câu hỏi, cho đến nay. Bạn có thể sử dụng .locphương pháp và sử dụng một điều kiện hoặc một số tùy thuộc vào nhu cầu của bạn.

Tóm tắt mã:

df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))
df['Color'] = "red"
df.loc[(df['Set']=="Z"), 'Color'] = "green"

#practice!
df.loc[(df['Set']=="Z")&(df['Type']=="B")|(df['Type']=="C"), 'Color'] = "purple"

Giải trình:

df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))

# df so far: 
  Type Set  
0    A   Z 
1    B   Z 
2    B   X 
3    C   Y

thêm một cột 'màu' và đặt tất cả các giá trị thành "đỏ"

df['Color'] = "red"

Áp dụng điều kiện duy nhất của bạn:

df.loc[(df['Set']=="Z"), 'Color'] = "green"


# df: 
  Type Set  Color
0    A   Z  green
1    B   Z  green
2    B   X    red
3    C   Y    red

hoặc nhiều điều kiện nếu bạn muốn:

df.loc[(df['Set']=="Z")&(df['Type']=="B")|(df['Type']=="C"), 'Color'] = "purple"

Bạn có thể đọc về toán tử logic Pandas và lựa chọn có điều kiện tại đây: Toán tử logic để lập chỉ mục boolean trong Pandas


2
Tốt nhất cho đến nay. Bạn có thể có thể thêm các điều kiện khác sẽ là mãdf.loc[(df['Set']=="Z") & (df['Type']=="A"), 'Color'] = "green"
Salvador Vigo

2
Đây phải là câu trả lời được chấp nhận. Thực tế thành ngữ và mở rộng.
AMC

1

Một lớp lót với .apply()phương pháp như sau:

df['color'] = df['Set'].apply(lambda set_: 'green' if set_=='Z' else 'red')

Sau đó, dfkhung dữ liệu trông như thế này:

>>> print(df)
  Type Set  color
0    A   Z  green
1    B   Z  green
2    B   X    red
3    C   Y    red

0

Nếu bạn đang làm việc với dữ liệu lớn, cách tiếp cận được ghi nhớ sẽ là tốt nhất:

# First create a dictionary of manually stored values
color_dict = {'Z':'red'}

# Second, build a dictionary of "other" values
color_dict_other = {x:'green' for x in df['Set'].unique() if x not in color_dict.keys()}

# Next, merge the two
color_dict.update(color_dict_other)

# Finally, map it to your column
df['color'] = df['Set'].map(color_dict)

Cách tiếp cận này sẽ nhanh nhất khi bạn có nhiều giá trị lặp lại. Nguyên tắc chung của tôi là ghi nhớ khi: data_size> 10**4& n_distinct<data_size/4

Ex Ghi nhớ trong trường hợp 10.000 hàng với 2.500 hoặc ít hơn các giá trị khác biệt.


Được rồi, do đó, chỉ với 2 giá trị riêng biệt trên bản đồ, 100.000.000 hàng, phải mất 6,67 giây để chạy mà không cần "ghi nhớ" và 9,86 giây với.
AMC

100.000.000 hàng, 52 giá trị riêng biệt, trong đó 1 trong số các ánh xạ tới giá trị đầu ra đầu tiên và 51 giá trị khác tương ứng với các giá trị khác: 7,99 giây không ghi nhớ, 11,1 giây với.
AMC

Là giá trị của bạn theo thứ tự ngẫu nhiên? Hay là họ quay trở lại? Tốc độ cao của gấu trúc có thể là do bộ nhớ đệm @AMC
Yaakov Bressler

1
Là giá trị của bạn theo thứ tự ngẫu nhiên? Hay là họ quay trở lại? Các giá trị là ngẫu nhiên, được lựa chọn bằng cách sử dụng random.choices().
AMC
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.