使用Pandas将列表列展开为值和天数

时间:2018-01-04 18:37:39

标签: python pandas

我正在尝试解压缩包含具有值列表的列的数据集。每个列表中的第一个位置表示在"日期"中的日期所采取的测量。柱。下一个位置是前一天的测量,依此类推(最多30天)。这些列表的长度并不相同,但count_users中列表的长度将等于count_samples中的长度。

目标是获取数据,使每个日期每个名称有1行,每行中有count_users和count_samples的单个度量。

换句话说,阵列的位置需要映射到特定的日期,每个名称的测量值应该相加每天。

原始数据如下所示:

Name     Date       count_users      count_samples
A     2017-10-20   [0,0,1,2,2,4]     [1,2,1,1,1,3]
A     2017-10-18   [5,2,0,0,0,0]     [1,2,1,1,1,3]
B     2017-11-24   [0,0,0,0,4]       [1,1,1,1,3]
C     2017-09-02   []                []
D     2017-10-30   [0,0,2,4]         [1,2,1,1]

结果看起来应该是这样的:

Name  Date          count_users      count_samples
A     2017-10-20    0                1
A     2017-10-19    0                2
A     2017-10-18    6                2
A     2017-10-17    4                3
A     2017-10-16    2                2
A     2017-10-15    4                4
A     2017-10-14    0                1
A     2017-10-13    0                3

有人可以推荐一个解决方案吗?

更新dict风格的数据:

{'Date': {0: Timestamp('2017-10-20 00:00:00'),
  1: Timestamp('2017-10-18 00:00:00'),
  2: Timestamp('2017-11-24 00:00:00'),
  3: Timestamp('2017-09-02 00:00:00'),
  4: Timestamp('2017-10-30 00:00:00')},
 'Name': {0: 'A', 1: 'A', 2: 'B', 3: 'C', 4: 'D'},
 'count_samples': {0: [1, 2, 1, 1, 1, 3],
  1: [1, 2, 1, 1, 1, 3],
  2: [1, 1, 1, 1, 3],
  3: [],
  4: [1, 2, 1, 1]},
 'count_users': {0: [0, 0, 1, 2, 2, 4],
  1: [5, 2, 0, 0, 0, 0],
  2: [0, 0, 0, 0, 4],
  3: [],
  4: [0, 0, 2, 4]}}

2 个答案:

答案 0 :(得分:2)

有点难以得到它

New_df=pd.DataFrame({'Date':np.concatenate(np.array([pd.date_range(end=x,periods=y,freq='D')[::-1] for x,y in zip(df.Date,df.count_samples.apply(len))])),
           'Name':df.Name.repeat(df.count_samples.apply(len)),
           'count_samples':np.concatenate(df.count_samples.values),
           'count_users':np.concatenate(df.count_users.values)})

New_df.groupby(['Name','Date'],as_index=False).sum().sort_values(['Name','Date'],ascending=[True,False])
Out[458]: 
   Name       Date  count_samples  count_users
7     A 2017-10-20            1.0          0.0
6     A 2017-10-19            2.0          0.0
5     A 2017-10-18            2.0          6.0
4     A 2017-10-17            3.0          4.0
3     A 2017-10-16            2.0          2.0
2     A 2017-10-15            4.0          4.0
1     A 2017-10-14            1.0          0.0
0     A 2017-10-13            3.0          0.0
12    B 2017-11-24            1.0          0.0
11    B 2017-11-23            1.0          0.0
10    B 2017-11-22            1.0          0.0
9     B 2017-11-21            1.0          0.0
8     B 2017-11-20            3.0          4.0
16    D 2017-10-30            1.0          0.0
15    D 2017-10-29            2.0          0.0
14    D 2017-10-28            1.0          2.0
13    D 2017-10-27            1.0          4.0

答案 1 :(得分:1)

你可以试试这个。

  • 将每行解包到数据帧然后
  • 然后使用pd.concat粘合。
  • 最后,使用groupby对同一日期的值求和。

注意,在此示例中,count_userscount_samples是字符串,我使用literal_eval将其转换为列表。如果已经有一个列表,你应该摆脱literal_eval

from ast import literal_eval
def unpack(row):
    l = len(literal_eval(row.count_users))
    date_index = pd.date_range(end=row.Date, periods=l)
    date_index = date_index[::-1]  # reverse it
    df = pd.DataFrame({"Name": [row.Name for _ in range(l)],
                       "count_users": literal_eval(row.count_users), 
                       "count_samples": literal_eval(row.count_samples)})
    df.set_index(date_index, inplace=True)
    return df

df_temp = pd.concat([unpack(row) for idx, row in df.iterrows()])
df_wanted = df_temp.reset_index().groupby(["index", "Name"]).sum()

结果

enter image description here

对于pd.date_range,您可以告诉它end=LAST_DATE的最后日期,并告诉它您需要从LAST_DATE向后period=LENGTH_DATES_YOU_NEED多少天。