请考虑以下两个数据帧(长度不相等)。
df1 = pd.DataFrame({'date': ['2016-10-08', '2016-11-08','2016-12-08','2017-01-08'], 'qty': [1,8,2,4]})
df2 = pd.DataFrame({'date': ['2016-11-12', '2017-01-12'], 'factor': [2,3]})
>>> df1
date qty
0 2016-10-08 1
1 2016-11-08 8
2 2016-12-08 2
3 2017-01-08 4
>>> df2
date factor
0 2016-11-12 2
1 2017-01-12 3
我想在factored_quantity
中计算一个名为df1
的新列,如下所示。
在
df2
中选择其日期大于df1
中的日期并乘以qty
的所有因子,得出factored_qty
所以我的最终数据帧看起来像
>>> df1
date qty factored_qty
0 2016-10-08 1 6
1 2016-11-08 8 48
2 2016-12-08 2 6
3 2017-01-08 4 12
说明:
2016-10-08
中的df1
小于2016-11-12
中的2017-01-12
和df2
。因此,乘以因子2*3*qty
2016-12-08
中的日期df1
大于2016-11-12
且小于2017-01-12
的{{1}}。因此,只能乘以因子df2
我看过的大部分与
有关
1.合并两个数据框。
2.比较两个等长的数据帧
3.比较两个长度不相等的数据框
但是,当前问题与基于另一个数据帧的收集(乘以因子)的值(外键将不相等)计算值有关。
答案 0 :(得分:2)
对于大型数据框而言,可能不是最快的解决方案,但它可以工作。我们在满足条件的prod
的所有行上使用df2
。
df1['factored_qty'] = df1.apply(lambda x: df2[df2.date>x.date].factor.prod() * x.qty,axis=1)
结果:
date qty factored_qty
0 2016-10-08 1 6
1 2016-11-08 8 48
2 2016-12-08 2 6
3 2017-01-08 4 12
merge_asof
。我们计算倒数cumprod
,即从最后一行到第一行。不幸的是,如果df2中的最后一个日期小于df1中的最后一个日期,这会有点令人费解,因为在这种情况下,我们必须向df2中添加一个前哨(df1的最大日期为1)。
df3 = pd.merge_asof(df1.assign(date=pd.to_datetime(df1.date)),
df2.assign(date=pd.to_datetime(df2.date), factor=df2.factor.iloc[::-1].cumprod().iloc[::-1]) if(df1.date.max()<df2.date.max())
else df2.assign(date=pd.to_datetime(df2.date), factor=df2.factor.iloc[::-1].cumprod().iloc[::-1]).append({'date': pd.to_datetime(df1.date.max()), 'factor': 1}, ignore_index=True),
'date',
direction='forward')
df3.factor *= df3.qty
df3.rename(columns={'factor': 'factored_qty'}, inplace=True)
import pandas as pd
import numpy as np
n = 100
np.random.seed(0)
df1_ = pd.DataFrame({'date': [(pd.Timestamp('2020-06-01') - pd.Timedelta(x,'D')).strftime('%Y-%m-%d') for x in np.sort(np.random.choice(200*n, 2*n, False))[::-1]],
'qty': np.random.randint(1, 20, 2*n)})
df2_ = pd.DataFrame({'date': [(pd.Timestamp('2020-06-01') - pd.Timedelta(x,'D')).strftime('%Y-%m-%d') for x in np.sort(np.random.choice(100*n, n, False))[::-1]],
'factor': np.random.randint(1, 10, n)})
def setup():
global df1, df2
df1 = df1_.copy(True)
df2 = df2_.copy(True)
def method_apply():
df1['factored_qty'] = df1.apply(lambda x: df2[df2.date>x.date].factor.prod() * x.qty,axis=1)
return df1
def method_merge():
df3 = pd.merge_asof(df1.assign(date=pd.to_datetime(df1.date)),
df2.assign(date=pd.to_datetime(df2.date), factor=df2.factor.iloc[::-1].cumprod().iloc[::-1]) if(df1.date.max()<df2.date.max())
else df2.assign(date=pd.to_datetime(df2.date), factor=df2.factor.iloc[::-1].cumprod().iloc[::-1]).append({'date': pd.to_datetime(df1.date.max()), 'factor': 1}, ignore_index=True),
'date',
direction='forward')
df3.factor *= df3.qty
df3.rename(columns={'factor': 'factored_qty'}, inplace=True)
return df3
from itertools import product
from collections import defaultdict
def method_dict():
d = defaultdict(list)
df1['date'] = pd.to_datetime(df1['date'])
df2['date'] = pd.to_datetime(df2['date'])
for (date1, qty), (date2, factor) in product(df1.to_numpy(),df2.to_numpy()) :
if date1 < date2 :
d[(date1, qty)].append(factor)
outcome = {k:[s,np.prod((s,*v))] for (k,s),v in d.items()}
return pd.DataFrame.from_dict(outcome, orient='index', columns=['qty','factored_qty']).reset_index()
def method_numpy():
mask = df1.date.to_numpy()[:,None] < df2.date.to_numpy()
it = iter(mask)
def mul(x):
val = np.prod(df2.loc[next(it),'factor'])
return x*val
df1['factored_qty'] = df1['qty'].map(mul)
return df1
结果:
method_apply 220 ms ± 5.99 ms per loop
method_numpy 86.7 ms ± 2.51 ms per loop
method_dict 80.7 ms ± 436 µs per loop
method_merge 8.87 ms ± 68.1 µs per loop
根据df2中的随机因素,其乘积可能会导致溢出,在此将其忽略。 method_dict
仅在df2中的最后一个日期大于df1中的最后一个日期时才能正常工作,并且在计时中也将忽略此时间。
答案 1 :(得分:2)
确保您的 if let url = Bundle.main.url(forResource: "SomeAudioFile", withExtension: "m4a") {
player.removeAllItems()
player.insert(AVPlayerItem(url: url), after: nil)
player.play()
}
dtype是有效的日期时间,否则请使用pd.to_datetime
。然后,您可以使用pd.Series.to_numpy
并在此处使用broadcasting
来比较和构建用于布尔索引的布尔数组。然后使用pd.Series.map
,使用np.prod
获得整个数组的乘积。
date
OR
mask = df1.date.to_numpy()[:,None] < df2.date.to_numpy() # `_.values` should be avoided instead use `_.to_numpy()`
it = iter(mask)
def mul(x):
val = np.prod(df2.loc[next(it),'factor'])
return x*val
df1['factored_qty'] = df1['qty'].map(mul)
df1
date qty factored_qty
0 2016-10-08 1 6
1 2016-11-08 8 48
2 2016-12-08 2 6
3 2017-01-08 4 12
时间分析:
mask = df1.date.to_numpy()[:,None] < df2.date.to_numpy()
l = [np.prod(df2.loc[idx,'factor']) for idx in mask]
# df2.loc[idx,'factor'].prod()
df['factored_qty'] = df1.qty.mul(l)
答案 2 :(得分:1)
转换为日期时间:
df1['date'] = pd.to_datetime(df1['date'])
df2['date'] = pd.to_datetime(df2['date'])
将计算移至词典;我想相信这样的计算在字典中会更快-这是一种假设;希望有人进行测试并证明或揭穿这一切。
from itertools import product
from collections import defaultdict
d = defaultdict(list)
#iterate through data and append factors that meet criteria
for (date1, qty), (date2, factor) in product(df1.to_numpy(),df2.to_numpy()) :
if date1 <= date2 :
d[(date1, qty)].append(factor)
else:
d[(date1, qty)].append(1)
让我们看看d的内容:
print(d)
defaultdict(list,
{(Timestamp('2016-10-08 00:00:00'), 1): [2, 3],
(Timestamp('2016-11-08 00:00:00'), 8): [2, 3],
(Timestamp('2016-12-08 00:00:00'), 2): [1, 3],
(Timestamp('2017-01-08 00:00:00'), 4): [1, 3]})
获取过滤后的数据与数量的乘积:
outcome = {k:[s,np.prod((s,*v))] for (k,s),v in d.items()}
创建数据框:
pd.DataFrame.from_dict(outcome, orient='index', columns=['qty','factored_qty'])
qty factored_qty
2016-10-08 1 6
2016-11-08 8 48
2016-12-08 2 6
2017-01-08 4 12