根据python中另一个df中的日期数据填写值
我想通过匹配日期数据将补充信息从df2添加到df1 df1是主数据帧:根据python中另一个df中的日期数据填写值,python,pandas,datetime,Python,Pandas,Datetime,我想通过匹配日期数据将补充信息从df2添加到df1 df1是主数据帧: x0 x1 x2 x3 x4 x5 ... x10000 Date 1 40 31.05 25.5 25.5 25.5 25 ... 33 2013-11-13 2 35 35.75 36.5 36.5 3
x0 x1 x2 x3 x4 x5 ... x10000 Date
1 40 31.05 25.5 25.5 25.5 25 ... 33 2013-11-13
2 35 35.75 36.5 36.5 36.5 36.5 ... 29 2013-09-05
⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮
df2是我想添加到df1中的补充天气信息:
year month day maxtemp mintemp rainfall wind
2013 1 1 26.2 20.2 0 32.4
2013 1 2 22.9 20.3 0 10
2013 1 3 24.8 18.4 0 28.8
2013 1 4 26.6 18.3 0 33.5
2013 1 5 28.3 20.9 0 33.4
2013 1 6 28 21.6 0 32.8
2013 1 7 27.5 21.4 0 26.8
2013 1 8 42.3 20.9 0 25.5
2013 1 9 25 21.1 0 20.9
2013 1 10 25.4 20.2 0 14
⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮
我需要将从df2
中提取的maxtemp
、mintemp
、rainment
和wind
前100天的df2
数据,通过与df1
中的年
、月
、日
进行匹配,水平地添加到df1上每行的末尾。因此,Date
是第100天,而前99天是Date
之前的99天
预期产出:
x0 x1 x2 x3 x4 x5 ... x10000 Date max_t1...max_t100 min_t1...min_t100 rf1... rf100 w1 ... w100
1 40 31.05 25.5 25.5 25.5 25 ... 33 2013-01-01 26.2 ... 20.2 ... 0 ... 32.4...
2 35 35.75 36.5 36.5 36.5 36.5 ... 29 2013-01-03 24.8. ... 18.4 ... 0 ... 28.8
⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮
在哪里
max_t1, ..., max_t100 represent max temperature from day1 to day100(`Date` day);
min_t1, ..., min_t100 represent min temperature from day1 to day100(`Date` day);
rf1, ..., rf100 represent rainfall from day1 to day100(`Date` day);
w1, ..., w100 represent wind from day1 to day100(`Date` day).
这些是新添加的列名(因此总共将有400个新列)。我建议先在df2中创建400个新列,然后使用将其合并到df1中 分为两个问题: 问题1:计算过去x天的聚合值 回答 适用于您的情况:
In[1]: df2 = pd.DataFrame({"year": [2013, 2013, 2013, 2013, 2013],
"month": [1, 1, 1, 1, 1],
"day": [1, 2, 3, 4, 5],
"mintemp": [26.2, 22.9, 24.8, 11.2, 10],
"maxtemp": [28.2, 23.9, 25.8, 22.1, 12]})
# Create date column (type datetime64[ns])
df2["date"] = pd.to_datetime((df2[["year", "month", "day"]]))
# Add the 400 columns needed (I am only adding 2 as an example)
# If you change 2 to 100 you will get your 100
colnumber = 2
# Maxtemp
for i in range(1, colnumber + 1):
col_name = "max_t" + str(i)
df2[col_name] = df2.set_index("date").rolling(i).max()["maxtemp"].values
# Mintemp
for i in range(1, colnumber + 1):
col_name = "min_t" + str(i)
df2[col_name] = df2.set_index("date").rolling(i).min()["mintemp"].values
# TODO: Add rainfall and wind
In[2]:df2
Out[2]:
year month day mintemp maxtemp date max_t1 max_t2 min_t1 min_t2
0 2013 1 1 26.2 28.2 2013-01-01 28.2 NaN 26.2 NaN
1 2013 1 2 22.9 23.9 2013-01-02 23.9 28.2 22.9 22.9
2 2013 1 3 24.8 25.8 2013-01-03 25.8 25.8 24.8 22.9
3 2013 1 4 11.2 22.1 2013-01-04 22.1 25.8 11.2 11.2
4 2013 1 5 10.0 12.0 2013-01-05 12.0 22.1 10.0 10.0
问题2:使用日期列作为公共键水平合并两个数据帧
您必须首先将列转换为datetime(类似的答案),然后使用公共键合并df
In[3]:df1 = pd.DataFrame({"x0": [40, 35, 33, 38],
"x1": [31.05, 35.75, 22, 28],
"x1000": [33, 29, 20, 18],
"Date": ["2013-1-1", "2013-1-2", "2013-1-3", "2013-1-4"]})
# Creating common key with type datetime64[ns]
df1["date"] = pd.to_datetime(df1["Date"])
Out[3]:
x0 x1 x1000 Date date
0 40 31.05 33 2013-1-1 2013-01-01
1 35 35.75 29 2013-1-2 2013-01-02
2 33 22.00 20 2013-1-3 2013-01-03
3 38 28.00 18 2013-1-4 2013-01-04
In[4]: # Merging
df1.merge(df2, how="left", left_on=["date"], right_on=["date"])
Out[4]:
x0 x1 x1000 Date date year month day mintemp maxtemp max_t1 max_t2 min_t1 min_t2
0 40 31.05 33 2013-1-1 2013-01-01 2013 1 1 26.2 28.2 28.2 NaN 26.2 NaN
1 35 35.75 29 2013-1-2 2013-01-02 2013 1 2 22.9 23.9 23.9 28.2 22.9 22.9
2 33 22.00 20 2013-1-3 2013-01-03 2013 1 3 24.8 25.8 25.8 25.8 24.8 22.9
3 38 28.00 18 2013-1-4 2013-01-04 2013 1 4 11.2 22.1 22.1 25.8 11.2 11.2
编辑:添加了输出我假设df1中的日期列是datetime类型。如果不是,则转换它
从这些准备步骤开始:
nDays = 3
出于演示目的,我将其设置为仅3,但您可以将其更改为100
或者任何你想要的价值def fn(row):
d1 = row.Date
d2 = d1 + pd.Timedelta(nDays - 1, 'D')
return pd.Series(df2.loc[d1:d2].values.reshape((1, -1),
order='F').squeeze(), index=cols)
df1 = df1.join(df1.apply(fn, axis=1))
非常简洁,并且在很大程度上是泛美的解决方案
为了演示此解决方案的工作原理,我稍微更改了您的数据:
df1:
x0 x1 x2 x3 Date
0 40 31.05 25.5 25.5 2013-01-03
1 35 35.75 36.5 36.5 2013-01-07
df2(初始内容):
df2(转换后):
添加新列后,df1包含:
x0 x1 x2 x3 Date max_t1 max_t2 max_t3 min_t1 min_t2 \
0 40 31.05 25.5 25.5 2013-01-03 24.8 26.6 28.3 18.4 18.3
1 35 35.75 36.5 36.5 2013-01-07 27.5 42.3 25.0 21.4 20.9
min_t3 rf1 rf2 rf3 w1 w2 w3
0 20.9 1.0 2.0 3.0 28.8 33.5 33.4
1 21.1 5.0 6.0 7.0 26.8 25.5 20.9
在“100天前”注释后编辑
如果添加的行取自当前日期之前的100天,
更改fn函数中两个“边界日期”的设置方式。比如:
def fn(row):
d1 = row.Date - pd.Timedelta(nDays, 'D')
d2 = row.Date - pd.Timedelta(1, 'D')
return pd.Series(df2.loc[d1:d2].values.reshape((1, -1), order='F')
.squeeze(), index=cols)
如何避免增加行数
如果df2在某些日期包含多行,则加入
df1和df2导致输出行数增加
如果df2的某个日期有3行,则df1的行
使用此日期,结果将仅包含3行(日期相同)
为了避免这种情况,你必须“抑制”这种重复
最初我想到的是df2=df2.drop_duplicates(…),但是你写了
一行不能包含一组值,另一行不能包含另一组值,
因此,我们不能随意留下一行而删除另一行(从同一日期起)
解决这个问题的一个可能方法是在“日期索引”之后
创建时,您应该:
- 按索引对df2进行分组(每组将包含 特定日期)
- 计算每列的平均值(忽略可能的NaN值)
- 将结果保存回df2下
df2 = df2.groupby(level=0).mean()
然后,您可以加入(如上所述)和输出行的数量
不应该增长。是
rf1。。。rf100
0,1?@YusufBaktir不,它们是小数点后1位的数值,那么,您需要接下来100天的平均值还是其他什么?@YusufBaktir不是平均值,只需将相应的值从df2复制并粘贴到df1Oh,好的,新的列类似于max_t1,max_t2。。。最大值为100
。基本上,您希望在df1I中添加日期后的100天。当日期列未排序时,我还没有测试过这一点,因此您可能需要在应用于示例时对其进行排序。谢谢您提供了详细的答案。这是100天前而不是之后的日期
,很抱歉混淆了max_t2
的NaN
不应该是23.9
?这是以前的情况。之所以存在NaN,是因为在我注意到一些相邻的日期具有相同的值之前没有数据,例如,2013-01-04
的minu t1
和minu t2
都是11.2。有什么不对劲吗?我刚意识到应该是100天前,而不是日期之后。你能考虑一下吗?很抱歉造成混淆,在将旧的fn
替换为新的fn之后,我得到了这个TypeError:(-:'str'和'Timedelta''不支持的操作数类型,发生在索引0')
。我做错了吗?检查df1中的日期列是否为datetime类型。我一开始就写了,现在可以了!但当我将nDays
增加到100时,它返回了ValueError:列重叠但没有指定后缀:Index(['maxtemp1'、'maxtemp2'、'mintemp1'、'mintemp2'、'mintemp3'、'rainwall1'、'rainwall2'、'rainwall3'、'wind1'、'wind2'、'wind3'],dtype='object'))
必须在设置nDays值后执行指令设置cols。从您的消息(从1到3的数字)中,我看到您执行此指令时,nDays==3。
maxtemp mintemp rainfall wind
2013-01-01 26.2 20.2 0 32.4
2013-01-02 22.9 20.3 0 10.0
2013-01-03 24.8 18.4 1 28.8
2013-01-04 26.6 18.3 2 33.5
2013-01-05 28.3 20.9 3 33.4
2013-01-06 28.0 21.6 4 32.8
2013-01-07 27.5 21.4 5 26.8
2013-01-08 42.3 20.9 6 25.5
2013-01-09 25.0 21.1 7 20.9
2013-01-10 25.4 20.2 8 14.0
x0 x1 x2 x3 Date max_t1 max_t2 max_t3 min_t1 min_t2 \
0 40 31.05 25.5 25.5 2013-01-03 24.8 26.6 28.3 18.4 18.3
1 35 35.75 36.5 36.5 2013-01-07 27.5 42.3 25.0 21.4 20.9
min_t3 rf1 rf2 rf3 w1 w2 w3
0 20.9 1.0 2.0 3.0 28.8 33.5 33.4
1 21.1 5.0 6.0 7.0 26.8 25.5 20.9
def fn(row):
d1 = row.Date - pd.Timedelta(nDays, 'D')
d2 = row.Date - pd.Timedelta(1, 'D')
return pd.Series(df2.loc[d1:d2].values.reshape((1, -1), order='F')
.squeeze(), index=cols)
df2 = df2.groupby(level=0).mean()