【问题标题】:Python Data manipulation: Duplicate and Average row and column values using datesPython数据操作:使用日期重复和平均行和列值
【发布时间】:2018-08-29 20:30:49
【问题描述】:

您好,我有一个格式如下的数据集:

复制数据的代码:

import pandas as pd
d1 = {'Year': 
['2008','2008','2008','2008','2008','2008','2008','2008','2008','2008'],
  'Month':['1','1','2','6','7','8','8','11','12','12'],
'Day':['6','22','6','18','3','10','14','6','16','24'],
'Subject_A':['','30','','','','35','','','',''],
'Subject_B':['','','','','','','','40','',''],
'Subject_C': ['','','','','','65','','50','','']}
d1 = pd.DataFrame(d1)

我将数字输入为字符串以显示空白单元格

前三列表示日期(年、月和日),以下列表示个人(我的实际数据文件由大约 300 行和大约 1000 个主题组成。我在这里展示了一部分数据)。

列值是指快速消费品产品的支出。 我想做的是:

第 1 部分(起点和终点)

a) 对于每个人,找到第一次观察并复制至少前六个月的第一次观察的值。例如:主题 C 的第一次观察是在 2008 年 8 月 10 日。在这种情况下,我希望 2008 年 6 月 10 日的所有行都等于主题 C 的 65(大约 2/12/2008 是截止日期。因此,我们将 Subject_C 的列从顶部数第三个单元格留空)。

b) 找到最后一次观察并在接下来的 3 个月内重复最后一次观察。例如对于 Subject_A,我们重复 35 两次(直到 2008 年 11 月 6 日)。

请参考下图突出显示的单元格及其解决方案。

第二部分 - (中间的行)

接下来我想做两件事(我需要分别做以下三个步骤,而不是一次完成):

对于像 Subject_A 这样的个人,找到两个依次出现的观察值(30 和 35)。

i) 使用两个观察值的平均值。在这种情况下,我们将在四行中有 32.5,而不用关心时间。

例如:

ii) 求两次观测之间的总时间并取时间的平均值。对于时间段的前半部分,分配第一个值,对于后半部分,分配第二个值。例如 - 对于主题 1,01/22/208 和 08/10/2008 之间的总天数为 201 天。对于前 201/2 = 100.5 天,将值 30 分配给 Subject_A,对于剩余的值分配 35。在这种情况下,Subject_A 和 Subject_C 的列将如下所示:

最终的数据集将使用 (a), (b) & (i) 或 (a), (b) & (ii)

最终数据 I [使用 a,b 和 i]

最终数据 II [使用 a,b 和 ii]

我将不胜感激。提前致谢。如果步骤不清楚,请告诉我。

跟进问题和问题

感谢@Juan 最初的回答。这是我的后续问题。假设 Subject_A 有超过 2 个观察值(下面示例数据的代码)。我们能否扩展此代码以包含两个以上的观察结果?

import pandas as pd
d1 = {'Year': 
['2008','2008','2008','2008','2008','2008','2008','2008','2008','2008'],
  'Month':['1','1','2','6','7','8','8','11','12','12'],
'Day':['6','22','6','18','3','10','14','6','16','24'],
'Subject_A':['','30','','45','','35','','','',''],
'Subject_B':['','','','','','','','40','',''],
'Subject_C': ['','','','','','65','','50','','']}
d1 = pd.DataFrame(d1)

问题 对于当前代码,我发现第二部分 (ii) 存在问题。这是我得到的输出:

这实际上是在正确的轨道上。 35 以上的两个单元格似乎没有更新。我这边有什么问题吗?也是和以前一样的问题,我们能否将其扩展到>2个观察的情况?

【问题讨论】:

  • 我认为最好将其拆分为三个问题,并让每个问题独立。
  • 我意识到这可能是一个很长的问题。我会记住这一点,同时在这里提出未来的问题。我很抱歉。我应该为每个部分提出单独的问题。

标签: python pandas data-manipulation data-cleaning


【解决方案1】:

这里是主题 A 的代码解决方案。应该与其他主题一起使用:

d1 = {'Year': 
['2008','2008','2008','2008','2008','2008','2008','2008','2008','2008'],
  'Month':['1','1','2','6','7','8','8','11','12','12'],
'Day':['6','22','6','18','3','10','14','6','16','24'],
'Subject_A':['','30','','45','','35','','','',''],
'Subject_B':['','','','','','','','40','',''],
'Subject_C': ['','','','','','65','','50','','']}
d1 = pd.DataFrame(d1)
d1 = pd.DataFrame(d1)
## Create a variable named date
d1['date']= pd.to_datetime(d1['Year']+'/'+d1['Month']+'/'+d1['Day'])
# convert to float, to calculate mean
d1['Subject_A'] = d1['Subject_A'].replace('',np.nan).astype(float)
# index of the not null rows
subja = d1['Subject_A'].notnull()

### max and min index row with notnull value
max_id_subja = d1.loc[subja,'date'].idxmax()
min_id_subja = d1.loc[subja,'date'].idxmin()
### max and min date for Sub A with notnull value
max_date_subja = d1.loc[subja,'date'].max()
min_date_subja = d1.loc[subja,'date'].min()
### value for max and min date
max_val_subja = d1.loc[max_id_subja,'Subject_A']
min_val_subja = d1.loc[min_id_subja,'Subject_A']
#### Cutoffs
min_cutoff = min_date_subja-pd.Timedelta(6, unit='M')
max_cutoff = max_date_subja+pd.Timedelta(3, unit='M')

## PART I.a
d1.loc[(d1['date']<min_date_subja) & (d1['date']>min_cutoff),'Subject_A'] = min_val_subja
## PART I.b
d1.loc[(d1['date']>max_date_subja) & (d1['date']<max_cutoff),'Subject_A'] = max_val_subja
## PART II
d1_2i = d1.copy()
d1_2ii = d1.copy()

lower_date = min_date_subja
lower_val = min_val_subja.copy()
next_dates_index = d1_2i.loc[(d1['date']>min_date_subja) & subja].index
for N in next_dates_index:
    next_date = d1_2i.loc[N,'date']
    next_val =  d1_2i.loc[N,'Subject_A']
    #PART II.i
    d1_2i.loc[(d1['date']>lower_date) & (d1['date']<next_date),'Subject_A'] = np.mean([lower_val,next_val])
    #PART II.ii
    mean_time_a = pd.Timedelta((next_date-lower_date).days/2, unit='d')
    d1_2ii.loc[(d1['date']>lower_date) & (d1['date']<=lower_date+mean_time_a),'Subject_A'] = lower_val
    d1_2ii.loc[(d1['date']>lower_date+mean_time_a) & (d1['date']<=next_date),'Subject_A'] = next_val
    lower_date = next_date
    lower_val = next_val
print(d1_2i)
print(d1_2ii)

【讨论】:

  • 谢谢@Juan。该代码适用于第一部分 (a) 和第一部分 (b)。然而,对于第 2 (i) 部分,当前设置在有两个观察值时有效。我相信这是因为当前代码使用了最大值和最小值。如果有超过 2 个观察结果,您能提供帮助吗?此外,代码在第 2 部分 (ii) 中也不能完全正常工作。我将在我的原始问题中附上结果和后续问题,因为我无法在此处附上 jpg。再次非常感谢。
  • 我编辑了答案以包含超过 2 个观察结果,但仅在主题 A 中进行了测试。
  • 像魅力一样工作。我在几个不同的列上对其进行了测试。太感谢了。 @胡安
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-03
  • 2017-03-10
  • 1970-01-01
  • 2020-12-26
  • 2020-01-08
  • 1970-01-01
相关资源
最近更新 更多