【问题标题】:Split a dataframe into chunks where each chunk has no common non-zero element with the other chunks将数据帧拆分为块,其中每个块与其他块没有共同的非零元素
【发布时间】:2021-01-22 14:43:48
【问题描述】:

我有一个非常大(大约 2000x2000 但不一定是正方形)的数据框,看起来像这样非常稀疏:

      col1  col2  col3  col4
row1     0     0     1     0
row2     1     1     0     0
row3     0     1     0     1
row4     0     0     0     1

你可以用这一行重新创建它:

df = pd.DataFrame([[0, 0, 1, 0], [1, 1, 0, 0], [0, 1, 0, 1], [0, 0, 0, 1]], columns=["col1", "col2", "col3", "col4"], index=["row1", "row2", "row3", "row4"])

所以在这种情况下,我们可以看到 row2 和 row3 有一个共同的 col2 元素,而 row4 和 row3 有一个共同的非零元素,所以它们都是一个组 (row2, row3, row4) 而 row1 没有共同的非零元素,因此将是它自己的组。

我想要的是有一种相当有效的方法来获取所有这些相互独立的行分组。

我想出的唯一策略是遍历所有行,找到其共同的行,然后继续遍历所有行,直到我将所有组合绑定在一起,但这似乎效率很低。

有没有人有更好的方法来生成这些不同的组?

【问题讨论】:

  • 这个可以用图论来解决,你愿意用pandas以外的库吗?
  • @Ben.T 我认为为此获得熊猫解决方案是一项艰巨的任务。如果您有 networkx 的解决方案,未来的读者将与 OP 一起受益 :)

标签: python pandas dataframe


【解决方案1】:

如果你可以安装和使用networkx,你可以这样做

# change the shape of the data only where 1
s = df.where(df.eq(1)).stack()
print(s.head())
# row1  col3    1.0
# row2  col1    1.0
#       col2    1.0
# row3  col2    1.0
#       col4    1.0
# dtype: float64

import networkx as nx
# create the graph and add the edges from couple rows-cols
G = nx.Graph()
G.add_edges_from(set(s.index))

# get the values together in a group with connected_components
print(list(nx.connected_components(G)))
#[{'row4', 'row2', 'row3', 'col1', 'col4', 'col2'}, <-- rows and cols together
# {'col3', 'row1'}]

# use this and create a series with group number reindex by original df index
gr = pd.Series({val: gr for gr, vals in enumerate(nx.connected_components(G)) 
                        for val in vals})[df.index]
# could be a column in df with df['gr'] = gr

print(gr)
row1    1
row2    0
row3    0
row4    0
dtype: int64

如果行和列具有相似的值,您可以在流程中添加合并以使用行-行对而不是行-列对:

# change the shape of the data only where 1 and merge
df_ = df.where(df.eq(1)).stack().reset_index()
df_ = df_.merge(df_, on=['level_1']) # <-- merge on cols
print(df_.head())
#   level_0_x level_1  0_x level_0_y  0_y
# 0      row1    col3  1.0      row1  1.0
# 1      row2    col1  1.0      row2  1.0
# 2      row2    col2  1.0      row2  1.0
# 3      row2    col2  1.0      row3  1.0
# 4      row3    col2  1.0      row2  1.0

import networkx as nx
# create the graph and add the edges from couple rows-cols
G = nx.Graph()
G.add_edges_from(df_[['level_0_x','level_0_y']].to_numpy()) #<-- couple of rows sharing same cols 
print(list(nx.connected_components(G)))
#[{'row1'}, {'row3', 'row2', 'row4'}] <-- only rows name here

# use this and create a series with group number reindex by original df index
gr = pd.Series({val: gr for gr, vals in enumerate(nx.connected_components(G)) 
                        for val in vals})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 2020-09-19
    • 2017-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多