[英]python pandas filter function regex behavior on MultiIndex dataframe
我有一個 dataframe df
,看起來像(有關生成數據幀的代碼,請參見附錄):
fy 2018 2019 tag uom Assets USD 3.753190e+11 3.385160e+11 AssetsCurrent USD 1.286450e+11 1.628190e+11 AssetsNoncurrent USD 2.466740e+11 1.756970e+11 DeferredTaxAssetsDeferredCostSharing USD 6.670000e+08 NaN DeferredTaxAssetsDeferredIncome USD 1.521000e+09 1.141000e+09 DeferredTaxAssetsGoodwillAndIntangibleAssets USD NaN 1.143300e+10 DeferredTaxAssetsLiabilitiesNet USD 5.834000e+09 5.834000e+09 DeferredTaxAssetsNet USD 8.974000e+09 6.610000e+09 DeferredTaxAssetsOther USD 8.340000e+08 7.970000e+08 DeferredTaxAssetsPropertyPlantAndEquipment USD 1.230000e+09 1.370000e+08 DeferredTaxAssetsTaxDeferredExpenseCompensation... USD 7.030000e+08 5.130000e+08 DeferredTaxAssetsTaxDeferredExpenseReservesAndA... USD 4.019000e+09 3.151000e+09 DeferredTaxAssetsUnrealizedLossesOnAvailablefor... USD 0.000000e+00 8.710000e+08 DerivativeAssetsReductionforMasterNettingArrang... USD 1.400000e+09 2.100000e+09 IncreaseDecreaseInOtherOperatingAssets USD -1.055000e+09 5.318000e+09 NoncurrentAssets USD 3.378300e+10 4.130400e+10 OtherAssetsCurrent USD 1.208700e+10 1.208700e+10 OtherAssetsNoncurrent USD 2.228300e+10 2.228300e+10
這是一個帶有索引tag
和uom
的 MultiIndex pivot 表。 我的目標是使用正則表達式和過濾器 function按tag
索引過濾行。 例如:
df.filter(regex="^Assets$", axis="index")
理想情況下會過濾掉該行:
fy 2018 2019 tag uom Assets USD 3.753190e+11 3.385160e+11
但是,當我這樣做時,它會輸出一個空的 dataframe:
Empty DataFrame Columns: [2018, 2019] Index: []
我可以通過使用來規避這個問題:
df.index.get_level_values("tag").str.contains("^Assets$")
或作為 function
search = lambda df, regex, index_name: df.loc[df.index.get_level_values(index_name).str.contains(regex)]
但這對我來說不太令人滿意。 我是否缺少有關 pandas 過濾器 function 及其正則表達式輸入的工作原理的信息? 它的行為不像預期的那樣,我的猜測是因為我有 2 個索引: tag
和uom
因此當我使用"^Assets$"
作為我的正則表達式時,正則表達式在uom
索引中失敗。 這通過使用正則表達式"^Assets$|USD"
得到支持,它返回整個 dataframe 因為所有行都有uom=USD
,並且它顯示過濾器 function 考慮了這兩個索引。 如果是這種情況,那么我如何有選擇地為 MultiIndex dataframe 上的過濾器 function 選擇 index= tag
?
附錄:
import pandas as pd
import numpy as np
levels = ['Assets',
'AssetsCurrent',
'AssetsNoncurrent',
'DeferredTaxAssetsDeferredCostSharing',
'DeferredTaxAssetsDeferredIncome',
'DeferredTaxAssetsGoodwillAndIntangibleAssets',
'DeferredTaxAssetsLiabilitiesNet',
'DeferredTaxAssetsNet',
'DeferredTaxAssetsOther',
'DeferredTaxAssetsPropertyPlantAndEquipment',
'DeferredTaxAssetsTaxDeferredExpenseCompensationAndBenefitsShareBasedCompensationCost',
'DeferredTaxAssetsTaxDeferredExpenseReservesAndAccruals',
'DeferredTaxAssetsUnrealizedLossesOnAvailableforSaleSecuritiesGross',
'DerivativeAssetsReductionforMasterNettingArrangements',
'IncreaseDecreaseInOtherOperatingAssets',
'NoncurrentAssets',
'OtherAssetsCurrent',
'OtherAssetsNoncurrent']
codes = ['USD' for i in range(len(levels))]
index = pd.MultiIndex.from_arrays([levels, codes], names=['tag', 'uom'])
columns = pd.Int64Index([2018, 2019], dtype='int64', name='fy')
values = [[3.75319e+11, 3.38516e+11],
[1.28645e+11, 1.62819e+11],
[2.46674e+11, 1.75697e+11],
[6.67000e+08, np.NaN],
[1.52100e+09, 1.14100e+09],
[np.NaN, 1.14330e+10],
[5.83400e+09, 5.83400e+09],
[8.97400e+09, 6.61000e+09],
[8.34000e+08, 7.97000e+08],
[1.23000e+09, 1.37000e+08],
[7.03000e+08, 5.13000e+08],
[4.01900e+09, 3.15100e+09],
[0.00000e+00, 8.71000e+08],
[1.40000e+09, 2.10000e+09],
[-1.05500e+09, 5.31800e+09],
[3.37830e+10, 4.13040e+10],
[1.20870e+10, 1.20870e+10],
[2.22830e+10, 2.22830e+10]]
df = pd.DataFrame(values, columns=columns, index=index)
過濾器 function 的正則表達式部分的實現很短,很容易適應多索引場景,在這種場景中,您仍然希望只對多索引的 1 部分進行正則表達式。 我知道這不是您所問問題的直接答案,因為您是對的,因為過濾器 function 不處理多索引。
我在這里遇到了同樣的問題,並認為發布我使用的代碼可能對其他人有用,該代碼改編自 pandas 原版:
import regex as re
def filter_multi(df, index_level_name, regex, axis=0):
def f(x):
return matcher.search(str(x)) is not None
matcher = re.compile(regex)
values = df.axes[axis].get_level_values(index_level_name).map(f)
return df.loc(axis=axis)[values]
使用附錄中的代碼:
print(df)
print(filter_multi(df, index_level_name='tag', regex='^Assets$', axis=0))
print(filter_multi(df, index_level_name='fy', regex='^2019$', axis=1))
如果你想從多索引的第一部分過濾一個唯一值,你可以使用loc
:
df.loc[['Assets']]
這使:
fy 2018 2019
tag uom
Assets USD 3.753190e+11 3.385160e+11
如果對於您的實際問題,必須使用過濾器,您應該重置索引中未使用的部分並在過濾后將其重新設置:
df.reset_index(level='uom').filter(regex='^Assets$', axis=0).set_index('uom', append=True)
另一種選擇是首先從您的索引中刪除uom
,應用filter
(然后將其應用於唯一的索引tag
)並將uom
添加回您的索引,如
df.reset_index('uom').filter(regex="^Assets$", axis=0).set_index('uom', append=True)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.