根据另一列中的值对pandas数据帧中的列进行标准化

时间:2015-05-20 05:18:34

标签: python pandas dataframe

我想基于另一列中的值来规范化pandas数据帧的一列中的值。从统计意义上讲,它不是纯粹的规范化。第二个值是一个类型;我想对每种类型的所有第一个值求和,然后在每一行中将值除以该行类型的总和。一个例子应该让这个更清楚。

// Replaces Pointer.
#[derive(Copy, Clone)]
pub struct Object<'a> {
    ptr: *mut AtomicUsize,
    mark: PhantomData<&'a usize>
}

impl<'a> Object<'a> {
    pub fn survive(self); // Now supposed to be perfectly safe!
}

pub type Adjust<'a> = BTreeMap<usize, Object<'a>>;

pub struct Heap { ... }
pub struct Allocator<'a> { ... }

impl Heap {
    fn allocator(&'a self) -> Allocator<'a>;
    // The following doesn't work:
    // 
    //  fn allocate(&'a mut self) -> Object<'a>;
    //  fn reallocate(&'a mut self, heap: Heap) -> Adjust<'a>;
    // 
    // Because it doesn't allow the user to allocate more
    // than one `Object` at a time (!) in a `Heap`.
}

impl<'a> Allocator<'a> {
    // Note that the resulting `Object`s are tied to the `Heap`,
    // but not to the allocator itself.
    fn allocate(&mut self, tag: Tag) -> Object<'a>;
    fn reallocate(&mut self, heap: Heap) -> Adjust<'a>;
}

然后我可以用以下内容找到总和:

df = pd.read_table(datafile, names = ["A", "B", "value", "type"])

    A   B  value   type
0  A1  B1      1  type1
1  A2  B2      1  type1
2  A1  B1      1  type2
3  A1  B3      1  type3
4  A2  B2      1  type2
5  A2  B4      1  type3
6  A3  B4      1  type2
7  A3  B5      1  type3
8  A4  B6      1  type2
9  A4  B7      1  type3

然后我如何使用它来规范化每一行的值?

我可以使用这样的循环来计算标准化值:

types = df.groupby(["type"])["value"].sum()

type
type1    2
type2    4
type3    4
Name: value, dtype: int64

然后使用具有以下值的新列替换该列:

norms = []
for ix, row in df.iterrows():
    norms.append(row["value"]/types[row["type"]])

但据我所知,使用这样的循环效率不高或不合适,并且可能有一种方法可以使用一些标准的pandas函数来实现。

感谢。

2 个答案:

答案 0 :(得分:4)

您可以使用transform,它对每个组执行操作,然后将结果重新展开以匹配原始索引。例如“

>>> df["value"] /= df.groupby("type")["value"].transform(sum)
>>> df
    A   B  value   type
0  A1  B1   0.50  type1
1  A2  B2   0.50  type1
2  A1  B1   0.25  type2
3  A1  B3   0.25  type3
4  A2  B2   0.25  type2
5  A2  B4   0.25  type3
6  A3  B4   0.25  type2
7  A3  B5   0.25  type3
8  A4  B6   0.25  type2
9  A4  B7   0.25  type3

因为我们有

>>> df.groupby("type")["value"].transform(sum)
0    2
1    2
2    4
3    4
4    4
5    4
6    4
7    4
8    4
9    4
dtype: int64

答案 1 :(得分:1)

我认为实现此目的的最佳方法是在groupby对象上使用.apply()方法:

# Using backslashes for explicit line continuation, not seen
#   that often in Python but useful in pandas when you're
#   chaining a lot of methods one after the other
df['value_normed'] = df.groupby('type', group_keys=False)\
    .apply(lambda g: g['value'] / g['value'].sum())
df
Out[9]: 
    A   B  value   type  value_normed
0  A1  B1      1  type1          0.50
1  A2  B2      1  type1          0.50
2  A1  B1      1  type2          0.25
3  A1  B3      1  type3          0.25
4  A2  B2      1  type2          0.25
5  A2  B4      1  type3          0.25
6  A3  B4      1  type2          0.25
7  A3  B5      1  type3          0.25
8  A4  B6      1  type2          0.25
9  A4  B7      1  type3          0.25

您需要group_keys=False参数,以便type不会成为每个群组数据的索引,这会阻止您将转换后的值与原始数据帧进行匹配容易。