使用具有索引值和多列值的 .loc 对 pandas 数据框进行切片,然后设置值
Slice pandas dataframe using .loc with both index values and multiple column values, then set values
我有一个数据框,我想 select 数据框的一个子集同时使用索引值和列值。我可以分别执行这两项操作,但无法弄清楚同时执行它们的语法。示例:
import pandas as pd
# sample dataframe:
cid=[1,2,3,4,5,6,17,18,91,104]
c1=[1,2,3,1,2,3,3,4,1,3]
c2=[0,0,0,0,1,1,1,1,0,1]
df=pd.DataFrame(list(zip(c1,c2)),columns=['col1','col2'],index=cid)
df
Returns:
col1 col2
1 1 0
2 2 0
3 3 0
4 1 0
5 2 1
6 3 1
17 3 1
18 4 1
91 1 0
104 3 1
使用.loc,我可以按索引收集:
rel_index=[5,6,17]
relc1=[2,3]
relc2=[1]
df.loc[rel_index]
Returns:
col1 col2
5 1 5
6 2 6
17 3 7
或者我可以 select 按列值:
df.loc[df['col1'].isin(relc1) & df['col2'].isin(relc2)]
返回:
col1 col2
5 2 1
6 3 1
17 3 1
104 3 1
但是,我不能两者都做。当我尝试以下操作时:
df.loc[rel_index,df['col1'].isin(relc1) & df['col2'].isin(relc2)]
Returns:
IndexingError: Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match
我尝试了一些其他变体(例如“&”而不是“,”),但这些 return 相同或其他错误。
一旦我收集了这个切片,我希望在主数据帧上重新分配值。我想一旦完成上述操作,这将是微不足道的,但我在这里注明以防万一。我的目标是在下面分配类似 df2 的内容:
c3=[1,2,3]
c4=[5,6,7]
df2=pd.DataFrame(list(zip(c3,c4)),columns=['col1','col2'],index=rel_index)
到索引和多列条件引用的切片(覆盖原始数据帧中的内容)。
出现 IndexingError 的原因是您使用 2 种不同大小的数组调用 df.loc
。
df.loc[rel_index]
的长度为 3,而 df['col1'].isin(relc1)
的长度为 10。
您需要索引结果的长度也为 10。如果您查看 df['col1'].isin(relc1)
的输出,它是一个布尔数组。
您可以通过将 df.loc[rel_index]
替换为 df.index.isin([5,6,17])
来获得具有适当长度的类似数组
所以你最终得到:
df.loc[df.index.isin([5,6,17]) & df['col1'].isin(relc1) & df['col2'].isin(relc2)]
哪个returns:
col1 col2
5 2 1
6 3 1
17 3 1
就是说,我不确定为什么您的索引会变成这样。通常当按索引切片时,您将使用 df.iloc
并且您的索引将匹配 0,1,2...等。格式。
或者,您可以先按值搜索 - 然后将结果数据帧分配给新变量 df2
df2 = df.loc[df['col1'].isin(relc1) & df['col2'].isin(relc2)]
那么 df2.loc[rel_index]
就可以正常工作了。
至于您的总体目标,您可以简单地执行以下操作:
c3=[1,2,3]
c4=[5,6,7]
df2=pd.DataFrame(list(zip(c3,c4)),columns=['col1','col2'],index=rel_index)
df.loc[df.index.isin([5,6,17]) & df['col1'].isin(relc1) & df['col2'].isin(relc2)] = df2
@Rexovas 解释得很好,这是一个替代方案,您可以在分配之前计算索引上的过滤器 - 它有点长,涉及 MultiIndex,但是一旦您了解 MultiIndex,应该很直观:
(df
# move columns into the index
.set_index(['col1', 'col2'], append = True)
# filter based on the index
.loc(axis = 0)[rel_index, relc1, relc2]
# return cols 1 and 2
.reset_index(level = [-2, -1])
# assign values
.assign(col1 = c3, col2 = c4)
)
col1 col2
5 1 5
6 2 6
17 3 7
我有一个数据框,我想 select 数据框的一个子集同时使用索引值和列值。我可以分别执行这两项操作,但无法弄清楚同时执行它们的语法。示例:
import pandas as pd
# sample dataframe:
cid=[1,2,3,4,5,6,17,18,91,104]
c1=[1,2,3,1,2,3,3,4,1,3]
c2=[0,0,0,0,1,1,1,1,0,1]
df=pd.DataFrame(list(zip(c1,c2)),columns=['col1','col2'],index=cid)
df
Returns:
col1 col2
1 1 0
2 2 0
3 3 0
4 1 0
5 2 1
6 3 1
17 3 1
18 4 1
91 1 0
104 3 1
使用.loc,我可以按索引收集:
rel_index=[5,6,17]
relc1=[2,3]
relc2=[1]
df.loc[rel_index]
Returns:
col1 col2
5 1 5
6 2 6
17 3 7
或者我可以 select 按列值:
df.loc[df['col1'].isin(relc1) & df['col2'].isin(relc2)]
返回:
col1 col2
5 2 1
6 3 1
17 3 1
104 3 1
但是,我不能两者都做。当我尝试以下操作时:
df.loc[rel_index,df['col1'].isin(relc1) & df['col2'].isin(relc2)]
Returns:
IndexingError: Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match
我尝试了一些其他变体(例如“&”而不是“,”),但这些 return 相同或其他错误。
一旦我收集了这个切片,我希望在主数据帧上重新分配值。我想一旦完成上述操作,这将是微不足道的,但我在这里注明以防万一。我的目标是在下面分配类似 df2 的内容:
c3=[1,2,3]
c4=[5,6,7]
df2=pd.DataFrame(list(zip(c3,c4)),columns=['col1','col2'],index=rel_index)
到索引和多列条件引用的切片(覆盖原始数据帧中的内容)。
出现 IndexingError 的原因是您使用 2 种不同大小的数组调用 df.loc
。
df.loc[rel_index]
的长度为 3,而 df['col1'].isin(relc1)
的长度为 10。
您需要索引结果的长度也为 10。如果您查看 df['col1'].isin(relc1)
的输出,它是一个布尔数组。
您可以通过将 df.loc[rel_index]
替换为 df.index.isin([5,6,17])
所以你最终得到:
df.loc[df.index.isin([5,6,17]) & df['col1'].isin(relc1) & df['col2'].isin(relc2)]
哪个returns:
col1 col2
5 2 1
6 3 1
17 3 1
就是说,我不确定为什么您的索引会变成这样。通常当按索引切片时,您将使用 df.iloc
并且您的索引将匹配 0,1,2...等。格式。
或者,您可以先按值搜索 - 然后将结果数据帧分配给新变量 df2
df2 = df.loc[df['col1'].isin(relc1) & df['col2'].isin(relc2)]
那么 df2.loc[rel_index]
就可以正常工作了。
至于您的总体目标,您可以简单地执行以下操作:
c3=[1,2,3]
c4=[5,6,7]
df2=pd.DataFrame(list(zip(c3,c4)),columns=['col1','col2'],index=rel_index)
df.loc[df.index.isin([5,6,17]) & df['col1'].isin(relc1) & df['col2'].isin(relc2)] = df2
@Rexovas 解释得很好,这是一个替代方案,您可以在分配之前计算索引上的过滤器 - 它有点长,涉及 MultiIndex,但是一旦您了解 MultiIndex,应该很直观:
(df
# move columns into the index
.set_index(['col1', 'col2'], append = True)
# filter based on the index
.loc(axis = 0)[rel_index, relc1, relc2]
# return cols 1 and 2
.reset_index(level = [-2, -1])
# assign values
.assign(col1 = c3, col2 = c4)
)
col1 col2
5 1 5
6 2 6
17 3 7