【问题标题】:creating if else statement to changing duplicate values to subsequent value (grouped by multiple columns)创建 if else 语句以将重复值更改为后续值(按多列分组)
【发布时间】:2021-12-02 20:11:51
【问题描述】:

我已经远远超过了我的头脑。可以用 R 得到这个,但不知道用 Python(我正在学习)。

所以...我有一个数据框,其中包含每天四次抽样的参与者,持续 30 天。问题是,如果参与者在一定范围内填写了两次调查,则两者的 time_of_day 可能都是 2;所以有时 time_of_day 对同一参与者和同一日期具有相同的值(它不应该)。我咨询了实验室主任,这是因为输入没有时间锁定。所以要解决这个问题,我想我需要创建某种 ifelse 语句,如果有重复使其成为前面的值(如果 2 有重复,则将 time_of_day 的第一个值设为 1)。我不知道如何在下面创建的 lambda/if else 语句中执行此操作,但我完全无法理解的是这些也需要按参与者和日期分组,我不知道如何在 Python 的 lambda 语句中结合 if else 语句和删除重复项。

data\
.assign(time_of_day = data['time_of_day'].apply(lambda x: if else )

因此,对于下面的数据,对于参与者 21 于 2019-12-08 日期的 time_of_day,第一次观察(当前为 2)将变为 1,第三次观察(当前为 4)将变为 3。

我在 R 中找不到 dput() 的等价物,所以我将一个最小的可重现数据框转换为字典(我在这里读到:Print pandas data frame for reproducible example (equivalent to dput in R))...所以只需将其转换为带有data = pd.DataFrame.from_dict(df_dict)的数据框:

df_dict = {'pid': {0: '21',
  1: '21',
  2: '21',
  3: '21',
  4: '21',
  5: '21',
  200: '26',
  201: '26',
  202: '26',
  203: '26',
  204: '26'},
 'datestamp': {0: Timestamp('2019-12-07 21:33:11'),
  1: Timestamp('2019-12-08 13:32:16'),
  2: Timestamp('2019-12-08 13:33:41'),
  3: Timestamp('2019-12-08 19:54:22'),
  4: Timestamp('2019-12-08 19:55:24'),
  5: Timestamp('2019-12-09 12:11:24'),
  200: Timestamp('2020-02-12 20:16:33'),
  201: Timestamp('2020-02-13 08:37:21'),
  202: Timestamp('2020-02-13 13:24:20'),
  203: Timestamp('2020-02-13 17:05:27'),
  204: Timestamp('2020-02-13 20:02:12')},
 'date': {0: datetime.date(2019, 12, 7),
  1: datetime.date(2019, 12, 8),
  2: datetime.date(2019, 12, 8),
  3: datetime.date(2019, 12, 8),
  4: datetime.date(2019, 12, 8),
  5: datetime.date(2019, 12, 9),
  200: datetime.date(2020, 2, 12),
  201: datetime.date(2020, 2, 13),
  202: datetime.date(2020, 2, 13),
  203: datetime.date(2020, 2, 13),
  204: datetime.date(2020, 2, 13)},
 'time_of_day': {0: 4,
  1: 2,
  2: 2,
  3: 4,
  4: 4,
  5: 2,
  200: 4,
  201: 1,
  202: 2,
  203: 3,
  204: 4},
 'depressed': {0: 3,
  1: 3,
  2: 4,
  3: 4,
  4: 4,
  5: 4,
  200: 3,
  201: 3,
  202: 1,
  203: 2,
  204: 2},
 'prev_night_sleep': {0: 0.0,
  1: 0.0,
  2: 0.0,
  3: 0.0,
  4: 0.0,
  5: 11.35,
  200: 7.166666666666667,
  201: 10.18333333333333,
  202: 10.18333333333333,
  203: 10.18333333333333,
  204: 10.18333333333333}}

【问题讨论】:

  • 我很难理解数据和预期输出。你能否重新格式化它并将其缩小到重现问题所需的最小值,然后给出所需输出的示例。
  • 这是一个包含 5 个观测值和 6 个变量的数据框,所以它确实已经被缩小了。我可以添加预期的输出。
  • 为什么对于pid=21date=2019-12-08time_of_day 向量不应该是简单的[1, 2, 3, 4](按datestamp 的顺序)?
  • 不确定我是否完全理解您的问题,但我认为您假设参与者会完成每项调查(尤其是在发送调查时)。通常,参与者错过访问,不完成问卷;因此缺少数据。或者,在另一种情况下,他们在第三个时间点完成了他们应该在第二个时间点完成的事情,所以它(在这种情况下)注册为 3,而它应该是 2。理想情况下,它会注册所有预期的时间点,然后就会被填满(不是我的设计)。
  • 目前正试图弄清楚如何在数据从未完成的适当时间段创建 NA。

标签: python pandas


【解决方案1】:

试试:

df['time_of_day'] = df.groupby(['pid', 'date']).cumcount().add(1)
print(df)

    pid           datestamp        date  time_of_day  depressed  prev_night_sleep
0    21 2019-12-07 21:33:11  2019-12-07            1          3          0.000000
1    21 2019-12-08 13:32:16  2019-12-08            1          3          0.000000
2    21 2019-12-08 13:33:41  2019-12-08            2          4          0.000000
3    21 2019-12-08 19:54:22  2019-12-08            3          4          0.000000
4    21 2019-12-08 19:55:24  2019-12-08            4          4          0.000000
5    21 2019-12-09 12:11:24  2019-12-09            1          4         11.350000
200  26 2020-02-12 20:16:33  2020-02-12            1          3          7.166667
201  26 2020-02-13 08:37:21  2020-02-13            1          3         10.183333
202  26 2020-02-13 13:24:20  2020-02-13            2          1         10.183333
203  26 2020-02-13 17:05:27  2020-02-13            3          2         10.183333
204  26 2020-02-13 20:02:12  2020-02-13            4          2         10.183333

【讨论】:

  • 什么?...这很简单。谢谢!我认为这要复杂得多。 cumcount().add(1) 是怎么回事?这如何返回重复的先前值?
  • 请花时间检查这是否真的是您需要的。我在time_of_day 列中更改了很多内容。事实上,我不在乎重复,我按(pid,日期)对行进行分组,并为每条记录(最多 4 个)设置一个从 0 到 3 的数字(cumcount)并加 1。
  • 是的,这不是我想要的。它正在将不重复的值更改为其他值。
  • 所以 IIUC,对于 [2, 2, 4, 4],结果应该是 [2-1, 2, 4-1, 4] 所以 [1, 2, 3, 4]。但是,如果对于 time_of_day,您有 [1, 2, 3, 3],结果应该是 [1, 2, 3, 3+1] 所以 [1, 2, 3, 4]?对于这种情况,dput 的输出是什么?
  • 感谢您对 @Corallien 的帮助。是的,您有这个权利,只是在您的示例 [4-3] 中更正不是 1,但在您提供的后续列表中,它是正确的 [1,2,3,4]。我不知道你会有 [1,2,3,3] 的实例;目前,我认为我们可以排除这种情况,因为它肯定是异常情况,我需要进一步研究。
【解决方案2】:

我没有找到一个非常简单的方法。但是下面的代码应该适用于这个例子。

import pandas as pd
import datetime
from pandas import Timestamp
df_dict = {'pid': {0: '21',
  1: '21',
  2: '21',
  3: '21',
  4: '21',
  5: '21',
  200: '26',
  201: '26',
  202: '26',
  203: '26',
  204: '26'},
 'datestamp': {0: Timestamp('2019-12-07 21:33:11'),
  1: Timestamp('2019-12-08 13:32:16'),
  2: Timestamp('2019-12-08 13:33:41'),
  3: Timestamp('2019-12-08 19:54:22'),
  4: Timestamp('2019-12-08 19:55:24'),
  5: Timestamp('2019-12-09 12:11:24'),
  200: Timestamp('2020-02-12 20:16:33'),
  201: Timestamp('2020-02-13 08:37:21'),
  202: Timestamp('2020-02-13 13:24:20'),
  203: Timestamp('2020-02-13 17:05:27'),
  204: Timestamp('2020-02-13 20:02:12')},
 'date': {0: datetime.date(2019, 12, 7),
  1: datetime.date(2019, 12, 8),
  2: datetime.date(2019, 12, 8),
  3: datetime.date(2019, 12, 8),
  4: datetime.date(2019, 12, 8),
  5: datetime.date(2019, 12, 9),
  200: datetime.date(2020, 2, 12),
  201: datetime.date(2020, 2, 13),
  202: datetime.date(2020, 2, 13),
  203: datetime.date(2020, 2, 13),
  204: datetime.date(2020, 2, 13)},
 'time_of_day': {0: 4,
  1: 2,
  2: 2,
  3: 4,
  4: 4,
  5: 2,
  200: 4,
  201: 1,
  202: 2,
  203: 3,
  204: 4},
 'depressed': {0: 3,
  1: 3,
  2: 4,
  3: 4,
  4: 4,
  5: 4,
  200: 3,
  201: 3,
  202: 1,
  203: 2,
  204: 2},
 'prev_night_sleep': {0: 0.0,
  1: 0.0,
  2: 0.0,
  3: 0.0,
  4: 0.0,
  5: 11.35,
  200: 7.166666666666667,
  201: 10.18333333333333,
  202: 10.18333333333333,
  203: 10.18333333333333,
  204: 10.18333333333333}}


data = pd.DataFrame.from_dict(df_dict)
to_change = data[data.duplicated(subset=['pid', 'date', 'time_of_day'], keep=False)].sort_values(['date', 'time_of_day'])

new_time_of_day = []
prev_t = 0
prev_d = ''
count = 1
for d, t in zip(to_change['date'], to_change['time_of_day']):
    if d == prev_d and t==prev_t:
        new_time_of_day.append(f'{t}-{count}')
        count+=1
    else:
        new_time_of_day.append(f'{t}')
        count = 1
        
    prev_d = d
    prev_t = t
    
del to_change['time_of_day']
to_change.insert(3, 'time_of_day', new_time_of_day)
data = data.drop_duplicates(subset=['pid', 'date', 'time_of_day'], keep=False)
data = pd.concat([to_change, data]).sort_index()
data.head(20)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    相关资源
    最近更新 更多