如何基于 pandas DataFrame 更新 numpy 数组
How to update numpy array based on pandas DataFrame
我有一个包含数千行和几列的 numpy 数组,我想知道如何根据 pandas DataFrame 中的值更新每个值。
例如,假设我的数组包含一个年份列表(这里有一个非常小的示例,只是为了给您提供基本概念):
[[2020, 2015, 2017],
[2015, 2016, 2016],
[2019, 2018, 2020]]
我想根据“年”将数组中的每个值更改为“Lat”。因此,如果我的 pandas 数据框如下所示:
Year
Lat
Lon
2020
37.2
103.45
2019
46.1
107.82
2018
35.2
101.45
2017
38.6
110.62
2016
29.1
112.73
2015
33.8
120.92
那么输出数组应该如下所示:
[[37.2, 33.8, 38.6],
[33.8, 29.1, 29.1],
[46.1, 35.2, 37.2]]
如果我的数据集真的这么小,那不是问题,但考虑到我在数组中有数百万个值,在 DataFrame 中有数千个值,我有点不知所措这很有效。
更新:
也许我的问题比我预想的要复杂一些。我没有匹配年份,而是匹配 GPS 时间,因此数字匹配得不太好。有没有办法在数组中取一个数字并将其与 DataFrame 列中最接近的值匹配?实际上,我的数组看起来更像这样:
[[2019.99, 2015.2, 2017.1],
[2015.33, 2016.01, 2015.87],
[2019.2, 2018.3, 2020.00]]
也许将 Year
设置为索引并使用 at
(或 loc
)会有所帮助
# Data
arr = np.array([[2020, 2015, 2017], [2015, 2016, 2016], [2019, 2018, 2020]])
df = pd.DataFrame({'Year': {0: 2020, 1: 2019, 2: 2018, 3: 2017, 4: 2016, 5: 2015},
'Lat': {0: 37.2, 1: 46.1, 2: 35.2, 3: 38.6, 4: 29.1, 5: 33.8},
'Lon': {0: 103.45, 1: 107.82, 2: 101.45, 3: 110.62, 4: 112.73, 5: 120.92}})
df = df.set_index("Year")
np.array([df.loc[years, "Lat"] for years in arr])
# array([[37.2, 33.8, 38.6],
# [33.8, 29.1, 29.1],
# [46.1, 35.2, 37.2]])
您基本上是在跨列映射值。一种想法是使用索引来定位需要为给定键替换的元素,然后一次替换它们。这对原始数据中的每个 key-value 对进行一次迭代。
示例:
import numpy as np
import pandas as pd
a = np.array([
[2020, 2015, 2017],
[2015, 2016, 2016],
[2019, 2018, 2020],
])
b = np.zeros(a.shape, dtype=float)
df = pd.DataFrame({
'Year': [2020, 2019, 2018, 2017, 2016, 2015],
'Lat': [37.2, 46.1, 35.2, 38.6, 29.1, 33.8],
})
for k, v in df.set_index('Year')['Lat'].to_dict().items():
b[a == k] = v
print(b)
# output:
# [[37.2 33.8 38.6]
# [33.8 29.1 29.1]
# [46.1 35.2 37.2]]
np.unique 可用于检测 years
列表中的唯一值,然后 return_inverse=True
可设置为 return 重新创建输入数组所需的索引.
我们可以将它与 set_index 和 reindex 结合使用来创建一系列可以转换的值 to_numpy。然后,来自 np.unique 的索引的结果可以与此纬度值数组一起使用到 select 必要的值。最后的 reshape 可用于获取正确形式的数组。
u, inv = np.unique(years, return_inverse=True)
result = (
df.set_index('Year')['Lat'].reindex(u).to_numpy()[inv].reshape(years.shape)
)
result
:
[[37.2 33.8 38.6]
[33.8 29.1 29.1]
[46.1 35.2 37.2]]
结果来自 np.unique
u, inv = np.unique(years, return_inverse=True)
u=array([2015, 2016, 2017, 2018, 2019, 2020])
inv=array([5, 0, 2, 0, 1, 1, 4, 3, 5])
以年份为索引的Lat
列:
df.set_index('Year')['Lat']
Year
2020 37.2
2019 46.1
2018 35.2
2017 38.6
2016 29.1
2015 33.8
Name: Lat, dtype: float64
中的顺序
df.set_index('Year')['Lat'].reindex(u)
Year
2015 33.8
2016 29.1
2017 38.6
2018 35.2
2019 46.1
2020 37.2
Name: Lat, dtype: float64
NumPy 索引到来自这个新系列的 select:
df.set_index('Year')['Lat'].reindex(u).to_numpy()[inv]
array([37.2, 33.8, 38.6, 33.8, 29.1, 29.1, 46.1, 35.2, 37.2])
最终reshape匹配初始输入years
数组维度:
df.set_index('Year')['Lat'].reindex(u).to_numpy()[inv].reshape(years.shape)
array([[37.2, 33.8, 38.6],
[33.8, 29.1, 29.1],
[46.1, 35.2, 37.2]])
设置:
import numpy as np
import pandas as pd
df = pd.DataFrame({
'Year': [2020, 2019, 2018, 2017, 2016, 2015],
'Lat': [37.2, 46.1, 35.2, 38.6, 29.1, 33.8],
'Lon': [103.45, 107.82, 101.45, 110.62, 112.73, 120.92]
})
years = np.array([[2020, 2015, 2017],
[2015, 2016, 2016],
[2019, 2018, 2020]])
一行:
df.set_index('Year').Lat.loc[arr.flatten()].to_numpy().reshape(arr.shape)
如果您要执行多个这样的操作,您应该只调用 set_index()
一次,如果您想修改现有的 DataFrame 而不是创建一个新的 DataFrame,则可以使用 inplace=True
。
之后,只需给 loc
一个一维数组,它可用于高效查找 Lat
值,然后重塑结果以匹配原始 arr
.
这类似于 d.b 的答案,但效率更高,因为它不使用 Python for
循环。
我有一个包含数千行和几列的 numpy 数组,我想知道如何根据 pandas DataFrame 中的值更新每个值。
例如,假设我的数组包含一个年份列表(这里有一个非常小的示例,只是为了给您提供基本概念):
[[2020, 2015, 2017],
[2015, 2016, 2016],
[2019, 2018, 2020]]
我想根据“年”将数组中的每个值更改为“Lat”。因此,如果我的 pandas 数据框如下所示:
Year | Lat | Lon |
---|---|---|
2020 | 37.2 | 103.45 |
2019 | 46.1 | 107.82 |
2018 | 35.2 | 101.45 |
2017 | 38.6 | 110.62 |
2016 | 29.1 | 112.73 |
2015 | 33.8 | 120.92 |
那么输出数组应该如下所示:
[[37.2, 33.8, 38.6],
[33.8, 29.1, 29.1],
[46.1, 35.2, 37.2]]
如果我的数据集真的这么小,那不是问题,但考虑到我在数组中有数百万个值,在 DataFrame 中有数千个值,我有点不知所措这很有效。
更新:
也许我的问题比我预想的要复杂一些。我没有匹配年份,而是匹配 GPS 时间,因此数字匹配得不太好。有没有办法在数组中取一个数字并将其与 DataFrame 列中最接近的值匹配?实际上,我的数组看起来更像这样:
[[2019.99, 2015.2, 2017.1],
[2015.33, 2016.01, 2015.87],
[2019.2, 2018.3, 2020.00]]
也许将 Year
设置为索引并使用 at
(或 loc
)会有所帮助
# Data
arr = np.array([[2020, 2015, 2017], [2015, 2016, 2016], [2019, 2018, 2020]])
df = pd.DataFrame({'Year': {0: 2020, 1: 2019, 2: 2018, 3: 2017, 4: 2016, 5: 2015},
'Lat': {0: 37.2, 1: 46.1, 2: 35.2, 3: 38.6, 4: 29.1, 5: 33.8},
'Lon': {0: 103.45, 1: 107.82, 2: 101.45, 3: 110.62, 4: 112.73, 5: 120.92}})
df = df.set_index("Year")
np.array([df.loc[years, "Lat"] for years in arr])
# array([[37.2, 33.8, 38.6],
# [33.8, 29.1, 29.1],
# [46.1, 35.2, 37.2]])
您基本上是在跨列映射值。一种想法是使用索引来定位需要为给定键替换的元素,然后一次替换它们。这对原始数据中的每个 key-value 对进行一次迭代。
示例:
import numpy as np
import pandas as pd
a = np.array([
[2020, 2015, 2017],
[2015, 2016, 2016],
[2019, 2018, 2020],
])
b = np.zeros(a.shape, dtype=float)
df = pd.DataFrame({
'Year': [2020, 2019, 2018, 2017, 2016, 2015],
'Lat': [37.2, 46.1, 35.2, 38.6, 29.1, 33.8],
})
for k, v in df.set_index('Year')['Lat'].to_dict().items():
b[a == k] = v
print(b)
# output:
# [[37.2 33.8 38.6]
# [33.8 29.1 29.1]
# [46.1 35.2 37.2]]
np.unique 可用于检测 years
列表中的唯一值,然后 return_inverse=True
可设置为 return 重新创建输入数组所需的索引.
我们可以将它与 set_index 和 reindex 结合使用来创建一系列可以转换的值 to_numpy。然后,来自 np.unique 的索引的结果可以与此纬度值数组一起使用到 select 必要的值。最后的 reshape 可用于获取正确形式的数组。
u, inv = np.unique(years, return_inverse=True)
result = (
df.set_index('Year')['Lat'].reindex(u).to_numpy()[inv].reshape(years.shape)
)
result
:
[[37.2 33.8 38.6]
[33.8 29.1 29.1]
[46.1 35.2 37.2]]
结果来自 np.unique
u, inv = np.unique(years, return_inverse=True)
u=array([2015, 2016, 2017, 2018, 2019, 2020])
inv=array([5, 0, 2, 0, 1, 1, 4, 3, 5])
以年份为索引的Lat
列:
df.set_index('Year')['Lat']
Year
2020 37.2
2019 46.1
2018 35.2
2017 38.6
2016 29.1
2015 33.8
Name: Lat, dtype: float64
中的顺序
df.set_index('Year')['Lat'].reindex(u)
Year
2015 33.8
2016 29.1
2017 38.6
2018 35.2
2019 46.1
2020 37.2
Name: Lat, dtype: float64
NumPy 索引到来自这个新系列的 select:
df.set_index('Year')['Lat'].reindex(u).to_numpy()[inv]
array([37.2, 33.8, 38.6, 33.8, 29.1, 29.1, 46.1, 35.2, 37.2])
最终reshape匹配初始输入years
数组维度:
df.set_index('Year')['Lat'].reindex(u).to_numpy()[inv].reshape(years.shape)
array([[37.2, 33.8, 38.6],
[33.8, 29.1, 29.1],
[46.1, 35.2, 37.2]])
设置:
import numpy as np
import pandas as pd
df = pd.DataFrame({
'Year': [2020, 2019, 2018, 2017, 2016, 2015],
'Lat': [37.2, 46.1, 35.2, 38.6, 29.1, 33.8],
'Lon': [103.45, 107.82, 101.45, 110.62, 112.73, 120.92]
})
years = np.array([[2020, 2015, 2017],
[2015, 2016, 2016],
[2019, 2018, 2020]])
一行:
df.set_index('Year').Lat.loc[arr.flatten()].to_numpy().reshape(arr.shape)
如果您要执行多个这样的操作,您应该只调用 set_index()
一次,如果您想修改现有的 DataFrame 而不是创建一个新的 DataFrame,则可以使用 inplace=True
。
之后,只需给 loc
一个一维数组,它可用于高效查找 Lat
值,然后重塑结果以匹配原始 arr
.
这类似于 d.b 的答案,但效率更高,因为它不使用 Python for
循环。