Pandas에서 공식의 식을 동적으로 평가
를 사용하여 열에 대한 .pd.eval
구체적으로 수식을 평가하는 다음 코드를 포팅하고 싶습니다.
x = 5
df2['D'] = df1['A'] + (df1['B'] * x)
을 .코드를 사용pd.eval
.pd.eval
많은 워크플로우를 자동화하고 싶으므로 동적으로 워크플로우를 생성하는 것이 저에게 유용합니다.
두 개의 입력 데이터 프레임은 다음과 같습니다.
import pandas as pd
import numpy as np
np.random.seed(0)
df1 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
df2 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
df1
A B C D
0 5 0 3 3
1 7 9 3 5
2 2 4 7 6
3 8 8 1 6
4 7 7 8 1
df2
A B C D
0 5 9 8 9
1 4 3 0 3
2 5 0 2 3
3 8 1 3 3
4 3 7 0 1
는 를 더 잘 .pd.eval
의engine
그리고.parser
내 문제를 가장 잘 해결할 수 있는 방법을 결정하기 위한 논쟁.저는 서류를 검토해 보았지만, 차이점이 명확하게 밝혀지지 않았습니다.
- 코드가 최대 성능으로 작동하는지 확인하려면 어떤 인수를 사용해야 합니까?
- 에 할 수 이 있습니까?
df2
? - 을 더 , 를
x
문자열 표현 안에 있는 논쟁으로?
1), 2) 또는 3)을 사용할 수 있습니다.그들의 다양한 특징과 기능에 대해서는 아래에서 설명합니다.
예를 들어, 별도로 지정하지 않는 한 이러한 데이터 프레임이 포함됩니다.
np.random.seed(0)
df1 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
df2 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
df3 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
df4 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
1) pandas.eval
이것은 팬더 문서가 포함해야 할 "실종 매뉴얼"입니다.참고: 논의 중인 세 가지 기능 중에서
pd.eval
가장 중요합니다.df.eval
그리고.df.query
pd.eval
보닛 밑에동작과 사용은 세 가지 기능에 걸쳐 어느 정도 일치하며, 약간의 의미 변형은 나중에 강조될 것입니다.이 절에서는 허용되는 구문, 우선 순위 규칙 및 키워드 인수를 포함하지만 이에 제한되지 않는 세 가지 함수 모두에서 공통된 기능을 소개합니다.
pd.eval
변수 및/또는 리터럴로 구성될 수 있는 산술식을 평가할 수 있습니다.이 식을 문자열로 전달해야 합니다.그래서, 언급된 것처럼 질문에 대답하기 위해, 당신은 다음을 할 수 있습니다.
x = 5
pd.eval("df1.A + (df1.B * x)")
여기에 주의할 사항:
- 식 전체가 문자열입니다.
df1
,df2
,그리고.x
를 참조하며,이 변수들은됩니다.합니다.eval
할 때- 속성 접근자 색인을 사용하여 특정 열에 접근합니다.사용할 수도 있습니다.
"df1['A'] + (df1['B'] * x)"
같은 취지로
는 에 .target=...
아래의 속성입니다.합니다를 보겠습니다.pd.eval
:
pd.eval("df1.A + df2.A") # Valid, returns a pd.Series object
pd.eval("abs(df1) ** .5") # Valid, returns a pd.DataFrame object
... 등등.조건식도 같은 방식으로 지원됩니다.아래 설명은 모두 유효한 표현이며 엔진이 평가합니다.
pd.eval("df1 > df2")
pd.eval("df1 > 5")
pd.eval("df1 < df2 and df3 < df4")
pd.eval("df1 in [1, 2, 3]")
pd.eval("1 < 2 < 3")
지원되는 모든 기능과 구문에 대한 자세한 목록은 설명서에서 확인할 수 있습니다.정리하자면,
- ()
<<
및 ()>>
) (), ,df + 2 * pi / s ** 4 % 42
황금빛- 를 포함한 , ,
2 < df < df2
- , ,
df < df2 and df3 < df4
아니면not df_bool
list
그리고.tuple
예를 들어, 문학작품.[1, 2]
아니면(1, 2)
- attribute access), (attribute access), :
df.a
- )(:
df[0]
- , ):
pd.eval('df')
(이는 그다지 유용하지 않습니다.- 수학함수: sin, cos, exp, log, expm1, log1p, sqrt, sinh, cosh, tanh, arcsin, arcos, arcsinh, arcsinh, arcsanh, abs 및 arcan2
이 의 이 에서는 합니다를 규칙을 합니다.set
/dict
리터럴, if-else 문, 루프 및 이해, 생성자 표현.
목록에서 다음과 같은 인덱스와 관련된 식을 전달할 수 있습니다.
pd.eval('df1.A * (df1.index > 1)')
1a) 파서 셀렉션: Theparser=...
pd.eval
를 생성하기 구문 을 구문 할 때 두 다른 옵션인를 지원합니다.pandas
그리고.python
이 둘 차이점은 약간 이 둘 사이의 주요 차이점은 약간 다른 우선순위 규칙을 통해 강조됩니다.
하기 pandas
, &
그리고.|
및된 AND및 OR입니다와 순위를 .and
그리고.or
.그렇게,
pd.eval("(df1 > df2) & (df3 < df4)")
다음과 같을 것입니다.
pd.eval("df1 > df2 & df3 < df4")
# pd.eval("df1 > df2 & df3 < df4", parser='pandas')
그리고 또한 마찬가지입니다.
pd.eval("df1 > df2 and df3 < df4")
여기서 괄호는 꼭 필요합니다.이를 수행하기 위해서는 괄호가 비트 와이즈 연산자의 높은 우선순위를 재정의해야 합니다.
(df1 > df2) & (df3 < df4)
그것 없이는 우리는
df1 > df2 & df3 < df4
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
사용하다parser='python'
문자열을 평가하는 동안 python의 실제 연산자 우선 순위 규칙과 일관성을 유지하려면 다음과 같이 하십시오.
pd.eval("(df1 > df2) & (df3 < df4)", parser='python')
의 또 은 의 의미론입니다.==
그리고.!=
s와 있습니다.in
그리고.not in
할 때,때.'pandas'
파서 예를 들면 예를들면,
pd.eval("df1 == [1, 2, 3]")
유효하며 다음과 같은 의미로 실행됩니다.
pd.eval("df1 in [1, 2, 3]")
OTOH,pd.eval("df1 == [1, 2, 3]", parser='python')
NotImplementedError
오류를 범실.
1b) 백엔드 셀렉션: Theengine=...
라는 두 가지 numexpr
및 값값)python
.numexpr
옵션은 성능에 최적화된 numexpr 백엔드를 사용합니다.
를 사용하면 하는 것과 eval
기능. 과 같은 할 수 .예를 들어 문자열 연산과 같은 내부 표현을 유연하게 수행할 수 있습니다.
df = pd.DataFrame({'A': ['abc', 'def', 'abacus']})
pd.eval('df.A.str.contains("ab")', engine='python')
0 True
1 False
2 True
Name: A, dtype: bool
불행히도 이 방법은 다음과 같은 성능 이점을 제공하지 않습니다.numexpr
엔진, 그리고 위험한 표현이 평가되지 않도록 보장하는 보안 조치는 매우 적으므로 자신의 위험을 무릅쓰고 사용하십시오!이 옵션은 일반적으로 다음으로 변경하지 않는 것이 좋습니다.'python'
무슨 짓을 하는지 모르는 한 말입니다
1c)local_dict
그리고.global_dict
식을 내부에 사용하지만 현재 네임스페이스에 정의되지 않은 변수 값을 제공하는 것이 유용한 경우도 있습니다.다에게 할 수 .local_dict
예를 들어,
pd.eval("df1 > thresh")
UndefinedVariableError: name 'thresh' is not defined
합니다. thresh
정의되지 않았습니다.그러나 다음과 같이 작동합니다.
pd.eval("df1 > thresh", local_dict={'thresh': 10})
사전에서 제공할 변수가 있을 때 유용합니다.또는 Python 엔진을 사용하면 간단히 다음과 같은 작업을 수행할 수 있습니다.
mydict = {'thresh': 5}
# Dictionary values with *string* keys cannot be accessed without
# using the 'python' engine.
pd.eval('df1 > mydict["thresh"]', engine='python')
하지만 이것은 아마도 사용하는 것보다 훨씬 느릴 것입니다.'numexpr'
및 local_dict
아니면global_dict
에 대한 있는 가 될 바라건대, 이것이 이러한 매개 변수의 사용에 대한 설득력 있는 논거가 되기를 바랍니다.
)target
(+inplace
및 )
이하는 더 간단한 방법이 에 이 사항이 되는 경우는 의 할 수 .pd.eval
__getitem__
를 들면sdict
(, (하신) DataFrame
질문의 예를 생각해 보십시오.
x = 5 df2['D'] = df1['A'] + (df1['B'] * x)
를 "D"에df2
, 우리가 합니다
pd.eval('D = df1.A + (df1.B * x)', target=df2)
A B C D
0 5 9 8 5
1 4 3 0 52
2 5 0 2 22
3 8 1 3 48
4 3 7 0 42
은 를 한 것이 아닙니다.df2
(하지만 그럴 수도...계속 읽음).또 예로오를 해 보겠습니다
pd.eval('df1.A + df2.A')
0 10
1 11
2 7
3 16
4 10
dtype: int32
를 들어,하려면 , 를 DataFrame을 할 수 target
다음과 같이 논합니다.
df = pd.DataFrame(columns=list('FBGH'), index=df1.index)
df
F B G H
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN NaN NaN NaN
4 NaN NaN NaN NaN
df = pd.eval('B = df1.A + df2.A', target=df)
# Similar to
# df = df.assign(B=pd.eval('df1.A + df2.A'))
df
F B G H
0 NaN 10 NaN NaN
1 NaN 11 NaN NaN
2 NaN 7 NaN NaN
3 NaN 16 NaN NaN
4 NaN 10 NaN NaN
df
,inplace=True
.
pd.eval('B = df1.A + df2.A', target=df, inplace=True)
# Similar to
# df['B'] = pd.eval('df1.A + df2.A')
df
F B G H
0 NaN 10 NaN NaN
1 NaN 11 NaN NaN
2 NaN 7 NaN NaN
3 NaN 16 NaN NaN
4 NaN 10 NaN NaN
한다면inplace
우, a 됩니다.ValueError
인양됩니다.
에.target
논쟁은 가지고 놀기에 재미있고, 당신은 그것을 거의 사용할 필요가 없을 것입니다.
으로 이걸 요.df.eval
합니다.
df = df.eval("B = @df1.A + @df2.A")
# df.eval("B = @df1.A + @df2.A", inplace=True)
df
F B G H
0 NaN 10 NaN NaN
1 NaN 11 NaN NaN
2 NaN 7 NaN NaN
3 NaN 16 NaN NaN
4 NaN 10 NaN NaN
메모
는 ㅇpd.eval
의하지 않은 을 의입니다와 분석하는 입니다.ast.literal_eval
:
pd.eval("[1, 2, 3]")
array([1, 2, 3], dtype=object)
또한 다음과 같이 중첩된 목록을 구문 분석할 수 있습니다.'python'
엔진:
pd.eval("[[1, 2, 3], [4, 5], [10]]", engine='python')
[[1, 2, 3], [4, 5], [10]]
문자열 목록:
pd.eval(["[1, 2, 3]", "[4, 5]", "[10]"], engine='python')
[[1, 2, 3], [4, 5], [10]]
그러나 문제는 길이가 100보다 큰 목록의 경우입니다.
pd.eval(["[1]"] * 100, engine='python') # Works
pd.eval(["[1]"] * 101, engine='python')
AttributeError: 'PandasExprVisitor' object has no attribute 'visit_Ellipsis'
이 오류의 원인, 해결 방법 및 해결 방법에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
2) DataFrame.eval
:
와 같이, ,df.eval
pd.eval
논쟁의 약간의 병치를 하고 있는 상태에서 말입니다.v0.23 소스 코드는 다음을 보여줍니다.
def eval(self, expr, inplace=False, **kwargs):
from pandas.core.computation.eval import eval as _eval
inplace = validate_bool_kwarg(inplace, 'inplace')
resolvers = kwargs.pop('resolvers', None)
kwargs['level'] = kwargs.pop('level', 0) + 1
if resolvers is None:
index_resolvers = self._get_index_resolvers()
resolvers = dict(self.iteritems()), index_resolvers
if 'target' not in kwargs:
kwargs['target'] = self
kwargs['resolvers'] = kwargs.get('resolvers', ()) + tuple(resolvers)
return _eval(expr, inplace=inplace, **kwargs)
eval
는 에 전달합니다.pd.eval
.
자세한 내용은 DataFrame.eval() 대 pandas.eval() 또는 Python eval()의 사용 시기를 참조하십시오.
2a) 사용상의 차이
2a1) 데이터 프레임을 사용한 표현 vs. 시리즈 표현식
DataFrame 를 .pd.eval
를 들어, . , 와 한 값을 .pd.eval("df1 + df2")
하실 때df1.eval
아니면df2.eval
.
2a2) 열 이름 지정
또 다른 주요 차이점은 열에 접근하는 방법입니다.를 들어 두 열 하려면 "A"와 "B"를열합니다.df1
, 당신은 전화할 것입니다.pd.eval
다음과 같은 표현으로
pd.eval("df1.A + df1.B")
df.eval의 경우 열 이름만 입력하면 됩니다.
df1.eval("A + B")
로의 맥락 에서.df1
가 열 "A"가 "B" 합니다를 합니다.
를 할 수도 .index
(인덱스 이름이 지정되지 않은 경우, 이 경우 이름을 사용합니다.)
df1.eval("A + index")
또는 일반적으로 인덱스가 1개 이상인 DataFrame의 경우 "index at level k"를 나타내는 변수 "ilevel_k"를 사용하여 식에서 인덱스의 kth 레벨을 참조할 수 있습니다.IOW, 위의 표현은 다음과 같이 쓸 수 있습니다.df1.eval("A + ilevel_0")
.
이 규칙들은 또한 다음에 적용됩니다.df.query
.
2a3) 로컬/글로벌 네임스페이스의 변수 접근
열 이름과의 혼동을 방지하기 위해 식 내부에 제공된 변수는 "@" 기호 앞에 와야 합니다.
A = 5
df1.eval("A > @A")
입니다도 입니다.query
.
입니다에서 수 지정 을 따라야 입니다.eval
. 이름 지정 식별자에 대한 규칙 목록은 여기를 참조하십시오.
2a4) 다중 줄 질의 및 할당
거의 eval
행 합니다()query
그렇지 않습니다.를 들어, 몇 연산을 두의 새 열 "를 에 만든 F를으로 세 열 "를 어를 수행하고, df1열 "E"와 "F"고를으로하고, "E"와 "F"열 "G"다를 수 있습니다.
df1.eval("""
E = A + B
F = @df2.A + @df2.B
G = E >= F
""")
A B C D E F G
0 5 0 3 3 5 14 False
1 7 9 3 5 16 7 True
2 2 4 7 6 6 5 True
3 8 8 1 6 16 9 True
4 7 7 8 1 14 10 True
3)eval
.query
은 를 이 됩니다.df.query
를 pd.eval
서브루틴으로서
으로.query
알 수 을 하고 이)예: True/False식)됩니다에 하는 데 됩니다.True
결과. 는 식의 결과는 다음으로 전달됩니다에게 전달됩니다.loc
(대부분의 경우) 식을 만족하는 행을 반환합니다.면,
의 평가 됩니다에게 됩니다.
DataFrame.loc
키 때문에 키예: DataFrame)다로 됩니다.DataFrame.__getitem__()
.합니다를 합니다.
pandas.eval()
전달된 쿼리를 평가하는 함수입니다.
,query
그리고.df.eval
열 이름과 변수에 액세스하는 방법이 둘 다 비슷합니다.
위에서 언급한 바와 같이 이 둘의 주요 차이점은 표현 결과를 처리하는 방식입니다.이는 실제로 이 두 함수를 통해 식을 실행할 때 명확해집니다.예를 들어 다음을 생각해 보십시오.
df1.A
0 5
1 7
2 2
3 8
4 7
Name: A, dtype: int32
df1.B
0 9
1 3
2 0
3 1
4 7
Name: B, dtype: int32
"A" > = "B" 인 모든 행을 가져오려면 다음과 같이 하십시오.df1
, 우리는 사용할 것입니다.eval
다음과 같이:
m = df1.eval("A >= B")
m
0 True
1 False
2 False
3 True
4 True
dtype: bool
m
는 A =B"를 식 "A = B"다입니다.그런 다음 마스크를 사용해 필터를 합니다.df1
:
df1[m]
# df1.loc[m]
A B C D
0 5 0 3 3
3 8 8 1 6
4 7 7 8 1
과 .query
은 "m" 로 됩니다.loc
, .query
, 당신은 단지 할 필요가 있을 것입니다.
df1.query("A >= B")
A B C D
0 5 0 3 3
3 8 8 1 6
4 7 7 8 1
성능 면에서는 똑같습니다.
df1_big = pd.concat([df1] * 100000, ignore_index=True)
%timeit df1_big[df1_big.eval("A >= B")]
%timeit df1_big.query("A >= B")
14.7 ms ± 33.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
14.7 ms ± 24.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
그러나 후자는 더 간결하고, 같은 동작을 한 단계로 표현합니다.
로 을 할 수도 하세요.query
와 같이이어를 들어 df1.index하려면)
df1.query("index")
# Same as df1.loc[df1.index] # Pointless,... I know
A B C D
0 5 0 3 3
1 7 9 3 5
2 2 4 7 6
3 8 8 1 6
4 7 7 8 1
하지만 하지 마요.
을(를) 하십시오.query
조건식을 기반으로 행을 쿼리하거나 필터링하는 경우.
이미 , 의 하시기 바랍니다.eval/query
단순한 구문에 이끌려 데이터셋의 행 수가 15,000개 미만일 경우 심각한 성능 문제가 발생합니다.
그런 경우에는 사용만 하면 됩니다.df.loc[mask1, mask2]
.
언급URL : https://stackoverflow.com/questions/53779986/dynamically-evaluate-an-expression-from-a-formula-in-pandas
'programing' 카테고리의 다른 글
입력에 초점이 맞추어져 있는지 확인하는 Javascript/jQuery (0) | 2023.10.09 |
---|---|
ServletContext 리소스 [/WEB-INF/applicationContext.xml]을(를) 열 수 없습니다. (0) | 2023.10.09 |
프로그래밍 방식으로 iPhone의 탈옥 여부 확인 (0) | 2023.10.09 |
C 코드는 어셈블리 코드(예: 최적화 스트렐렌)를 어떻게 호출합니까? (0) | 2023.10.09 |
Firefox의 Flexbox 오버플로 문제 (0) | 2023.10.09 |