基于变量的百分比变化

时间:2016-10-28 13:40:48

标签: r

我理解标题不是很清楚我要问的问题,但我认为我的例子会解决这个问题。

我需要计算数据集中几个变量的百分比变化。为此,我使用函数:

Content

我在网上找到了。问题是,在我应用它之后,我的数据看起来像这样:

pcchange=function(x,lag=1) c(diff(x,lag),rep(NA,lag))/x

我想要完成的是:

 color  shade   value   pcchange
RED LIGHT   -1.05   N/A
RED LIGHT   -1.37   0.3
RED LIGHT   -0.32   -0.8
RED LIGHT   0.87    -3.7
RED LIGHT   -0.20   -1.2
RED DARK    0.52    -3.6
RED DARK    -0.20   -1.4
RED DARK    0.64    -4.2
RED DARK    1.12    1
RED DARK    4.00    2.6
BLUE    LIGHT   0.93    -0.8
BLUE    LIGHT   0.78    -0.2
BLUE    LIGHT   -1.84   -3.3
BLUE    LIGHT   -0.50   -0.7
BLUE    LIGHT   -1.11   1.2
BLUE    DARK    -4.86   3.4
BLUE    DARK    1.11    -1.2
BLUE    DARK    0.14    -0.9
BLUE    DARK    0.12    -0.1
BLUE    DARK    -1.65   -14.5
GREEN   LIGHT   3.13    -2.9
GREEN   LIGHT   2.65    -0.2
GREEN   LIGHT   -2.36   -1.9
GREEN   LIGHT   -3.11   0.3
GREEN   LIGHT   3.49    -2.1
GREEN   DARK    1.91    -0.5
GREEN   DARK    -1.10   -1.6
GREEN   DARK    -1.93   0.8
GREEN   DARK    1.00    -1.5
GREEN   DARK    -0.23   -1.2

很抱歉很长的例子,但我想尽可能清楚地问我的问题。

所以你可以看到我需要一种方法在某些变量值之后使值“重置”(在我的例子中它将是变量:shade)。

有没有简单的方法可以做到这一点,或者只有解决方案基于循环?

提前谢谢!

3 个答案:

答案 0 :(得分:2)

我会把这一点添加到评论中,但我没有足够的代表:) 因此,如果您仍希望将NA放在每个组的开头,则必须将该函数更改为如下所示:

import sys
from PyQt4 import QtGui, QtCore


class MyFileViewDelegate(QtGui.QStyledItemDelegate ):
    def __init__(self, parent=None, *args, **kwargs):
        QtGui.QItemDelegate.__init__(self, parent, *args)

        self.condition = None
        self.isMatch = False

        self.brush_active =         QtGui.QBrush(QtGui.QColor("#79b9ed"))
        self.brush_active_matched = QtGui.QBrush(QtGui.QColor("#58cd1c"))
        self.pen =                  QtGui.QPen(QtGui.QColor("#414141") )
        self.pen_matched =          QtGui.QPen(QtGui.QColor("#39c819") )
        self.pen_active =           QtGui.QPen(QtGui.QColor("#eef2fd") )
        self.pen_active_matched =   QtGui.QPen(QtGui.QColor("#e7fade") )


    def paint(self, painter, option, index):
        text = index.data(QtCore.Qt.DisplayRole)
        self.matchText(text)

        painter.save()
        ######## set background 
        painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
        if option.state & QtGui.QStyle.State_Selected:
            if self.isMatch:
                painter.setBrush(self.brush_active_matched)
            else:
                painter.setBrush(self.brush_active)

        painter.drawRect(option.rect)
        ######## set font color
        if option.state & QtGui.QStyle.State_Selected:
            if self.isMatch:
                painter.setPen(self.pen_active_matched)
            else:
                painter.setPen(self.pen_active)
        else:
            if self.isMatch:
                painter.setPen(self.pen_matched) 
            else:
                painter.setPen(self.pen) 

        painter.drawText(option.rect, QtCore.Qt.AlignLeft, text)

        painter.restore()

    def matchText(self, filename):
        # testing condition. In the real case this is much more complicated
        if (self.condition != None) and (self.condition != "") and (self.condition in filename):
            self.isMatch = True
        else:
            self.isMatch = False

    def setCondition(self, condition):
        self.condition = condition


class MainWidget(QtGui.QWidget):
    def __init__(self, parent=None, useDelegate = False):
        super(MainWidget, self).__init__(parent)
        self.setLayout(QtGui.QVBoxLayout())

        self.FolderModel = QtGui.QFileSystemModel()
        self.FolderModel.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.AllDirs)
        self.FolderModel.setRootPath("")

        self.FolderView = QtGui.QTreeView(parent=self)
        self.FolderView.setModel(self.FolderModel)

        self.FolderView.setHeaderHidden(True)
        self.FolderView.hideColumn(1)
        self.FolderView.hideColumn(2)
        self.FolderView.hideColumn(3)
        self.FolderView.expanded.connect(self.FolderView.scrollTo)
        self.FolderView.clicked[QtCore.QModelIndex].connect(self.browserClicked)

        self.FileModel = QtGui.QFileSystemModel()
        self.FileModel.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Files)

        self.FileView = QtGui.QListView(parent=self)
        self.FileView.setModel(self.FileModel)

        self.FileViewDelegate = None
        if useDelegate:
            self.FileViewDelegate = MyFileViewDelegate()
            self.FileView.setItemDelegate(self.FileViewDelegate)

        self.FileView.setSelectionMode(  QtGui.QAbstractItemView.ExtendedSelection  ) 

        self.LineEdit = QtGui.QLineEdit()
        self.LineEdit.textChanged.connect(self.changeCondition)

        # Add Widgets to layout
        self.layout().addWidget(self.FolderView)
        self.layout().addWidget(self.FileView)
        self.layout().addWidget(self.LineEdit)

    def changeCondition(self, text):
        if self.FileViewDelegate:
            self.FileViewDelegate.setCondition(text)

    def browserClicked(self, index):
        # the signal passes the index of the clicked item
        # set the FileView's root_index to the clicked index
        dir_path =  self.FileModel.filePath(index) 
        root_index = self.FileModel.setRootPath(dir_path)
        self.FileView.setRootIndex(root_index)


class App(QtGui.QMainWindow):
    def __init__(self, parent=None, useDelegate=False):
        super(App, self).__init__(parent)
        self.central = MainWidget(parent =self, useDelegate=useDelegate)
        self.setCentralWidget(self.central)

if __name__=='__main__':
    app = QtGui.QApplication(sys.argv)
    thisapp = App(None, True) # set False to view App without custom FileViewDelegate
    thisapp.show()
    sys.exit(app.exec_())

由于您只计算连续值之间的百分比变化(因此您不需要跳过之间的任何值),因此您不需要LineEdit.textChange和多个NAs每个小组的开头。由于每个组只需要一个NA,pcchange = function(x){ c( NA, diff(x)/x[-length(x)] ) } 也可以忽略不计。

答案 1 :(得分:1)

使用dplyr,按破坏数据框的内容进行分组,改变:

data %>% group_by(color, shade) %>% mutate(pcchange = pcchange(value))

生成一个数据框(实际上是tbl),如下所示:

   color shade value    pcchange
1    RED LIGHT -1.05   0.3047619
2    RED LIGHT -1.37  -0.7664234
3    RED LIGHT -0.32  -3.7187500
4    RED LIGHT  0.87  -1.2298851
5    RED LIGHT -0.20          NA
6    RED  DARK  0.52  -1.3846154
7    RED  DARK -0.20  -4.2000000
8    RED  DARK  0.64   0.7500000
9    RED  DARK  1.12   2.5714286
10   RED  DARK  4.00          NA
11  BLUE LIGHT  0.93  -0.1612903
12  BLUE LIGHT  0.78  -3.3589744
13  BLUE LIGHT -1.84  -0.7282609
14  BLUE LIGHT -0.50   1.2200000
15  BLUE LIGHT -1.11          NA
16  BLUE  DARK -4.86  -1.2283951
[etc]

我注意到你的答案在每个序列的开头都有NA,但是你的pcchange函数将它放在最后。如果需要,请修改pcchange

期待使用数据表和基础R(split)的解决方案很快......

答案 2 :(得分:1)

这是一个data.table(开发版本1.9.7)解决方案,与OP的预期结果非常相似。

读取数据

但首先,我们需要为可重现的示例创建数据。来自fread的{​​{1}}功能非常方便。

data.table

按组计算相对变化

library(data.table)

# prepare data, reading first 3 columns
dt <- fread("color  shade   value   pcchange
RED LIGHT   -1.05   N/A
RED LIGHT   -1.37   0.3
RED LIGHT   -0.32   -0.8
RED LIGHT   0.87    -3.7
RED LIGHT   -0.20   -1.2
RED DARK    0.52    -3.6
RED DARK    -0.20   -1.4
RED DARK    0.64    -4.2
RED DARK    1.12    1
RED DARK    4.00    2.6
BLUE    LIGHT   0.93    -0.8
BLUE    LIGHT   0.78    -0.2
BLUE    LIGHT   -1.84   -3.3
BLUE    LIGHT   -0.50   -0.7
BLUE    LIGHT   -1.11   1.2
BLUE    DARK    -4.86   3.4
BLUE    DARK    1.11    -1.2
BLUE    DARK    0.14    -0.9
BLUE    DARK    0.12    -0.1
BLUE    DARK    -1.65   -14.5
GREEN   LIGHT   3.13    -2.9
GREEN   LIGHT   2.65    -0.2
GREEN   LIGHT   -2.36   -1.9
GREEN   LIGHT   -3.11   0.3
GREEN   LIGHT   3.49    -2.1
GREEN   DARK    1.91    -0.5
GREEN   DARK    -1.10   -1.6
GREEN   DARK    -1.93   0.8
GREEN   DARK    1.00    -1.5
GREEN   DARK    -0.23   -1.2",
            drop = "pcchange")

说明

  1. 默认情况下,# Now, compute relative changes by group dt[, pcchange := value/shift(value) - 1, by = "color,shade"] print(dt) color shade value pcchange 1: RED LIGHT -1.05 NA 2: RED LIGHT -1.37 0.3047619 3: RED LIGHT -0.32 -0.7664234 4: RED LIGHT 0.87 -3.7187500 5: RED LIGHT -0.20 -1.2298851 6: RED DARK 0.52 NA 7: RED DARK -0.20 -1.3846154 8: RED DARK 0.64 -4.2000000 9: RED DARK 1.12 0.7500000 10: RED DARK 4.00 2.5714286 11: BLUE LIGHT 0.93 NA 12: BLUE LIGHT 0.78 -0.1612903 13: BLUE LIGHT -1.84 -3.3589744 14: BLUE LIGHT -0.50 -0.7282609 15: BLUE LIGHT -1.11 1.2200000 16: BLUE DARK -4.86 NA 17: BLUE DARK 1.11 -1.2283951 18: BLUE DARK 0.14 -0.8738739 19: BLUE DARK 0.12 -0.1428571 20: BLUE DARK -1.65 -14.7500000 21: GREEN LIGHT 3.13 NA 22: GREEN LIGHT 2.65 -0.1533546 23: GREEN LIGHT -2.36 -1.8905660 24: GREEN LIGHT -3.11 0.3177966 25: GREEN LIGHT 3.49 -2.1221865 26: GREEN DARK 1.91 NA 27: GREEN DARK -1.10 -1.5759162 28: GREEN DARK -1.93 0.7545455 29: GREEN DARK 1.00 -1.5181347 30: GREEN DARK -0.23 -1.2300000 color shade value pcchange 函数将值滞后1,并使用shift填充缺失值。根据OP的要求,这方便地返回NA每组的第一行。

  2. 计算相对变化的公式在数学上等同于较少的输入。

  3. 参数NA告诉by = "color,shade"data.tablecolor进行分组。

  4. 此处需要
  5. shade来显示结果。 print(dt)通过引用创建新变量(不复制整个对象),从而节省时间和内存。