发布代码后会更容易解释问题。
这是我的前两个 dfs:
df_data1 = {
"ID": [1, 2, 3, 4, 5],
"Date": ['01-01-2010', '01-02-2010', '01-03-2010', '01-04-2010', '01-05-2010'],
'Value': [90, 58, 85, 33, 68]
}
df_data2 = {
"ID": [6, 7, 8, 9, 10],
"Date": ['01-06-2010', '01-07-2010', '01-08-2010', '01-09-2010', '01-10-2010'],
"Value": [85, 39, 99, 15, 87]
}
df1 = pd.DataFrame(df_data1)
df2 = pd.DataFrame(df_data2)
然后我使用交叉方法合并这两个,以便这两个 dfs 逐行比较。
df3 = df1.merge(df2, how="cross")
df3
然后我用两个索引创建第四个 df,所以我有一个整洁的 df,其中每一行都是两者之间的比较。
df4 = pd.DataFrame()
df4["Value"] = (df3[['Value_x', 'Value_y']].mean(axis=1))
df4.index = pd.MultiIndex.from_tuples(list(itertools.product(df1["ID"], df2["ID"])), names = ['df1 ID', 'df2 ID'])
df4
现在我遇到了麻烦。我想做的是添加列。一列显示第一个索引的日期,第二列显示第二个索引的日期。我认为 loc 将是最好使用的工具。这是我尝试使用的代码:
df4['df1 Date'] = df1.loc[df1['Date'] == df4.index.get_level_values(0)]['Date']
df4
这是错误:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-107-253564fdd003> in <module>
----> 1 df4['df1 Date'] = df1.loc[df1['Date'] == df4.index.get_level_values(0)]['Date']
2 df4
~\AppData\Roaming\Python\Python37\site-packages\pandas\core\ops\common.py in new_method(self, other)
67 other = item_from_zerodim(other)
68
---> 69 return method(self, other)
70
71 return new_method
~\AppData\Roaming\Python\Python37\site-packages\pandas\core\arraylike.py in __eq__(self, other)
30 @unpack_zerodim_and_defer("__eq__")
31 def __eq__(self, other):
---> 32 return self._cmp_method(other, operator.eq)
33
34 @unpack_zerodim_and_defer("__ne__")
~\AppData\Roaming\Python\Python37\site-packages\pandas\core\series.py in _cmp_method(self, other, op)
5500
5501 with np.errstate(all="ignore"):
-> 5502 res_values = ops.comparison_op(lvalues, rvalues, op)
5503
5504 return self._construct_result(res_values, name=res_name)
~\AppData\Roaming\Python\Python37\site-packages\pandas\core\ops\array_ops.py in comparison_op(left, right, op)
260 if len(lvalues) != len(rvalues):
261 raise ValueError(
--> 262 "Lengths must match to compare", lvalues.shape, rvalues.shape
263 )
264
ValueError: ('Lengths must match to compare', (5,), (25,))
我明白为什么会出现错误,但我不知道如何克服它。它误解了我的意图。我并不是想将 25 行与 5 行进行比较;每当该 ID 出现在该特定索引中时,我都会尝试在新列中显示 df1 的日期。
解决此问题后,我计划对第二个索引执行相同的操作,然后最终添加第三列来减去两个日期,以便它可以测量两个日期之间经过的时间。如果您知道一个好的、简洁的代码,我也会很有帮助,但我也可以自己做。
谢谢!
我会保持简单,避免中间体,并且
itertools
:
out = (df1
.merge(df2, how='cross', suffixes=['_df1', '_df2'])
.set_index(['ID_df1', 'ID_df2'])
.assign(Value=lambda d: d.pop('Value_df1').add(d.pop('Value_df2')).div(2))
)
替代方案:
out = (df1
.merge(df2, how='cross', suffixes=['_df1', '_df2'])
.set_index(['ID_df1', 'ID_df2'])
.assign(Value=lambda d: d[['Value_df1', 'Value_df2']].mean(axis=1))
.drop(columns=['Value_df1', 'Value_df2'])
)
注意。如果您确实想要
df1
/df2
作为前缀而不是后缀,请 rename
或使用正则表达式来后处理名称。
输出:
Date_df1 Date_df2 Value
ID_df1 ID_df2
1 6 01-01-2010 01-06-2010 87.5
7 01-01-2010 01-07-2010 64.5
8 01-01-2010 01-08-2010 94.5
9 01-01-2010 01-09-2010 52.5
10 01-01-2010 01-10-2010 88.5
2 6 01-02-2010 01-06-2010 71.5
7 01-02-2010 01-07-2010 48.5
8 01-02-2010 01-08-2010 78.5
9 01-02-2010 01-09-2010 36.5
10 01-02-2010 01-10-2010 72.5
3 6 01-03-2010 01-06-2010 85.0
7 01-03-2010 01-07-2010 62.0
8 01-03-2010 01-08-2010 92.0
9 01-03-2010 01-09-2010 50.0
10 01-03-2010 01-10-2010 86.0
4 6 01-04-2010 01-06-2010 59.0
7 01-04-2010 01-07-2010 36.0
8 01-04-2010 01-08-2010 66.0
9 01-04-2010 01-09-2010 24.0
10 01-04-2010 01-10-2010 60.0
5 6 01-05-2010 01-06-2010 76.5
7 01-05-2010 01-07-2010 53.5
8 01-05-2010 01-08-2010 83.5
9 01-05-2010 01-09-2010 41.5
10 01-05-2010 01-10-2010 77.5