我有一个数据框:
Time c_1 c_2
t1 x 1
t2 x 2
t3 y 1
t4 y 2
t5 1 x
t6 2 x
t7 1 y
t8 2 y
我需要在不循环的情况下形成 2 列,这样:
- new_1:c_1.value 出现在 c_2 中的下一个最早时间(例如,对于 t1,new_1 = t5,因为 c_1 值为 'x',下一次 'x' 出现在 c_2 中是在 t5)
- new_2:c_2.value 下一次出现在 c_1 中的最早时间(例如,对于 t1,new_1 = t5,因为 c_2 值为 '1',下一次 '1' 出现在 c_1 中是在 t3)
所以对于上面的输入,输出应该是:
Time c_1 c_2 new_1 new_2
t1 x 1 t5 t5
t2 x 2 t5 t6
t3 y 1 t7 t5
t4 y 2 t7 t6
t5 1 x NaT NaT
t6 2 x NaT NaT
t7 1 y NaT NaT
t8 2 y NaT NaT
你会如何处理这个问题?
最佳答案
这是一个使用 apply()
和 lambda 函数从原始 DataFrame 中为每一行选择正确数据的解决方案。
import pandas as pd
data = {'Time': pd.date_range('1/1/2000', periods=16, freq='D'),
'c_1': ['x', 'x', 'y', 'y', '1', '2', '1', '2']*2,
'c_2': ['1', '2', '1', '2', 'x', 'x', 'y', 'y']*2 }
df = pd.DataFrame(data)
df['new_1'] = df.apply(lambda r: (df.Time[(df.Time>r.Time) & (df.c_2 == r.c_1)].head(1).reset_index(drop=True)), axis=1)
df['new_2'] = df.apply(lambda r: (df.Time[(df.Time>r.Time) & (df.c_1 == r.c_2)].head(1).reset_index(drop=True)), axis=1)
print(df)
输出是:
Time c_1 c_2 new_1 new_2
0 2000-01-01 x 1 2000-01-05 2000-01-05
1 2000-01-02 x 2 2000-01-05 2000-01-06
2 2000-01-03 y 1 2000-01-07 2000-01-05
3 2000-01-04 y 2 2000-01-07 2000-01-06
4 2000-01-05 1 x 2000-01-09 2000-01-09
5 2000-01-06 2 x 2000-01-10 2000-01-09
6 2000-01-07 1 y 2000-01-09 2000-01-11
7 2000-01-08 2 y 2000-01-10 2000-01-11
8 2000-01-09 x 1 2000-01-13 2000-01-13
9 2000-01-10 x 2 2000-01-13 2000-01-14
10 2000-01-11 y 1 2000-01-15 2000-01-13
11 2000-01-12 y 2 2000-01-15 2000-01-14
12 2000-01-13 1 x NaT NaT
13 2000-01-14 2 x NaT NaT
14 2000-01-15 1 y NaT NaT
15 2000-01-16 2 y NaT NaT
apply
是通过 axis=1
完成的,所以它一次迭代一行。 lambda 函数仅选择数据帧中出现在当前行之后且列中具有正确值的行。可能有多个行符合这些条件。 head(1)
选择第一个匹配项,reset_index(drop=True)
确保返回的每个 Series 具有相同的索引 (0),以便 apply ()
将它们全部从返回值中放到一个列中。
关于python - Pandas 操纵: Non-distinct groups,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43158177/