通过多个标签过滤或选择熊猫中两行之间的数据
Posted
技术标签:
【中文标题】通过多个标签过滤或选择熊猫中两行之间的数据【英文标题】:Filter or selecting data between two rows in pandas by multiple labels 【发布时间】:2021-10-25 19:59:40 【问题描述】:所以我有这个来自 pdf 转换的 df 或表格,例如:
ElementRow | ElementColumn | ElementPage | ElementText | X1 | Y1 | X2 | Y2 | |
---|---|---|---|---|---|---|---|---|
1 | 50 | 0 | 1 | Emergency Contacts | 917 | 8793 | 2191 | 8878 |
2 | 51 | 0 | 1 | Contact | 1093 | 1320 | 1451 | 1388 |
3 | 51 | 2 | 1 | Relationship | 2444 | 1320 | 3026 | 1388 |
4 | 51 | 7 | 1 | Work Phone | 3329 | 1320 | 3898 | 1388 |
5 | 51 | 9 | 1 | Home Phone | 4260 | 1320 | 4857 | 1388 |
6 | 51 | 10 | 1 | Cell Phone | 5176 | 1320 | 5684 | 1388 |
7 | 51 | 12 | 1 | Priority Phone | 6143 | 1320 | 6495 | 1388 |
8 | 51 | 14 | 1 | Contact Address | 6542 | 1320 | 7300 | 1388 |
9 | 51 | 17 | 1 | City | 7939 | 1320 | 7300 | 1388 |
10 | 51 | 18 | 1 | State | 8808 | 1320 | 8137 | 1388 |
11 | 51 | 21 | 1 | Zip | 9134 | 1320 | 9294 | 1388 |
12 | 52 | 0 | 1 | Silvia Smith | 1093 | 1458 | 1973 | 1526 |
13 | 52 | 2 | 1 | Mother | 2444 | 1458 | 2783 | 1526 |
13 | 52 | 7 | 1 | (123) 456-78910 | 5176 | 1458 | 4979 | 1526 |
14 | 52 | 10 | 1 | Austin | 7939 | 1458 | 8406 | 1526 |
15 | 52 | 15 | 1 | Texas | 8808 | 1458 | 8961 | 1526 |
16 | 52 | 20 | 1 | 76063 | 9134 | 1458 | 9421 | 1526 |
17 | 52 | 2 | 1 | 1234 Parkside Ct | 6542 | 1458 | 9421 | 1526 |
18 | 53 | 0 | 1 | Naomi Smith | 1093 | 2350 | 1973 | 1526 |
19 | 53 | 2 | 1 | Aunt | 2444 | 2350 | 2783 | 1526 |
20 | 53 | 7 | 1 | (123) 456-78910 | 5176 | 2350 | 4979 | 1526 |
21 | 53 | 10 | 1 | Austin | 7939 | 2350 | 8406 | 1526 |
22 | 53 | 15 | 1 | Texas | 8808 | 2350 | 8961 | 1526 |
23 | 53 | 20 | 1 | 76063 | 9134 | 2350 | 9421 | 1526 |
24 | 53 | 2 | 1 | 3456 Parkside Ct | 6542 | 2350 | 9421 | 1526 |
25 | 54 | 40 | 1 | End Employee Line | 6542 | 2350 | 9421 | 1526 |
25 | 55 | 0 | 1 | Emergency Contacts | 917 | 8793 | 2350 | 8878 |
我试图将每个寄存器按行分隔,作为参考 ElementRow 列,并保留第一行的标题,然后遍历其他行。 X1 列有一个关于哪个标题应该是值的参考。我想要这样的数据。
Contact | Relationship | Work Phone | Cell Phone | Priority | ContactAddress | City | State | Zip | |
---|---|---|---|---|---|---|---|---|---|
1 | Silvia Smith | Mother | (123) 456-78910 | 1234 Parkside Ct | Austin | Texas | 76063 | ||
2 | Naomi Smith | Aunt | (123) 456-78910 | 3456 Parkside Ct | Austin | Texas | 76063 |
我尝试过的事情:
在遍历列之间获取行。尝试对第一个索引和最后一个索引进行切片,但显示此错误:
emergStartIndex = df.index[df['ElementText'] == 'Emergency Contacts']
emergLastIndex = df.index[df['ElementText'] == 'End Employee Line']
emerRows_between = df.iloc[emergStartIndex:emergLastIndex]
TypeError: cannot do positional indexing on RangeIndex with these indexers [Int64Index([...
这种方式可以使用这个 numpy 技巧。
emerRows_between = df.iloc[np.r_[1:54,55:107]]
emerRows_between
但在尝试替换索引时显示:
emerRows_between = df.iloc[np.r_[emergStartIndex:emergLastIndex]]
emerRows_between
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
我尝试像这样逐行迭代,但在某些时候 df 到达末尾,我收到 index out of bound。
emergencyContactRow1 = df['ElementText','X1'].iloc[emergStartIndex+1].reset_index(drop=True)
emergencyContactRow2 = df['ElementText','X1'].iloc[emergStartIndex+2].reset_index(drop=True)
emergencyContactRow3 = df['ElementText','X1'].iloc[emergStartIndex+3].reset_index(drop=True)
emergencyContactRow4 = df['ElementText','X1'].iloc[emergStartIndex+4].reset_index(drop=True)
emergencyContactRow5 = df['ElementText','X1'].iloc[emergStartIndex+5].reset_index(drop=True)
emergencyContactRow6 = df['ElementText','X1'].iloc[emergStartIndex+6].reset_index(drop=True)
emergencyContactRow7 = df['ElementText','X1'].iloc[emergStartIndex+7].reset_index(drop=True)
emergencyContactRow8 = df['ElementText','X1'].iloc[emergStartIndex+8].reset_index(drop=True)
emergencyContactRow9 = df['ElementText','X1'].iloc[emergStartIndex+9].reset_index(drop=True)
emergencyContactRow10 = df['ElementText','X1'].iloc[emergStartIndex+10].reset_index(drop=True)
frameEmergContact1 = [emergencyContactRow1 , emergencyContactRow2 , emergencyContactRow3, emergencyContactRow4, emergencyContactRow5, emergencyContactRow6, emergencyContactRow7, , emergencyContactRow8,, emergencyContactRow9, , emergencyContactRow10]
df_emergContact1= pd.concat(frameEmergContact1 , axis=1)
df_emergContact1.columns = range(df_emergContact1.shape[1])
那么如何使这段代码动态化或如何避免索引越界错误并让我的标题仅作为紧急联系人行之后的第一行的参考?我知道我还没有尝试使用 X1 列,但我必须首先解决如何遍历这些多个索引。
从紧急联系人索引到 End Employee 行的每次迭代都属于整个数据帧中的一个人或一个员工,因此在捕获所有这些值之后的想法是还保留一个计数器变量,以查看在之间捕获数据的次数这两个索引。
【问题讨论】:
您的数据正确吗?对于 Silvia Smith,Work Phone 的“ElementColumn”是 7,但对于 Naomi Smith,它是 2? 是的!感谢您检查是构建表的错误,已修复。这些是列坐标,但我认为我必须更多地关注 X1 值和 Y1 以获取正确的数据。 您有机会测试我的答案吗?我认为它对于更大的数据集是可扩展的。 【参考方案1】:这有点难看,但这应该可以。基本上你不需要第一行或最后两行,所以如果你去掉那些,然后旋转 X1 和 ElemenTex 列,你会非常接近。然后就是摆脱空值并将第一行提升为标题的问题。
df = df.iloc[1:-2][['ElementTex','X1','ElementRow']].pivot(columns='X1',values='ElementTex')
df = pd.DataFrame([x[~pd.isnull(x)] for x in df.values.T]).T
df.columns = df.iloc[0]
df = df[1:]
【讨论】:
当然这是一条路要走。问题是数据比这里发布的更丑陋,我必须首先过滤它,只取所有数据帧的第一行之间的任何内容,然后进行数据透视。但是谢谢你,这肯定是解决这个问题的一种方法。关于您的代码还有一个问题,为什么 .T 在这行末尾的括号之后: df = pd.DataFrame([x[~pd.isnull(x)] for x in df.values.T]).T. @lug0lug0 将其从列交换到行以消除空值,然后返回列以进入数据框【参考方案2】:-
每当“紧急联系人”出现在“ElementText”列中时,将数据框拆分为块
将每个块解析为所需的格式
附加到输出
import numpy as np
list_of_df = np.array_split(data, data[data["ElementText"]=="Emergency Contacts"].index)
output = pd.DataFrame()
for frame in list_of_df:
df = frame[~frame["ElementText"].isin(["Emergency Contacts", "End Employee Line"])].dropna()
if df.shape[0]>0:
temp = pd.DataFrame(df.groupby("X1")["ElementText"].apply(list).tolist()).T
temp.columns = temp.iloc[0]
temp = temp.drop(0)
output = output.append(temp, ignore_index=True)
>>> output
0 Contact Relationship Work Phone ... City State Zip
0 Silvia Smith Mother None ... Austin Texas 76063
1 Naomi Smith Aunt None ... Austin Texas 76063
【讨论】:
以上是关于通过多个标签过滤或选择熊猫中两行之间的数据的主要内容,如果未能解决你的问题,请参考以下文章