Python Pandas:将数据从一个数据帧归一化到另一个数据帧

时间:2017-10-01 02:35:34

标签: python pandas dataframe

我有一个Pandas数据框,您可能会将其描述为“规范化”。出于显示目的,我想“去标准化”数据。也就是说,我想将一些数据分布在多个键值上,我希望将它们放在输出记录的同一行上。有些记录在组合时需要求和。 (旁白:如果有人比“非规范化”有更好的术语,请对这个问题进行编辑,或者在评论中这样说。)

我正在使用包含许多列的pandas数据框,因此我将在下面向您展示简化版本。

以下代码设置(几乎)规范化的源数据帧。 (注意,我正在寻找关于第二个代码块的建议,这个代码块只是为了提供一些上下文。)与我的实际数据类似,识别数据中有一些重复,有些数字需要求和:

import pandas as pd

dates = pd.date_range('20170701', periods=21)
datesA1 = pd.date_range('20170701', periods=11)
datesB1 = pd.date_range('20170705', periods=9)
datesA2 = pd.date_range('20170708', periods=10)
datesB2 = pd.date_range('20170710', periods=11)
datesC1 = pd.date_range('20170701', periods=5)
datesC2 = pd.date_range('20170709', periods=9)

cols=['Date','Type','Count']

df_A1 = pd.DataFrame({'Date':datesA1,
                      'Type':'Apples',
                      'Count': np.random.randint(30,size=11)})
df_A2 = pd.DataFrame({'Date':datesA2,
                      'Type':'Apples',
                      'Count': np.random.randint(30,size=10)})
df_B1 = pd.DataFrame({'Date':datesB1,
                      'Type':'Berries',
                      'Count': np.random.randint(30,size=9)})
df_B2 = pd.DataFrame({'Date':datesB2,
                      'Type':'Berries',
                      'Count': np.random.randint(30,size=11)})
df_C1 = pd.DataFrame({'Date':datesC1,
                      'Type':'Canteloupes',
                      'Count': np.random.randint(30,size=5)})
df_C2 = pd.DataFrame({'Date':datesC2,
                      'Type':'Canteloupes',
                      'Count': np.random.randint(30,size=9)})

frames = [df_A1, df_A2, df_B1, df_B2, df_C1, df_C2]

dat_fra_source = pd.concat(frames)

此外,以下代码实现了我的意图。源数据框每个日期和水果类型(A,B和C)有多行。目标数据每天只有一行,总和为A,B和C.

dat_fra_dest = pd.DataFrame(0, index=dates, columns=['Apples','Berries','Canteloupes'])

for index,row in dat_fra_source.iterrows():
    dat_fra_dest.at[row['Date'],row['Type']]+=row['Count']

我的问题是,是否有更简洁的方法:不需要零初始化和/或对整个数据帧而不是逐行操作的方式。我也怀疑我有一个有效的实施。我还要注意,虽然我只是在简化示例中处理“count”,但我的实际示例中还有其他列。认为对于A,B和C,不仅有计数,还有重量和体积。

2 个答案:

答案 0 :(得分:6)

选项1

dat_fra_source.groupby(['Date','Type']).sum().unstack().fillna(0)

Out[63]: 
            Count                    
Type       Apples Berries Canteloupes
Date                                 
2017-07-01   13.0     0.0        24.0
2017-07-02   18.0     0.0        16.0
2017-07-03   11.0     0.0        29.0
2017-07-04   13.0     0.0         7.0
2017-07-05   24.0    11.0        23.0
2017-07-06    6.0     4.0         0.0
2017-07-07   29.0    26.0         0.0
2017-07-08   31.0    19.0         0.0
2017-07-09   38.0    17.0        26.0
2017-07-10   57.0    54.0         1.0
2017-07-11    4.0    41.0        10.0
2017-07-12   16.0    28.0        23.0
2017-07-13   25.0    20.0        20.0
2017-07-14   19.0     6.0        15.0
2017-07-15    6.0    22.0         7.0
2017-07-16   16.0     0.0         5.0
2017-07-17   29.0     7.0         4.0
2017-07-18    0.0    21.0         0.0
2017-07-19    0.0    19.0         0.0
2017-07-20    0.0     8.0         0.0

选项2

pd.pivot_table(dat_fra_source,index=['Date'],columns=['Type'],values='Count',aggfunc=sum).fillna(0)
Out[75]: 
Type        Apples  Berries  Canteloupes
Date                                    
2017-07-01    13.0      0.0         24.0
2017-07-02    18.0      0.0         16.0
2017-07-03    11.0      0.0         29.0
2017-07-04    13.0      0.0          7.0
2017-07-05    24.0     11.0         23.0
2017-07-06     6.0      4.0          0.0
2017-07-07    29.0     26.0          0.0
2017-07-08    31.0     19.0          0.0
2017-07-09    38.0     17.0         26.0
2017-07-10    57.0     54.0          1.0
2017-07-11     4.0     41.0         10.0
2017-07-12    16.0     28.0         23.0
2017-07-13    25.0     20.0         20.0
2017-07-14    19.0      6.0         15.0
2017-07-15     6.0     22.0          7.0
2017-07-16    16.0      0.0          5.0
2017-07-17    29.0      7.0          4.0
2017-07-18     0.0     21.0          0.0
2017-07-19     0.0     19.0          0.0
2017-07-20     0.0      8.0          0.0

假设你有列vol和重量

dat_fra_source['vol']=2
dat_fra_source['weight']=2
dat_fra_source.groupby(['Date','Type']).apply(lambda x: sum(x['vol']*x['weight']*x['Count'])).unstack().fillna(0)
Out[88]: 
Type        Apples  Berries  Canteloupes
Date                                    
2017-07-01    52.0      0.0         96.0
2017-07-02    72.0      0.0         64.0
2017-07-03    44.0      0.0        116.0
2017-07-04    52.0      0.0         28.0
2017-07-05    96.0     44.0         92.0
2017-07-06    24.0     16.0          0.0
2017-07-07   116.0    104.0          0.0
2017-07-08   124.0     76.0          0.0
2017-07-09   152.0     68.0        104.0
2017-07-10   228.0    216.0          4.0
2017-07-11    16.0    164.0         40.0
2017-07-12    64.0    112.0         92.0
2017-07-13   100.0     80.0         80.0
2017-07-14    76.0     24.0         60.0
2017-07-15    24.0     88.0         28.0
2017-07-16    64.0      0.0         20.0
2017-07-17   116.0     28.0         16.0
2017-07-18     0.0     84.0          0.0
2017-07-19     0.0     76.0          0.0
2017-07-20     0.0     32.0          0.0

答案 1 :(得分:2)

使用pd.crosstab(dat_fra_source['Date'], dat_fra_source['Type'], dat_fra_source['Count'], aggfunc='sum', dropna=False).fillna(0)

Type        Apples  Berries  Canteloupes
Date                                    
2017-07-01    19.0      0.0          4.0
2017-07-02    25.0      0.0          4.0
2017-07-03    11.0      0.0         26.0
2017-07-04    27.0      0.0          8.0
2017-07-05     8.0     18.0         12.0
2017-07-06    10.0     11.0          0.0
2017-07-07     6.0     17.0          0.0
2017-07-08    10.0      5.0          0.0
2017-07-09    51.0     25.0         16.0
2017-07-10    31.0     23.0         21.0
2017-07-11    35.0     40.0         10.0
2017-07-12    16.0     30.0          9.0
2017-07-13    13.0     23.0         20.0
2017-07-14    21.0     26.0         27.0
2017-07-15    20.0     17.0         19.0
2017-07-16    12.0      4.0          2.0
2017-07-17    27.0      0.0          5.0
2017-07-18     0.0      5.0          0.0
2017-07-19     0.0     26.0          0.0
2017-07-20     0.0      6.0          0.0

输出:

{{1}}