我有一個pandas DataFrame,每列代表一個季度,最近的季度放在右邊,不是所有的資訊都同時得到,有些列可能缺少資訊(NaN 值)
我想用該行匹配的第一個條件編號創建一個新列,如果不匹配任何條件,則為零
該條件適用于具有資料的 3 個最新列(整數,忽略 NaN),如果串列中的值大于或等于其在 DataFrame 中的相應值,則認為匹配
我嘗試使用 apply,但我無法使其作業并且失敗的嘗試很慢
import pandas as pd
import numpy as np
criteria_dict = {
1: [10, 0, 10]
, 2: [0, 10, 10]
}
list_of_tuples = [
(78, 7, 11, 15), # classify as 2 since 7 >= 0, 11 >= 10, 15 >= 10
(98, -5, np.NaN, 18), # classify as 0, ignoring NaN it doesn't match any criteria because of the -5
(-78, 20, 64, 28), # classify as 1 20 >= 10, 64 >= 0, 28 >= 10
(35, 63, 27, np.NaN), # classify as 1, NaN value should be ignored, 35 >= 10, 63 >=0, 27 >= 10
(-11, 0, 56, 10) # classify as 2, 0 >= 0, 56 >= 10, 10 >= 10
]
df = pd.DataFrame(
list_of_tuples,
index=['A', 'B', 'C', 'D', 'E'],
columns=['2021Q2', '2021Q3', '2021Q4', '2022Q1']
)
print(df)
uj5u.com熱心網友回復:
將自定義函式應用于每一行應該可以作業。
def func(x):
x = x.dropna().to_numpy()[-3:]
if len(x) < 3:
return 0
for k, v in criteria_dict.items():
if np.all(x >= v):
return k
return 0
df.apply(func, axis=1)
uj5u.com熱心網友回復:
可能使用apply是最簡單的,但我想嘗試使用 numpy 的解決方案,對于具有多行的資料幀應該更快。
import numpy as np
# Rows with too many NaNs.
df_arr = df.to_numpy()
# Find NaNs.
nans = np.nonzero(np.isnan(df_arr))
# Roll the rows so that the latest three columns with valid data are all to the right.
for row, col in zip(*nans):
df_arr[row, :] = np.roll(df_arr[row, :], shift=4-col)
# Check for matching criteria.
df['criteria'] = np.select([np.all((df_arr[:, 1:] - criteria_dict[crit])>=0, axis=1) for crit in criteria_dict],
[crit for crit in criteria_dict])
print(df)
2021Q2 2021Q3 2021Q4 2022Q1 criteria
A 78 7 11.0 15.0 2.0
B 98 -5 NaN 18.0 0.0
C -78 20 64.0 28.0 1.0
D 35 63 27.0 NaN 1.0
E -11 0 56.0 10.0 2.0
一些時間df = pd.concat([df]*10000):
# 103 ms ± 1.27 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit numpy(df)
# 1.32 s ± 14.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit pandas_apply(df)
所以它的速度要快 10 倍。
uj5u.com熱心網友回復:
可以實作全矢量比較。請注意,瓶頸是廣播步驟,它將創建一個K*N*M大小的中間陣列,其中M*N是資料幀子集的大小(此處為 5*3)和K*N標準的大小(此處為 2*3)。您需要有足夠的記憶體來創建這個陣列。
分步程式:
首先獲取最后 3 個非 nan 值b:
N = 3
a = df.to_numpy()
from scipy.stats import rankdata
b = a[rankdata(~np.isnan(a), method='ordinal', axis=1)>(a.shape[1]-N)].reshape(-1,N)
array([[ 7., 11., 15.],
[98., -5., 18.],
[20., 64., 28.],
[35., 63., 27.],
[ 0., 56., 10.]])
然后制作一個條件為的陣列c;
c = np.array(list(criteria_dict.values()))
array([[10, 0, 10],
[ 0, 10, 10]])
廣播和的比較b并c獲取所有值>=:
d = (b>=c[:, None]).all(2)
array([[False, False, True, True, False],
[ True, False, True, True, True]])
criteria_dict使用鍵(否則為 0)獲取第一個 True 的索引:
e = np.where(d.any(0), np.array(list(criteria_dict))[np.argmax(d, axis=0)], 0)
array([2, 0, 1, 1, 2])
分配給資料框:
df['criteria'] = e
2021Q2 2021Q3 2021Q4 2022Q1 criteria
A 78 7 11.0 15.0 2
B 98 -5 NaN 18.0 0
C -78 20 64.0 28.0 1
D 35 63 27.0 NaN 1
E -11 0 56.0 10.0 2
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/474506.html
下一篇:我正在嘗試合并兩個資料框
