Panda 데이터 프레임의 두 열에 함수를 적용하는 방법
, 내가 ★★★★★★★★★★★★★★★★★★★★★.df
이 .'ID', 'col_1', 'col_2'
저는를 정의합니다. : 리고그그그그그 . . . . . . . . . . 。
f = lambda x, y : my_function_expression
.
'우리'를 하겠습니다.f
로로 합니다.df
<2'col_1', 'col_2'
'col_3'
, 약간 다음과 같습니다.
df['col_3'] = df[['col_1','col_2']].apply(f)
# Pandas gives : TypeError: ('<lambda>() takes exactly 2 arguments (1 given)'
어떻게 해야 하나요?
**아래와 같이 상세 샘플 추가***
import pandas as pd
df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']
def get_sublist(sta,end):
return mylist[sta:end+1]
#df['col_3'] = df[['col_1','col_2']].apply(get_sublist,axis=1)
# expect above to output df as below
ID col_1 col_2 col_3
0 1 0 1 ['a', 'b']
1 2 2 4 ['c', 'd', 'e']
2 3 3 5 ['d', 'e', 'f']
판다에게는 깔끔하고 한 줄짜리 방법이 있습니다.
df['col_3'] = df.apply(lambda x: f(x.col_1, x.col_2), axis=1)
에 의해, 「」가 가능하게 됩니다.f
여러 입력 값을 가진 사용자 정의 함수이며, 열에 액세스하기 위해 (수치) 숫자 인덱스가 아닌 (안전한) 열 이름을 사용합니다.
데이터 사용 예(원래 질문 기준):
import pandas as pd
df = pd.DataFrame({'ID':['1', '2', '3'], 'col_1': [0, 2, 3], 'col_2':[1, 4, 5]})
mylist = ['a', 'b', 'c', 'd', 'e', 'f']
def get_sublist(sta,end):
return mylist[sta:end+1]
df['col_3'] = df.apply(lambda x: get_sublist(x.col_1, x.col_2), axis=1)
의 print(df)
:
ID col_1 col_2 col_3
0 1 0 1 [a, b]
1 2 2 4 [c, d, e]
2 3 3 5 [d, e, f]
열 이름에 공백이 포함되거나 기존 데이터 프레임 속성과 이름을 공유하는 경우 대괄호로 인덱싱할 수 있습니다.
df['col_3'] = df.apply(lambda x: f(x['col 1'], x['col 2']), axis=1)
하다, 하다, 하다를 사용한 가 있습니다.apply
에 접속할 수 .axis = 1
하려고 하는 것이 2개의 값을 전달하려고 합니다.f
기능을 다시 작성하여 판다 시리즈 개체를 받아들인 다음 시리즈를 인덱싱하여 필요한 값을 얻습니다.
In [49]: df
Out[49]:
0 1
0 1.000000 0.000000
1 -0.494375 0.570994
2 1.000000 0.000000
3 1.876360 -0.229738
4 1.000000 0.000000
In [50]: def f(x):
....: return x[0] + x[1]
....:
In [51]: df.apply(f, axis=1) #passes a Series object, row-wise
Out[51]:
0 1.000000
1 0.076619
2 1.000000
3 1.646622
4 1.000000
팬더를 것이 이 될 수 .group
object를 하고 나서, 를 사용합니다.apply
그룹 내에요.
간단한 해결책은 다음과 같습니다.
df['col_3'] = df[['col_1','col_2']].apply(lambda x: f(*x), axis=1)
흥미로운 질문입니다! 제 답변은 다음과 같습니다.
import pandas as pd
def sublst(row):
return lst[row['J1']:row['J2']]
df = pd.DataFrame({'ID':['1','2','3'], 'J1': [0,2,3], 'J2':[1,4,5]})
print df
lst = ['a','b','c','d','e','f']
df['J3'] = df.apply(sublst,axis=1)
print df
출력:
ID J1 J2
0 1 0 1
1 2 2 4
2 3 3 5
ID J1 J2 J3
0 1 0 1 [a]
1 2 2 4 [c, d]
2 3 3 5 [d, e]
열 이름을 ID, J1, J2, J3으로 변경하여 ID < J1 < J2 < J3가 올바르게 표시되도록 했습니다.
또 하나의 간단한 버전:
import pandas as pd
df = pd.DataFrame({'ID':['1','2','3'], 'J1': [0,2,3], 'J2':[1,4,5]})
print df
lst = ['a','b','c','d','e','f']
df['J3'] = df.apply(lambda row:lst[row['J1']:row['J2']],axis=1)
print df
찾으시는 방법은 Series.combine 입니다.다만, 데이터 타입에 대해서는 어느 정도 주의가 필요한 것 같습니다.이 예에서는 (답변 테스트 시처럼) 순진하게 콜을 합니다.
df['col_3'] = df.col_1.combine(df.col_2, func=get_sublist)
단, 이로 인해 다음 오류가 발생합니다.
ValueError: setting an array element with a sequence.
내 추측으로는 메서드를 호출하는 시리즈(여기서는 df.col_1)와 같은 타입의 결과가 될 것으로 생각됩니다.다만, 다음의 조작이 가능합니다.
df['col_3'] = df.col_1.astype(object).combine(df.col_2, func=get_sublist)
df
ID col_1 col_2 col_3
0 1 0 1 [a, b]
1 2 2 4 [c, d, e]
2 3 3 5 [d, e, f]
에서 목록 apply
「시리즈」 「Data Frame」 「Data Frame」 「Data Frame」 「Data Frame」 。그리고 경우에 따라 예외가 발생할 수 있습니다.이치노
df = pd.DataFrame(data=np.random.randint(0, 5, (5,3)),
columns=['a', 'b', 'c'])
df
a b c
0 4 0 0
1 2 0 1
2 2 2 2
3 1 2 2
4 3 0 0
세 가지 가 있을 수 있습니다.apply
1) 반환된 목록의 길이가 열 수와 같지 않으면 일련의 목록이 반환됩니다.
df.apply(lambda x: list(range(2)), axis=1) # returns a Series
0 [0, 1]
1 [0, 1]
2 [0, 1]
3 [0, 1]
4 [0, 1]
dtype: object
2) 반환된 목록의 길이가 열 수와 같으면 Data Frame이 반환되고 각 열은 목록 내의 해당 값을 가져옵니다.
df.apply(lambda x: list(range(3)), axis=1) # returns a DataFrame
a b c
0 0 1 2
1 0 1 2
2 0 1 2
3 0 1 2
4 0 1 2
3) 반환되는 목록의 길이가 첫 번째 행의 열 수와 동일하지만 목록에 요소의 수가 열 수와 다른 행이 하나 이상 있는 경우 ValueError가 발생합니다.
i = 0
def f(x):
global i
if i == 0:
i += 1
return list(range(3))
return list(range(4))
df.apply(f, axis=1)
ValueError: Shape of passed values is (5, 4), indices imply (5, 3)
해당되지 않는 문제에 대한 답변
「」를 사용합니다.apply
Axis=1을 사용하다.기본적인 반복 방법을 사용하면 (특히 대규모 데이터셋에서) 훨씬 더 나은 성능을 얻을 수 있습니다.
더 큰 데이터 프레임 생성
df1 = df.sample(100000, replace=True).reset_index(drop=True)
타이밍
# apply is slow with axis=1
%timeit df1.apply(lambda x: mylist[x['col_1']: x['col_2']+1], axis=1)
2.59 s ± 76.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# zip - similar to @Thomas
%timeit [mylist[v1:v2+1] for v1, v2 in zip(df1.col_1, df1.col_2)]
29.5 ms ± 534 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
@토마스의 대답
%timeit list(map(get_sublist, df1['col_1'],df1['col_2']))
34 ms ± 459 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
np.vectorize에 투표하겠습니다.이 기능을 사용하면 함수에서 데이터 프레임을 처리하지 않고 x개의 열만 쏠 수 있으므로 사용자가 제어하지 않거나 함수에 2개의 열과 상수를 보내는 등의 작업을 수행하는 데 적합합니다(예: col_1, col_2, foo).
import numpy as np
import pandas as pd
df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']
def get_sublist(sta,end):
return mylist[sta:end+1]
#df['col_3'] = df[['col_1','col_2']].apply(get_sublist,axis=1)
# expect above to output df as below
df.loc[:,'col_3'] = np.vectorize(get_sublist, otypes=["O"]) (df['col_1'], df['col_2'])
df
ID col_1 col_2 col_3
0 1 0 1 [a, b]
1 2 2 4 [c, d, e]
2 3 3 5 [d, e, f]
Panda나 Numpy 연산을 사용하는 솔루션만큼 빠르지는 않지만, 기능을 다시 쓰고 싶지 않다면 지도를 사용해도 됩니다.원래 예제 데이터 사용 -
import pandas as pd
df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']
def get_sublist(sta,end):
return mylist[sta:end+1]
df['col_3'] = list(map(get_sublist,df['col_1'],df['col_2']))
#In Python 2 don't convert above to list
이렇게 하면 원하는 만큼 많은 인수를 함수에 넣을 수 있습니다.결과는 우리가 원했던 것이다.
ID col_1 col_2 col_3
0 1 0 1 [a, b]
1 2 2 4 [c, d, e]
2 3 3 5 [d, e, f]
f를 쓰는 방법에는 두 가지 입력이 필요합니다.오류 메시지를 보면 f에 2개의 입력이 아닌 1개의 입력만 제공한다고 표시됩니다.에러 메세지가 올바르게 표시된다.
이 불일치는 df[['col1'',col2']가 두 개의 열이 아닌 두 개의 열이 포함된 단일 데이터 프레임을 반환하기 때문입니다.
f는 단일 입력을 받도록 변경하고 위의 데이터 프레임을 입력으로 유지한 다음 함수 본문 내에서 x, y로 분할해야 합니다.그런 다음 필요한 모든 작업을 수행하고 단일 값을 반환합니다.
구문이 .databrame(f)이기 때문에 이 함수 서명이 필요합니다. 따라서 f는 현재 f가 기대하는 두 가지가 아니라 단일 = 데이터 프레임을 취해야 합니다.
f의 본문을 제공하지 않았기 때문에 더 이상 자세히 설명할 수 없습니다.그러나 코드를 근본적으로 변경하거나 적용하는 대신 다른 방법을 사용하지 않아도 됩니다.
다음은 보다 빠른 솔루션입니다.
def func_1(a,b):
return a + b
df["C"] = func_1(df["A"].to_numpy(),df["B"].to_numpy())
속도입니다.df.apply(f, axis=1)
@@Aman에서 @Aman에서 @Aman보다 .df['col_3'] = df.apply(lambda x: f(x.col_1, x.col_2), axis=1)
from @ajrwhite.
벤치마크도 몇 가지 추가했습니다.
결과:
FUNCTIONS TIMINGS GAIN
apply lambda 0.7 x 1
apply 0.56 x 1.25
map 0.3 x 2.3
np.vectorize 0.01 x 70
f3 on Series 0.0026 x 270
f3 on np arrays 0.0018 x 380
f3 numba 0.0018 x 380
요컨대:
apply 사용 속도가 느리다.Panda Series(또는 Numpy 어레이)에서 직접 작동하는 기능을 사용하는 것만으로 매우 간단하게 작업을 가속화할 수 있습니다.또, Panda 시리즈 또는 Numpy 어레이로 운용하기 때문에, 운용을 벡터화할 수 있습니다.이 함수는 새로운 컬럼으로 할당될 판다 시리즈 또는 numpy 배열을 반환합니다.
벤치마크 코드는 다음과 같습니다.
import timeit
timeit_setup = """
import pandas as pd
import numpy as np
import numba
np.random.seed(0)
# Create a DataFrame of 10000 rows with 2 columns "A" and "B"
# containing integers between 0 and 100
df = pd.DataFrame(np.random.randint(0,10,size=(10000, 2)), columns=["A", "B"])
def f1(a,b):
# Here a and b are the values of column A and B for a specific row: integers
return a + b
def f2(x):
# Here, x is pandas Series, and corresponds to a specific row of the DataFrame
# 0 and 1 are the indexes of columns A and B
return x[0] + x[1]
def f3(a,b):
# Same as f1 but we will pass parameters that will allow vectorization
# Here, A and B will be Pandas Series or numpy arrays
# with df["C"] = f3(df["A"],df["B"]): Pandas Series
# with df["C"] = f3(df["A"].to_numpy(),df["B"].to_numpy()): numpy arrays
return a + b
@numba.njit('int64[:](int64[:], int64[:])')
def f3_numba_vectorize(a,b):
# Here a and b are 2 numpy arrays with dtype int64
# This function must return a numpy array whith dtype int64
return a + b
"""
test_functions = [
'df["C"] = df.apply(lambda row: f1(row["A"], row["B"]), axis=1)',
'df["C"] = df.apply(f2, axis=1)',
'df["C"] = list(map(f3,df["A"],df["B"]))',
'df["C"] = np.vectorize(f3) (df["A"].to_numpy(),df["B"].to_numpy())',
'df["C"] = f3(df["A"],df["B"])',
'df["C"] = f3(df["A"].to_numpy(),df["B"].to_numpy())',
'df["C"] = f3_numba_vectorize(df["A"].to_numpy(),df["B"].to_numpy())'
]
for test_function in test_functions:
print(min(timeit.repeat(setup=timeit_setup, stmt=test_function, repeat=7, number=10)))
출력:
0.7
0.56
0.3
0.01
0.0026
0.0018
0.0018
마지막 메모: Cython과 다른 numba 트릭으로 모든 것을 최적화할 수 있습니다.
다른 옵션은 다음과 같습니다(일반적으로 더 빠르고 문서 및 사용자 테스트에 의해 권장됩니다).
import pandas as pd
df = pd.DataFrame([range(4) for _ in range(4)], columns=list("abcd"))
df
a b c d
0 0 1 2 3
1 0 1 2 3
2 0 1 2 3
3 0 1 2 3
df["e"] = [sum(row) for row in df[["b", "d"]].itertuples(index=False)]
df
a b c d e
0 0 1 2 3 4
1 0 1 2 3 4
2 0 1 2 3 4
3 0 1 2 3 4
부터itertuples
반환하다Iterable
의 태플 요소에는 컬럼 이름(일명 도트 표기)과 인덱스로 모두 Atribute로서 액세스 할 수 있습니다.
b, d = row
b = row.b
d = row[1]
질문의 예:
def get_sublist(row, col1, col2):
return mylist[row[col1]:row[col2]+1]
df.apply(get_sublist, axis=1, col1='col_1', col2='col_2')
당신은 변하기 싫을 것 같군요.get_sublist
DataFrame의 기능을 사용하고 싶을 뿐입니다.apply
그 일을 하는 방법.원하는 결과를 얻기 위해 두 가지 도움말 기능을 작성했습니다.get_sublist_list
그리고.unlist
함수 이름에서 알 수 있듯이 먼저 서브리스트 목록을 가져오고 다음으로 해당 서브리스트를 해당 목록에서 추출합니다.마지막으로, 우리는 전화해야 한다.apply
이 두 가지 기능을 에 적용하는 기능df[['col_1','col_2']]
그 후 데이터 프레임.
import pandas as pd
df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']
def get_sublist(sta,end):
return mylist[sta:end+1]
def get_sublist_list(cols):
return [get_sublist(cols[0],cols[1])]
def unlist(list_of_lists):
return list_of_lists[0]
df['col_3'] = df[['col_1','col_2']].apply(get_sublist_list,axis=1).apply(unlist)
df
사용하지 않으면[]
을 the the the the the get_sublist
그 에 ,,, 음음음get_sublist_list
리스트를 이 함수는 플레인 리스트를.ValueError: could not broadcast input array from shape (3) into shape (2)
@ Ted Petrou ★★★★★★★★★★★★★★★★★」
대량의 데이터 세트를 가지고 있는 경우는, 스위프터를 사용해 간단하지만 고속(실행 시간)의 방법을 사용할 수 있습니다.
import pandas as pd
import swifter
def fnc(m,x,c):
return m*x+c
df = pd.DataFrame({"m": [1,2,3,4,5,6], "c": [1,1,1,1,1,1], "x":[5,3,6,2,6,1]})
df["y"] = df.swifter.apply(lambda x: fnc(x.m, x.x, x.c), axis=1)
다음의 2개의 간단한 방법으로 실행할 수 있습니다.를 들어,, 라고 합시다.col1
★★★★★★★★★★★★★★★★★」col2
에 "" " " " " " "col_sum
- 방법 1
f = lambda x : x.col1 + x.col2
df['col_sum'] = df.apply(f, axis=1)
- 방법 2
def f(x):
x['col_sum'] = x.col_1 + col_2
return x
df = df.apply(f, axis=1)
방법 2는 어떤 복잡한 함수를 데이터 프레임에 적용해야 할 때 사용해야 한다.방법 2는 여러 열의 출력이 필요한 경우에도 사용할 수 있습니다.
언급URL : https://stackoverflow.com/questions/13331698/how-to-apply-a-function-to-two-columns-of-pandas-dataframe
'source' 카테고리의 다른 글
날짜와 함께 GROUP_CONCAT에서 NOT IN 연산자(<>)를 사용하는 방법 (0) | 2022.11.15 |
---|---|
EntityManager.find()와 EntityManager.getReference()를 JPA와 함께 사용하는 경우 (0) | 2022.11.15 |
한 줄 if 또는 루프에 중괄호(예: {})를 사용하는 목적은 무엇입니까? (0) | 2022.11.15 |
Vue 3 앱에서 계산된 속성이 반응하지 않는 이유는 무엇입니까? (0) | 2022.11.15 |
html 텍스트 상자에서 키보드 캐럿 위치 설정 (0) | 2022.11.15 |