使用 Python/Pandas 匹配样本对年度数据
Use Python/Pandas to Match Sample Pairs Yearly Data
虽然这听起来像是统计问题,但请耐心等待。
我从不同采样点收集的水样中得到了几种钙浓度。每月、每年、每隔一年在一些站点对水进行重新采样。
我想使用 Lindsey 和 Rupert (http://pubs.usgs.gov/sir/2012/5049/) 执行的 Wilcoxon-Pratt 符号秩检验来测量站点组钙浓度的年度和十年变化。为了进行测试,我想创建以一年(365 天的时间增量)或尽可能接近该时间范围分隔的数据对。成对的测量值应该有相同的月份,只是不同的年份。我每个站每个月只需要一对。我不希望对共享相同站点、月份和年份的样本的样本浓度进行平均。
这是我的数据示例:
https://raw.githubusercontent.com/inkenbrandt/IPython/master/Calcium_Samples.csv
SampleLocation CalciumConc_mgL
SampleDate
10/1/1947 0:00 USGS-09382000 66.0
10/15/1947 0:00 USGS-09382000 132.0
1/1/1948 0:00 USGS-09382000 130.0
1/15/1948 0:00 USGS-09382000 98.0
5/1/1948 0:00 USGS-09382000 82.0
5/15/1948 0:00 USGS-09382000 53.0
6/1/1948 0:00 USGS-09382000 142.0
9/1/1948 0:00 USGS-09382000 107.0
9/15/1948 0:00 USGS-09382000 59.0
10/1/1948 0:00 USGS-09382000 106.0
10/15/1948 0:00 USGS-09382000 102.0
5/15/1949 0:00 USGS-09382000 59.0
6/1/1949 0:00 USGS-09382000 50.0
6/15/1949 0:00 USGS-09382000 161.0
9/1/1949 0:00 USGS-09382000 82.0
9/15/1949 0:00 USGS-09382000 376.0
10/1/1949 0:00 USGS-09382000 210.0
10/15/1949 0:00 USGS-09382000 131.0
1/1/1950 0:00 USGS-09382000 132.0
... ... ...
9/20/1947 0:00 USGS-09288500 59.0
9/20/1947 0:00 USGS-09288500 59.0
6/9/1948 0:00 USGS-09288500 51.0
6/9/1948 0:00 USGS-09288500 51.0
9/29/1948 0:00 USGS-09288500 51.0
9/29/1948 0:00 USGS-09288500 51.0
9/10/1949 0:00 USGS-09288500 40.0
5/19/1941 0:00 USGS-09295000 33.0
6/16/1941 0:00 USGS-09295000 3.4
5/11/1947 0:00 USGS-09295000 42.0
6/22/1947 0:00 USGS-09295000 32.0
9/20/1947 0:00 USGS-09295000 97.0
6/9/1948 0:00 USGS-09295000 37.0
9/29/1948 0:00 USGS-09295000 126.0
9/10/1949 0:00 USGS-09295000 93.0
[429 rows x 2 columns]
我想生成一个看起来像这样的 Pandas 数据框:
SampleLocation SampleDate1 CaConc1 SampleDate2 CaConc2
USGS-09382000 10/1/1947 0:00 66.0 10/1/1948 0:00 106.0
USGS-09382000 10/15/1947 0:00 132.0 10/15/1948 0:00 102.0
USGS-09382000 5/15/1948 0:00 53.0 5/15/1949 0:00 59.0
... ... ... ... ...
USGS-09288500 9/20/1947 0:00 59.0 9/29/1948 0:00 51.0
我相信可以使用 Pandas 中的多索引功能来解决这个问题。到目前为止,我已经查看了以下 Whosebug 问题以帮助匹配日期和使用索引进行操作:
How to get the closest single row after a specific datetime index using Python Pandas
Pandas: how to plot yearly data on top of each other
我认为第二个 link 使用拆栈多索引非常接近,如果我愿意聚合,我也许可以执行此操作,但我正在努力避免这种情况。
此技术与其他想要分析季节性趋势数据的人相关,例如比较同一天或接近同一天的河流流量或累积降水量或温度。
这个方法有点乱,但我正在努力让它更健壮,以解决丢失的数据。
首先,我们将删除数据中的重复项,然后将日期转换为 Pandas 时间戳:
df = df.drop_duplicates()
df.SampleDate = [pd.Timestamp(ts) for ts in df.SampleDate]
然后让我们安排您的 DataFrame,以便它在一组唯一的日期上建立索引(列将是位置 ID):
df2 = df.pivot_table(values='CalciumConc_mgL',
index='SampleDate',
columns='SampleLocation').ffill()
我已经填写了值以使结果更可靠。您可能希望限制可能提前填充的天数(例如 .ffill(limit=30))。
现在我们可以将这个 DataFrame 移动 365 个日期:
df2_lagged = df2.shift(365)
为 df2 和 df2_lagged 叠加 SampleLocation:
df2 = pd.DataFrame(df2.stack('SampleLocation', dropna=False))
df2_lagged = df2_lagged.stack('SampleLocation', dropna=False)
现在将滞后数据合并到 df2。 DataFrame 具有完全相同的结构,因此您只需复制值即可:
df2['lagged_val'] = df2_lagged
最后,交换位置和日期并重命名列:
result = df2.swaplevel(0, 1)
result.columns = ['CalciumConc_mgL', 'CalciumConc_mgL_lagged_12m']
对样本数据使用 60 天滞后:
>>> result
result.tail(10)
CalciumConc_mgL CalciumConc_mgL_lagged_12m
SampleLocation SampleDate
USGS-421548113205301 1950-01-01 59 59
USGS-422818113225801 1950-01-01 59 NaN
USGS-423200113472601 1950-01-01 33 33
USGS-424006113355301 1950-01-01 62 54
USGS-424142113340901 1950-01-01 54 54
USGS-424348113242701 1950-01-01 40 NaN
USGS-424431113412301 1950-01-01 46 NaN
USGS-424511113291401 1950-01-01 38 38
USGS-424518113282002 1950-01-01 39 39
USGS-424659113433701 1950-01-01 39 39
并且仅索引位置 ID:
result = result.reset_index().set_index('SampleLocation')
>>> result.loc['USGS-09402500', :]
CalciumConc_mgL CalciumConc_mgL_lagged_12m
SampleDate
1941-05-18 NaN NaN
1941-05-19 NaN NaN
1941-06-16 NaN NaN
1941-10-01 102 NaN
1941-10-12 132 NaN
1941-10-21 119 NaN
1943-09-18 110 NaN
1943-10-01 138 NaN
1943-10-11 140 NaN
1943-10-12 140 NaN
1943-10-14 140 NaN
1943-10-21 156 NaN
1944-01-01 116 NaN
1944-01-11 126 NaN
1944-01-13 126 NaN
1944-01-21 133 NaN
1944-05-01 84 NaN
1944-05-11 84 NaN
1944-05-13 66 NaN
1944-05-15 66 NaN
1944-05-16 66 NaN
1944-05-21 57 NaN
1944-05-22 57 NaN
1944-06-01 58 NaN
1944-06-11 57 NaN
1944-06-21 57 NaN
1944-09-01 134 NaN
1944-09-11 122 NaN
1944-09-15 122 NaN
1944-09-18 122 NaN
... ... ...
1949-05-03 63 62
1949-05-11 63 62
1949-05-15 63 62
1949-05-21 57 62
1949-06-01 58 133
1949-06-09 58 128
1949-06-10 58 128
1949-06-11 74 128
1949-06-12 74 128
1949-06-13 74 124
1949-06-15 74 112
1949-06-21 67 123
1949-06-23 67 123
1949-06-30 67 123
1949-09-01 142 123
1949-09-09 142 123
1949-09-10 142 131
1949-09-11 140 106
1949-09-15 140 108
1949-09-21 146 108
1949-09-28 146 102
1949-10-01 156 102
1949-10-11 153 102
1949-10-13 153 68
1949-10-14 153 68
1949-10-15 153 63
1949-10-21 152 63
1949-10-27 152 63
1949-10-28 152 63
1950-01-01 128 60
虽然这听起来像是统计问题,但请耐心等待。
我从不同采样点收集的水样中得到了几种钙浓度。每月、每年、每隔一年在一些站点对水进行重新采样。
我想使用 Lindsey 和 Rupert (http://pubs.usgs.gov/sir/2012/5049/) 执行的 Wilcoxon-Pratt 符号秩检验来测量站点组钙浓度的年度和十年变化。为了进行测试,我想创建以一年(365 天的时间增量)或尽可能接近该时间范围分隔的数据对。成对的测量值应该有相同的月份,只是不同的年份。我每个站每个月只需要一对。我不希望对共享相同站点、月份和年份的样本的样本浓度进行平均。
这是我的数据示例: https://raw.githubusercontent.com/inkenbrandt/IPython/master/Calcium_Samples.csv
SampleLocation CalciumConc_mgL
SampleDate
10/1/1947 0:00 USGS-09382000 66.0
10/15/1947 0:00 USGS-09382000 132.0
1/1/1948 0:00 USGS-09382000 130.0
1/15/1948 0:00 USGS-09382000 98.0
5/1/1948 0:00 USGS-09382000 82.0
5/15/1948 0:00 USGS-09382000 53.0
6/1/1948 0:00 USGS-09382000 142.0
9/1/1948 0:00 USGS-09382000 107.0
9/15/1948 0:00 USGS-09382000 59.0
10/1/1948 0:00 USGS-09382000 106.0
10/15/1948 0:00 USGS-09382000 102.0
5/15/1949 0:00 USGS-09382000 59.0
6/1/1949 0:00 USGS-09382000 50.0
6/15/1949 0:00 USGS-09382000 161.0
9/1/1949 0:00 USGS-09382000 82.0
9/15/1949 0:00 USGS-09382000 376.0
10/1/1949 0:00 USGS-09382000 210.0
10/15/1949 0:00 USGS-09382000 131.0
1/1/1950 0:00 USGS-09382000 132.0
... ... ...
9/20/1947 0:00 USGS-09288500 59.0
9/20/1947 0:00 USGS-09288500 59.0
6/9/1948 0:00 USGS-09288500 51.0
6/9/1948 0:00 USGS-09288500 51.0
9/29/1948 0:00 USGS-09288500 51.0
9/29/1948 0:00 USGS-09288500 51.0
9/10/1949 0:00 USGS-09288500 40.0
5/19/1941 0:00 USGS-09295000 33.0
6/16/1941 0:00 USGS-09295000 3.4
5/11/1947 0:00 USGS-09295000 42.0
6/22/1947 0:00 USGS-09295000 32.0
9/20/1947 0:00 USGS-09295000 97.0
6/9/1948 0:00 USGS-09295000 37.0
9/29/1948 0:00 USGS-09295000 126.0
9/10/1949 0:00 USGS-09295000 93.0
[429 rows x 2 columns]
我想生成一个看起来像这样的 Pandas 数据框:
SampleLocation SampleDate1 CaConc1 SampleDate2 CaConc2
USGS-09382000 10/1/1947 0:00 66.0 10/1/1948 0:00 106.0
USGS-09382000 10/15/1947 0:00 132.0 10/15/1948 0:00 102.0
USGS-09382000 5/15/1948 0:00 53.0 5/15/1949 0:00 59.0
... ... ... ... ...
USGS-09288500 9/20/1947 0:00 59.0 9/29/1948 0:00 51.0
我相信可以使用 Pandas 中的多索引功能来解决这个问题。到目前为止,我已经查看了以下 Whosebug 问题以帮助匹配日期和使用索引进行操作:
How to get the closest single row after a specific datetime index using Python Pandas
Pandas: how to plot yearly data on top of each other
我认为第二个 link 使用拆栈多索引非常接近,如果我愿意聚合,我也许可以执行此操作,但我正在努力避免这种情况。
此技术与其他想要分析季节性趋势数据的人相关,例如比较同一天或接近同一天的河流流量或累积降水量或温度。
这个方法有点乱,但我正在努力让它更健壮,以解决丢失的数据。
首先,我们将删除数据中的重复项,然后将日期转换为 Pandas 时间戳:
df = df.drop_duplicates()
df.SampleDate = [pd.Timestamp(ts) for ts in df.SampleDate]
然后让我们安排您的 DataFrame,以便它在一组唯一的日期上建立索引(列将是位置 ID):
df2 = df.pivot_table(values='CalciumConc_mgL',
index='SampleDate',
columns='SampleLocation').ffill()
我已经填写了值以使结果更可靠。您可能希望限制可能提前填充的天数(例如 .ffill(limit=30))。
现在我们可以将这个 DataFrame 移动 365 个日期:
df2_lagged = df2.shift(365)
为 df2 和 df2_lagged 叠加 SampleLocation:
df2 = pd.DataFrame(df2.stack('SampleLocation', dropna=False))
df2_lagged = df2_lagged.stack('SampleLocation', dropna=False)
现在将滞后数据合并到 df2。 DataFrame 具有完全相同的结构,因此您只需复制值即可:
df2['lagged_val'] = df2_lagged
最后,交换位置和日期并重命名列:
result = df2.swaplevel(0, 1)
result.columns = ['CalciumConc_mgL', 'CalciumConc_mgL_lagged_12m']
对样本数据使用 60 天滞后:
>>> result
result.tail(10)
CalciumConc_mgL CalciumConc_mgL_lagged_12m
SampleLocation SampleDate
USGS-421548113205301 1950-01-01 59 59
USGS-422818113225801 1950-01-01 59 NaN
USGS-423200113472601 1950-01-01 33 33
USGS-424006113355301 1950-01-01 62 54
USGS-424142113340901 1950-01-01 54 54
USGS-424348113242701 1950-01-01 40 NaN
USGS-424431113412301 1950-01-01 46 NaN
USGS-424511113291401 1950-01-01 38 38
USGS-424518113282002 1950-01-01 39 39
USGS-424659113433701 1950-01-01 39 39
并且仅索引位置 ID:
result = result.reset_index().set_index('SampleLocation')
>>> result.loc['USGS-09402500', :]
CalciumConc_mgL CalciumConc_mgL_lagged_12m
SampleDate
1941-05-18 NaN NaN
1941-05-19 NaN NaN
1941-06-16 NaN NaN
1941-10-01 102 NaN
1941-10-12 132 NaN
1941-10-21 119 NaN
1943-09-18 110 NaN
1943-10-01 138 NaN
1943-10-11 140 NaN
1943-10-12 140 NaN
1943-10-14 140 NaN
1943-10-21 156 NaN
1944-01-01 116 NaN
1944-01-11 126 NaN
1944-01-13 126 NaN
1944-01-21 133 NaN
1944-05-01 84 NaN
1944-05-11 84 NaN
1944-05-13 66 NaN
1944-05-15 66 NaN
1944-05-16 66 NaN
1944-05-21 57 NaN
1944-05-22 57 NaN
1944-06-01 58 NaN
1944-06-11 57 NaN
1944-06-21 57 NaN
1944-09-01 134 NaN
1944-09-11 122 NaN
1944-09-15 122 NaN
1944-09-18 122 NaN
... ... ...
1949-05-03 63 62
1949-05-11 63 62
1949-05-15 63 62
1949-05-21 57 62
1949-06-01 58 133
1949-06-09 58 128
1949-06-10 58 128
1949-06-11 74 128
1949-06-12 74 128
1949-06-13 74 124
1949-06-15 74 112
1949-06-21 67 123
1949-06-23 67 123
1949-06-30 67 123
1949-09-01 142 123
1949-09-09 142 123
1949-09-10 142 131
1949-09-11 140 106
1949-09-15 140 108
1949-09-21 146 108
1949-09-28 146 102
1949-10-01 156 102
1949-10-11 153 102
1949-10-13 153 68
1949-10-14 153 68
1949-10-15 153 63
1949-10-21 152 63
1949-10-27 152 63
1949-10-28 152 63
1950-01-01 128 60