Python 有没有办法得到一个;“工会”;数据帧中的几列?

Python 有没有办法得到一个;“工会”;数据帧中的几列?,python,pandas,Python,Pandas,我不希望合并/连接列或用其他值替换某些值(尽管…可能是吗?)。但是我有一个大的数据帧(>100行和列),我想提取“几乎相同”的列,即具有>2个公共值(在同一索引中),而在其他索引中没有不同的值(如果一列中有值,则另一列中必须有相同的值或NaN)。 以下是此类数据帧的示例: a = np.random.randint(1,10,10) b = np.array([np.nan,2,np.nan,3,np.nan,6,8,1,2,np.nan]) c = np.random.randint(1,10

我不希望合并/连接列或用其他值替换某些值(尽管…可能是吗?)。但是我有一个大的数据帧(>100行和列),我想提取“几乎相同”的列,即具有>2个公共值(在同一索引中),而在其他索引中没有不同的值(如果一列中有值,则另一列中必须有相同的值或NaN)。 以下是此类数据帧的示例:

a = np.random.randint(1,10,10)
b = np.array([np.nan,2,np.nan,3,np.nan,6,8,1,2,np.nan])
c = np.random.randint(1,10,10)
d = np.array([7,2,np.nan,np.nan,np.nan,6,8,np.nan,2,2])
e = np.array([np.nan,2,np.nan,np.nan,np.nan,6,8,np.nan,np.nan,2])
f = np.array([np.nan,2,np.nan,3.0,7,np.nan,8,np.nan,np.nan,2])
df = pd.DataFrame({'A':a,'B':b,'C':c,'D':d,'E':e, 'F':f})
df.ix[3:6,'A']=np.nan
df.ix[4:8,'C']=np.nan
编辑

keys=['S01_o4584','S02_o2531','S03_o7812','S03_o1122','S04_o5210','S04_o3212','S05_o4665','S06_o7425','S07_o3689','S08_o2371']
df['index']=keys
df = df.set_index('index')

             A    B    C    D    E    F
index                                  
S01_o4584  8.0  NaN  9.0  7.0  NaN  NaN
S02_o2531  8.0  2.0  5.0  2.0  2.0  2.0
S03_o7812  1.0  NaN  5.0  NaN  NaN  NaN
S03_o1122  NaN  3.0  6.0  NaN  NaN  3.0
S04_o5210  NaN  NaN  NaN  NaN  NaN  7.0
S04_o3212  NaN  6.0  NaN  6.0  6.0  NaN
S05_o4665  NaN  8.0  NaN  8.0  8.0  8.0
S06_o7425  1.0  1.0  NaN  NaN  NaN  NaN
S07_o3689  8.0  2.0  NaN  2.0  NaN  NaN
S08_o2371  3.0  NaN  9.0  2.0  2.0  2.0
如您所见,列B、D(和新的E)在位置(索引)S02_o2531、S04_o3212、S05_o4665和S08_o2371处具有相同的值,而在其他位置,一个具有值,而另一个具有s NaN

我期望的结果是:

index   BD*E*
S01_o4584   7
S02_o2531   2
S03_o7812   NaN
S03_o1122   3
S04_o5210   NaN
S04_o3212   6
S05_o4665   8
S06_o7425   1
S07_o3689   2
S08_o2371   2
但是,我不能组合那些在索引的同一开头有两个不同值的列:正如您所看到的,F列也共享一些索引,但新的索引位于S04_o5210,但是以前组合的列已经在“S04_”(索引S04_o3212)有一个值

有没有一种合理的蟒蛇式的方法?即1)根据列中的值必须相同或np.nan,而不是不同的条件查找列。2) 设置一个条件,即如果某列的索引前面包含的值的开头相同,则该列不能合并(我可能需要将字符串拆分为两列并进行多重索引)?3)将它们合并到新的系列/数据帧中。

等等

test = df.B == df.D
df.loc[test,'myunion'] = df.loc[test, 'B']
df.loc[!test ,'myunion'] = df.loc[!test, 'B'].fillna(0) + df.loc[!test, 'D'].fillna(0)
它的工作原理

  • i
    j
    表示使用
    numpy
    获取上三角形索引的每一列组合
  • 使用
    i
    j
    对基础
    numpy
    数组
    df.值进行切片,然后将其减去。其中差异为
    nan
    ,表示一个或另一个为
    nan
    。否则,如果各个元素相同,则差值应为零
  • 因为我们可以容忍其中一个
    nan
    ,所以使用
    np.where
    将它们填充为零
  • (x==0)查找所有行都为零的位置。all(0)
  • 使用上面的掩码对
    i
    j
    进行切片,并识别匹配的列
  • 使用
    pd.MultiIndex
    为显示匹配内容的列构建所有匹配项的数据框
更酷的示例

np.random.seed([3,1415])
m, n = 20, 26
df = pd.DataFrame(
    np.random.randint(10, size=(m, n)),
    columns=list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
).mask(np.random.choice([True, False], (m, n), p=(.6, .4)))

df


听起来症结在于如何检测“几乎相同”的列,这些列只在缺少哪些值方面存在差异(如果有的话)。给定两个列名,如何检查它们是否几乎相同?请注意,如果我们发现一个重要的差异,它必须位于两列都没有
NaN
的索引处。换句话说,诀窍是丢弃缺少值的行,然后比较其余的:

tocheck = df[["B", "D"]].dropna()
if all(tocheck.B == tocheck.D):
    print("B, D are almost identical")
让我们使用它来迭代所有列对,并合并匹配的列:

for a, b in itertools.combinations(df.columns, 2):
    if a not in df.columns or b not in df.columns:  # Was one deleted already?
        continue
    tocheck = df[[a, b]].dropna()
    if all(tocheck[a] == tocheck[b]):
        print(b, "->", a)
        df[a] = df[a].combine_first(df[b])
        del df[b]
请注意(如果您没有注意到),当多个列最终合并时,可能会出现顺序相关的行为。例如:

     A    B   C
0   NaN   1   2 
1   10   NaN NaN

在这里,您可以将
B
C
合并到
A
,但不能同时合并两者。撇开这些问题不谈,可以将多个列合并为一个列,因为合并的列被保存在一个比较列的位置。

啊,前面的答案被删除了(连同我的评论):(。因此,我想再次了解之前的步骤,即如何找出我要合并的是B和D列。(搜索值与np.nan相同或相同的列-如果同一索引中有不同的值,我不希望这样。)谢谢。我将在问题中对其进行编辑以使其更清楚。感谢您的示例和解释,这看起来正是我想要的!但是,不知何故,我在实现时失败了。您的示例证明该方法有效,并且它返回组合列的数据帧(其列数比原始列少).但是,当我在数据上使用它时,它返回的数据帧要大得多。你知道是什么导致了这种不一致吗?@durbachit不能保证返回的数据帧“更小”。我假设你的意思是更少的列。对于一个10列的数据帧,如果每一列彼此匹配,你可能会得到一个45列的结果。有足够的列和稀疏性,我根本不希望有少量的列。哦,我明白了!不应该是每一列彼此匹配,但在有些情况下,我有一个3列之间的匹配-4列,而不仅仅是两列。因此我想将所有这3列合并为一列。函数中的
循环可以完成这项工作?(在计算d之后,继续查看是否有更多相同参数的循环)@durbachit我会小心的。这不是一个等价关系。意思是,它不是可传递的。意思是你可以有
A
match
B
B
match
C
,和
C
不匹配
A
。酷!这一个可以在多个列上工作!但是,它没有说,哪几列是组合的……但是我可以st创建一个列表,描述哪些值与新的数据帧组合在一起。干杯!我怎么能在这里设置一个条件,不组合索引中包含字符串相同部分的值?说什么?我不确定你的意思,但如果你能检测到,我想很清楚应该在哪里进行测试。解释你需要什么,如果不重要的话这足够成为一个新问题了。我知道,对不起,这很难解释,我希望这个例子现在能说明问题本身。(我编辑了这个问题)
for a, b in itertools.combinations(df.columns, 2):
    if a not in df.columns or b not in df.columns:  # Was one deleted already?
        continue
    tocheck = df[[a, b]].dropna()
    if all(tocheck[a] == tocheck[b]):
        print(b, "->", a)
        df[a] = df[a].combine_first(df[b])
        del df[b]
     A    B   C
0   NaN   1   2 
1   10   NaN NaN