根据列值将Pandas Dataframe拆分为单独的部分

时间:2014-11-18 04:02:20

标签: arrays python-2.7 pandas split dataframe

我希望使用Python 2.7在Pandas中执行一些内连接。这是我正在使用的数据集:

import pandas as pd
import numpy as np

columns = ['s_id', 'c_id', 'c_col1']
index = np.arange(46) # array of numbers for the number of samples
df = pd.DataFrame(columns=columns, index = index)

df.s_id[:15] = 144
df.s_id[15:27] = 105
df.s_id[27:46] = 52

df.c_id[:5] = 1
df.c_id[5:10] = 2
df.c_id[10:15] = 3
df.c_id[15:19] = 1
df.c_id[19:27] = 2
df.c_id[27:34] = 1
df.c_id[34:39] = 2
df.c_id[39:46] = 3

df.c_col1[:5] = ['H', 'C', 'N', 'O', 'S']
df.c_col1[5:10] = ['C', 'O','S','K','Ca']
df.c_col1[10:15] = ['H', 'O','F','Ne','Si']
df.c_col1[15:19] = ['C', 'O', 'F', 'Zn']
df.c_col1[19:27] = ['N', 'O','F','Fe','Zn','Gd','Hg','Pb']
df.c_col1[27:34] = ['H', 'He', 'Li', 'B', 'N','Al','Si']
df.c_col1[34:39] = ['N', 'F','Ne','Na','P']
df.c_col1[39:46] = ['C', 'N','O','F','K','Ca', 'Fe']

以下是数据框:

   s_id c_id c_col1
0   144    1      H
1   144    1      C
2   144    1      N
3   144    1      O <--
4   144    1      S
5   144    2      C
6   144    2      O <--
7   144    2      S
8   144    2      K
9   144    2     Ca
10  144    3      H
11  144    3      O <--
12  144    3      F
13  144    3     Ne
14  144    3     Si
15  105    1      C
16  105    1      O
17  105    1      F
18  105    1     Zn
19  105    2      N
20  105    2      O
21  105    2      F
22  105    2     Fe
23  105    2     Zn
24  105    2     Gd
25  105    2     Hg
26  105    2     Pb
27   52    1      H
28   52    1     He
29   52    1     Li
30   52    1      B
31   52    1      N
32   52    1     Al
33   52    1     Si
34   52    2      N
35   52    2      F
36   52    2     Ne
37   52    2     Na
38   52    2      P
39   52    3      C
40   52    3      N
41   52    3      O
42   52    3      F
43   52    3      K
44   52    3     Ca
45   52    3     Fe

我需要在Pandas中执行以下操作:

  1. 在给定的s_id中,为每个c_id值生成单独的数据帧。恩。对于s_id = 144,将有3个数据帧,而对于s_id = 105,将有2个数据帧
  2. Inner在Pandas中的元素列(c_col1)上加入。)中生成的单独数据帧。这有点难以理解,所以这里是数据框,我希望从这一步得到什么:

    index s_id c_id c_col1

    0   144    1      O
    1   144    2      O
    2   144    3      O
    3   105    1      O
    4   105    2      F
    5    52    1      N
    6    52    2      N
    7    52    3      N
    

    正如您所看到的,我在第2部分中寻找的内容如下:在每个s_id中,我正在寻找所有c_id值出现的c_col1值。恩。在s_id = 144的情况下,对于c_id = 1,2,3,仅发生O(氧)。我已经在原始数据中使用&#34;&lt; - &#34;来指向这些条目。所以,我想让数据框在c_col1列中显示O 3次,相应的c_id条目将是1,2,3。

  3. 条件:

    1. 提前知道唯一c_id的数量。即e。为了一个 特别是s_id,我不知道是否会有1,2和3或只有1 这意味着如果发生1,2和3,则会有一个内部 加入;如果只出现1和2,则只有一个内连接。
    2. 如何用熊猫做到这一点?

1 个答案:

答案 0 :(得分:2)

生成单独的数据帧非常简单。你想怎么存储它们?一种方法是在嵌套的dict中,外键是s_id,内键是c_id,内值是数据。你可以用一个相当长但直截了当的词典理解来做:

DF_dict = {s_id : 
          {c_id : df[(df.s_id == s_id) & (df.c_id == c_id)] for c_id in df[df.s_id == s_id]['c_id'].unique()} 
          for s_id in df.s_id.unique()}

然后例如:

In [12]: DF_dict[52][2]
Out[12]:
   s_id c_id c_col1
34   52    2      N
35   52    2      F
36   52    2     Ne
37   52    2     Na
38   52    2      P

我不明白你问题的第二部分。您想要在s_id中加入数据吗?你能说出预期的产量吗?如果你想在每个s_id中做一些事情,你可能最好去探索groupby选项。也许有人理解你想要的东西,但如果你能澄清我可能能够展示一个更好的选择,跳过问题的第一部分......

##################编辑

在我看来,你应该直接回答问题2,如果问题1只是你认为有必要解决问题2的一个步骤。事实上,这完全没必要。要解决第二个问题,您需要按s_id对数据进行分组,并根据您的要求转换数据。为了总结您的需求,我看到规则如下:对于按s_id分组的每个数据组,仅返回c__1数据,每个ccol_1数据的每个c_id值都相等。

您可以编写如下函数:

def c_id_overlap(df):
    common_vals = [] #container for values of c_col1 that are in ever c_id subgroup
    c_ids = df.c_id.unique() #get unique values of c_id
    c_col1_values = set(df.c_col1) # get a set of c_col1 values
    #create nested list of values. Each inner list contains the c_col1 values for each c_id
    nested_c_col_vals = [list(df[df.c_id == ID]['c_col1'].unique()) for ID in c_ids]
    #Iterate through the c_col1_values and see if they are in every nested list
    for val in c_col1_values:
        if all([True if val in elem else False for elem in nested_c_col_vals]):
            common_vals.append(val)
    #return a slice of the dataframe that only contains values of c_col1 that are in every
    #c_id
    return df[df.c_col1.isin(common_vals)]

然后将其传递给apply上按s_id分组的数据:

df.groupby('s_id', as_index = False).apply(c_id_overlap)

给出了以下输出:

     s_id c_id c_col1
0 31   52    1      N
  34   52    2      N
  40   52    3      N
1 16  105    1      O
  17  105    1      F
  18  105    1     Zn
  20  105    2      O
  21  105    2      F
  23  105    2     Zn
2 3   144    1      O
  6   144    2      O
  11  144    3      O

这似乎就是你要找的。 ###########编辑:附加说明:

因此,apply将每个分组数据块传递给函数,并且一旦针对每组数据完成此操作,这些部分就会粘合在一起。

因此,请考虑第一组传递s_id == 105.函数的第一行创建一个空列表common_vals,它将包含出现在数据的每个子组中的那些周期性元素(即相对于c_id)的每个值。

第二行获取&#39; c_id&#39;的唯一值,在本例中为[1, 2],并将它们存储在名为c_ids

的数组中

第三行创建一组c_col1的值,在这种情况下会产生:

 {'C', 'F', 'Fe', 'Gd', 'Hg', 'N', 'O', 'Pb', 'Zn'}

第四行创建一个嵌套列表结构nested_c_col_vals,其中每个内部列表是与c_ids数组中每个元素关联的唯一值的列表。在这种情况下,这看起来像这样:

[['C', 'O', 'F', 'Zn'], ['N', 'O', 'F', 'Fe', 'Zn', 'Gd', 'Hg', 'Pb']]

现在迭代c_col1_values列表中的每个元素,并且对于每个元素,程序确定该元素是否出现在nested_c_col_vals对象的每个内部列表中。 all函数中的bulit确定backets之间序列中的每个项目是True还是非零(您需要检查此项)。所以:

In [10]: all([True, True, True])
Out[10]: True

In [11]: all([True, True, True, False])
Out[11]: False

In [12]: all([True, True, True, 1])
Out[12]: True

In [13]: all([True, True, True, 0])
Out[13]: False

In [14]: all([True, 1, True, 0])
Out[14]: False 

所以在这种情况下,让我们说“C&#39;是迭代的第一个元素。 all()支持中的列表理解说,查看每个内部列表,看看元素是否在那里。如果是,则True如果不是False。所以在这种情况下,这解决了:

all([True, False])

当然是False。当元素是&#39; Zn&#39;这个操作的结果是

all([True, True])

解析为True。因此&#39; Zn&#39;被附加到common_vals列表。

完成此过程后,common_vals中的值为:

['O', 'F', 'Zn']

如上所述,return语句根据vaues os c_col1是否在列表common_vals中来简单地切片数据块。

然后对每个剩余的组重复这一过程,并将数据粘合在一起。

希望这有帮助