我一直在阅读很多关于merge()和join()方法的帖子pandas.DataFrames,并针对我自己的问题尝试了这些,但还没有完全找到解决方案。
我有一个非常大的数据文件 (.csv),其中包含各种 ID 的每小时消耗量。我想汇总每个月每个 ID 的消耗量。
由于内存限制,我需要分read_csv块处理每小时消耗文件(使用chunk_size选项),并最终加载了几个月的 ID 消耗数据帧,例如:
df1 =
Month Dec Nov
ID
XXX 4.0 1.0
YYY 8.0 3.0
ZZZ 4.0 1.0
df2 =
Month Dec Nov Oct
ID
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
YYY 5.0 5.0 0.0
Run Code Online (Sandbox Code Playgroud)
为这篇文章生成:
df1 = pd.DataFrame({'ID': ['XXX','XXX','YYY','YYY','ZZZ','ZZZ'],
'Month': ['Nov','Dec']*3,
'Consumption': [1.0,4.0,3.0,8.0,1.0,4.0]})
df1 = df1.pivot(index='ID', columns='Month', values='Consumption')
df2 = pd.DataFrame({'ID': ['AAA','AAA','AAA','YYY','YYY','YYY','BBB','BBB','BBB'],
'Month': ['Oct','Nov','Dec']*3,
'Consumption': [9,7,1,0,5,5,2,np.nan,0]})
df2 = df2.pivot(index='ID', columns='Month', values='Consumption')
Run Code Online (Sandbox Code Playgroud)
请注意,消耗0.0和之间存在差异NaN。0.0表示0.0当月至少有一个消费读数,但NaN表示根本没有记录消费值,在这种情况下,不能假设为 0。为了我的目的,这种差异必须保持明显。
因为数据文件是分块处理的,所以有一些 ID 出现在多个 DataFrame 中,例如YYY,对于这些 ID,有时月份也会重叠,例如NovID YYY。在这种情况下,上半月的消费是 in df1,下半月是 in df2。
因此,为了聚合消耗,我需要按“ID”合并这些数据帧,并在重叠的“月”中汇总值。
直接对DataFrame求和会产生许多 NaN:
df1 + df2 =
Month Dec Nov Oct
ID
AAA NaN NaN NaN
BBB NaN NaN NaN
XXX NaN NaN NaN
YYY 13.0 8.0 NaN
ZZZ NaN NaN NaN
Run Code Online (Sandbox Code Playgroud)
我认为这是因为当它的 IDs/Monthsdf1没有出现时,df2它返回一个 NaN。
外部合并为重叠月份生成后缀列:
df1.merge(df2,how='outer',on='ID') =
Month Dec_x Nov_x Dec_y Nov_y Oct
ID
XXX 4.0 1.0 NaN NaN NaN
YYY 8.0 3.0 5.0 5.0 0.0
ZZZ 4.0 1.0 NaN NaN NaN
AAA NaN NaN 1.0 7.0 9.0
BBB NaN NaN 0.0 NaN 2.0
Run Code Online (Sandbox Code Playgroud)
我也不combine_first能做我想做的事。
我想要的是中间的东西,看起来像这样:
Month Dec Nov Oct
ID
XXX 4.0 1.0 NaN
YYY 13.0 8.0 0.0
ZZZ 4.0 1.0 NaN
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
Run Code Online (Sandbox Code Playgroud)
重叠月份的总和使得x + NaN = x,NaN + y = y和NaN + NaN = NaN。
我可以看到的一种解决方案是进行合并,然后对重叠的列求和,忽略 NaN:
df3 = df1.merge(df2,how='outer',on='ID',suffixes=['','_x'])
overlapping_months_sufx = df3.columns.values[df3.columns.str.endswith('_x')]
for mnth_sufx in overlapping_months_sufx:
mnth = mnth_sufx[:-2]
df3[mnth][df3[mnth_sufx].notnull()] = df3[mnth].fillna(0) + df3[mnth_sufx]
df3=df3.drop(columns=mnth_sufx)
df3 =
Month Dec Nov Oct
ID
XXX 4.0 1.0 NaN
YYY 13.0 8.0 0.0
ZZZ 4.0 1.0 NaN
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
Run Code Online (Sandbox Code Playgroud)
鉴于此数据集的大小,最好能以最有效的方式汇总所有这些数据。有没有更好的方法来做到这一点,也许只需一步?
谢谢,克里斯
这是一个尝试。如果我理解正确,请发表评论。
鉴于:
>>> df1
Month Dec Nov
ID
XXX 4.0 1.0
YYY 8.0 3.0
ZZZ 4.0 1.0
>>> df2
Month Dec Nov Oct
ID
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
YYY 5.0 5.0 0.0
Run Code Online (Sandbox Code Playgroud)
解决方案:
>>> pd.concat([df1, df2]).reset_index().groupby('ID', sort=False).sum(min_count=1)
Dec Nov Oct
ID
XXX 4.0 1.0 NaN
YYY 13.0 8.0 0.0
ZZZ 4.0 1.0 NaN
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
Run Code Online (Sandbox Code Playgroud)
解释:
级联只是把df2下df1。
>>> cat = pd.concat([df1, df2])
>>> cat
Dec Nov Oct
ID
XXX 4.0 1.0 NaN
YYY 8.0 3.0 NaN
ZZZ 4.0 1.0 NaN
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
YYY 5.0 5.0 0.0
Run Code Online (Sandbox Code Playgroud)
reset_index 将索引移动到列中。
>>> cat = cat.reset_index()
>>> cat
ID Dec Nov Oct
0 XXX 4.0 1.0 NaN
1 YYY 8.0 3.0 NaN
2 ZZZ 4.0 1.0 NaN
3 AAA 1.0 7.0 9.0
4 BBB 0.0 NaN 2.0
5 YYY 5.0 5.0 0.0
Run Code Online (Sandbox Code Playgroud)
我这样做是为了有一个带有名称的列'ID',我可以通过它对其他值进行分组。groupby('ID', sort=False)创建列中共享相同值的行组'ID'(并sort=False确保最终结果中的行未排序以匹配您的输出)。
我们可以像这样检查组大小:
>>> cat.groupby('ID', sort=False).size()
ID
XXX 1
YYY 2
ZZZ 1
AAA 1
BBB 1
dtype: int64
Run Code Online (Sandbox Code Playgroud)
如您所见,我们只有一组大小为 2 的组,因为'YYY'ID 是唯一重复的组。
sum(min_count=1)像这样工作:每个组中的值相对于它们的列相加。该参数min_count=1确保NaN在NaN汇总时产生一系列所有值。
>>> cat.groupby('ID', sort=False).sum(min_count=1)
Dec Nov Oct
ID
XXX 4.0 1.0 NaN
YYY 13.0 8.0 0.0
ZZZ 4.0 1.0 NaN
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
Run Code Online (Sandbox Code Playgroud)
演示min_count:
>>> s = pd.Series([np.nan, np.nan])
>>> s
0 NaN
1 NaN
dtype: float64
>>>
>>> s.sum()
0.0
>>> s.sum(min_count=1)
nan
>>> s[0] = 1
>>> s
0 1.0
1 NaN
dtype: float64
>>> s.sum()
1.0
>>> s.sum(min_count=1)
1.0
>>> s.sum(min_count=2)
nan
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2449 次 |
| 最近记录: |