通过多个标签过滤或选择熊猫中两行之间的数据

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

【讨论】:

以上是关于通过多个标签过滤或选择熊猫中两行之间的数据的主要内容,如果未能解决你的问题,请参考以下文章

表格中两行之间的空间?

Oracle - 两个表中两行之间的差异或变化

MySQL Workbench中两行之间的差异,但未授权LAG

如何获取同一列中两行之间的差异

引导表中两行之间的空格

分组选择器