I am looking for a way to write the code below in a more concise manner. I thought about trying df[timemonths] = pd.to_timedelta(df[timemonths])...
but it did not work (arg must be a string, timedelta, list, tuple, 1-d array, or Series).
Appreciate any help. Thanks
timemonths = ['TimeFromPriorRTtoSRS', 'TimetoAcuteG3','TimetoLateG3',
'TimeSRStoLastFUDeath','TimeDiagnosistoLastFUDeath',
'TimetoRecurrence']
monthsec = 2.628e6 # to convert to months
df.TimetoLocalRecurrence = pd.to_timedelta(df.TimetoLocalRecurrence).dt.total_seconds()/monthsec
df.TimeFromPriorRTtoSRS = pd.to_timedelta(df.TimeFromPriorRTtoSRS).dt.total_seconds()/monthsec
df.TimetoAcuteG3 = pd.to_timedelta(df.TimetoAcuteG3).dt.total_seconds()/monthsec
df.TimetoLateG3 = pd.to_timedelta(df.TimetoLateG3).dt.total_seconds()/monthsec
df.TimeSRStoLastFUDeath = pd.to_timedelta(df.TimeSRStoLastFUDeath).dt.total_seconds()/monthsec
df.TimeDiagnosistoLastFUDeath = pd.to_timedelta(df.TimeDiagnosistoLastFUDeath).dt.total_seconds()/monthsec
df.TimetoRecurrence = pd.to_timedelta(df.TimetoRecurrence).dt.total_seconds()/monthsec
You could write your operation as a lambda function and then apply it to the relevant columns:
timemonths = ['TimeFromPriorRTtoSRS', 'TimetoAcuteG3','TimetoLateG3',
'TimeSRStoLastFUDeath','TimeDiagnosistoLastFUDeath',
'TimetoRecurrence']
monthsec = 2.628e6
convert_to_months = lambda x: pd.to_timedelta(x).dt.total_seconds()/monthsec
df[timemonths] = df[timemonths].apply(convert_to_months)
Granted I am kind of guessing here since you haven't provided any example data to work with.
Iterate over vars() of df
Disclaimer: this solution will most likely only work if the df class doesn't have any other variables.
The way this works is by simply moving the repetitive code after the = to a function.
def convert(times):
monthsec = 2.628e6
return {
key: pd.to_timedelta(value).dt.total_seconds()/monthsec
for key, value in times.items()
}
Now we have to apply this function to each variable.
The problem here is that it can be tedious to apply it to each variable individually, so we could use your list timemonths to apply it based on the keys, however, this requires us to create an array of keys manually like so:
timemonths = ['TimeFromPriorRTtoSRS', 'TimetoAcuteG3','TimetoLateG3', 'TimeSRStoLastFUDeath','TimeDiagnosistoLastFUDeath', 'TimetoRecurrence']
And this can be annoying, especially if you add more, or take away some because you have to keep updating this array.
So instead, let's dynamically iterate over every variable in df
for key, value in convert(vars(df)).items():
setattr(df, key, value)
Full Code:
def convert(times):
monthsec = 2.628e6
return {
key: pd.to_timedelta(value).dt.total_seconds()/monthsec
for key, value in times.items()
}
for key, value in convert(vars(df)).items():
setattr(df, key, value)
Sidenote
The reason I am using setattr is because when examining your code, I came to the conclusion that df was most likely a class instance, and as such, properties (by this I mean variables like self.variable = ...) of a class instance must by modified via setattr and not df['variable'] = ....
Related
I am trying to understand a Python for loop that is implemented as below
samples= [(objectinstance.get('sample', record['token'])['timestamp'], record)
for record in objectinstance.scene]
'scene' is a JSON file with list of dictionaries and each dictionary entry refers through values of the token to another JSON file called 'sample' containing 'timestamp' key among other keys.
Although I can roughly understand at a high level, I am not able to decipher how the 'record' is being used here as the output of object's get method. I am thinking this is some sort of list comprehension, but not sure. Can you help understand this and also point me any reference to understand this better? thank you
in non comprehension form it is as below
samples = []
for record in objectinstance.scene:
data = (
objectinstance.get('sample', record['token'])['timestamp'],
record
)
samples.append(data)
objectinstance.get('sample', record['token']) this looks like a method, which took two arguments and return a json/dictionary
{<key1>:<value1>, ... ,'timestmap':<somedata>, ...<keyn>:<valuen>}
and you are saving record with the timestamp value of this call.
it this objectinstance.get can be seen as
class Tmp:
def __init__(self):
self.scene = [{'token': 'a'}, {'token':'b'}, {'token':'c'}]
def get(self, arg1, arg2):
# calculation
return result
objectinstance = Tmp()
samples =[]
for record in objectinstance.scene:
object_instance_data = objectinstance.get('sample', record['token'])
data = object_instance_data['timestamp']
samples.append(data)
so as you can see, there is method in the object class name get, which take 2 arguments, and use them calculation to provide you result in dict/json which as timestamp as key value
Yes, you are right, it is a list comprehension. Schematically, it is something like this:
samples = [(timestamp, item) for item in list_of_dicts]
The result will be a list of touples, where (objectinstance.get('sample', record['token'])['timestamp'] is the first entry and record is the second.
Moreover, objectinstance.get('key', default) gets 'key' from a dict, if not present returns the default value, cf. documentation at python.org. The result of the get method seems to be a dict as well, from which the value of key ['timestamp'] is retrieved.
I created multiply arrays and want to append something to them, but the user should choose which array he want append it to.
So to clarify what I mean: (The code down under is wrong, but I do not know how I could write it.)
x = []
y = []
def test(pName):
%s.append(1) %pName
test(y)
Edit:
#Jim Fasarakis-Hilliard
I am trying to program in PyGame.
Therefor I have to initalise all the images I want to use.
To not expand it, I wanted to create a function where you can easily append to any array you want to, so I do not have to create a new function every time I want to initalise new pictures.
My code looks like this atm.:
def loadImages(self,pName,pAnz,pScaleX,pScaleY):
for i in range(0,pAnz):
tux = pygame.transform.scale(pygame.image.load('./images/%s.png'),(pScaleX,pScaleY) % pName)
self.%s.append(tux) %pName
length_array = len(self.%s) %pName
return length_array
You could use globals, pass a string of the variable name to the function:
def test(pName):
globals()[pName].append(1)
test('y')
this, of course, relies on the name existing in the global scope.
You could put the array's in a dictionary. Assuming that there is a fixed number of arrays, the code would look something like this:
arrays = {}
arrays['x'] = []
arrays['y'] = []
def test(pName):
arrays[pName].append(1)
test('y')
You will want to check the user input, as a pName which is not a key in the dictionary will throw a key exception. If you want the arrays to be dynamic, you could do something like this:
arrays={}
def test(pName):
if pName not in arrays.keys():
arrays[pName]=[]
arrays[pName].append(1)
test('y')
If all you want is to be able to save your objects into different "namespaces", you can use dictionaries:
lists = {
"x": [],
"y": []
}
def test(pName):
lists[pName].append(1)
test("y")
Cleaner and easier to understand than using globals or similars IMHO.
I have a class which looks like this.
class CharInStageList(object):
def __init__(self, charid, charname) :
self.charid = charid
self.charname = charname
into this class I would like to add lists that I have.
I know how to do it the normal way
charOne = CharInStageList(1,'Tim')
charTwo = CharInStageList(2,'Struppi')
that's not a problem what I actually want to do is to add them by using a loop.
I get my data in this form
((1,'Tim'),(4,'Struppi'))
or
((1,'Tim'),(4,'Struppi'),(5,'Nami'),(6,'Luffy'))
the amount of characters I have in the scene is always different.
what I imagined would be a loop like this
charlist = ((1,'Tim'),(4,'Struppi'))
for char in charlist
objname = CharInStageList(char[0],char[1])
something like this
I want the objname to change by itself for every object I add to the class.
How can I get this effect?
I can only use python 2.6.6 for this since it's the maya 2013 python
Edit:
Thx #silas-ray #chepner #theodox I looked into Dicts a bit more and that's pretty much what I need
I use a modified version of #chepner method on it.
object_dict = dict( (y, CharInStageList(x,y)) for x,y in data )
Works like a charm
My testcode looks like this
import maya.cmds as cmds
dicttest = {}
def getdata ():
global dicttest
data = ((1,'Tim'),(4,'Struppi'),(5,'Nami'),(6,'Luffy'))
dicttest = dict( (y,(x,y)) for x,y in data )
getdata()
def printtest() :
for char in dicttest:
print dicttest[char]
printtest()
dicttest.clear()
I would have liked to comment in your answers with code examples but I can't get that to work there.
Objects are not added to a class. Instead, you can create a list of objects which are all instances of the same class, using a list comprehension and taking advantage of the *args syntax:
data = ((1,'Tim'),(4,'Struppi'),(5,'Nami'),(6,'Luffy'))
object_list = [ CharInStageList(*x) for x in data ]
Perhaps you want a dictionary instead:
object_dict = dict( (y, CharInStageList(x,y)) for x,y in data )
(Note that CharInStageList is a poor name for the class, because it's not a list; it encapsulates a single character.)
If you really want CharInStateList to be a collection of characters, try something like this, which is just a thin wrapper around a dictionary:
# Your former CharInStageList
class Character(object):
def __init__(self, charid, charname) :
self.charid = charid
self.charname = char name
class OnStageCharacters(object):
def __init__(self):
self.characters = dict()
# Index on-stage characters using their charid
def add(self, character):
self.characters[character.charid] = character
on_stage = OnStageCharacters()
for id, name in data:
on_stage.add( Character(id, name) )
You can't (at least not without hacking at locals/globals, which is generally not a good idea) change the name you are assigning to dynamically like that. You can, however, insert them in to a dictionary where the keys are your dynamically generated names.
characters = {}
for char_data in char_list:
characters[char_data[1]] = CharInStageList(*char_data)
Though if all your character objects are storing is name and id, it might make more sense to simplify the whole thing and just create mapping dictionaries rather than objects.
character_names_by_id = dict(char_data)
character_ids_by_name = dict((name, id) for id, name in char_data)
#chepner's answer is a great one if you can use the *args form to fill out your class instances.
If you're just asking the most efficient way to do this from a loop, remember you can have iterate over the parts of a tuple together:
data = ((1,'Tim'),(4,'Struppi'),(5,'Nami'),(6,'Luffy'))
class_data = (CharInStageList(id, name) for id, name in data) # "for id, name" will yield two vals
You can also use map, which is very common for doing bulk data translations. A common way to do it is with a lambda so you can write it clearly:
to_char = lambda k: CharInStageList(k[0], k[1])
class_data = map(to_char, data)
If you're doing something as simple as your example, you might not want to bother with your own class. the namedtuple is a great data structure for creating tuples that are easy to work with. It also means you can use positional or named args interchangeably, just as in #chepner's *args version:
StageListChar = namedtuple('CharInStageList', ['id', 'name'])
class_data = map(StageListChar , data)
I have code along these lines:
classinstance.col1 = queryresult.col1
classinstance.col2 = queryresult.col2
classinstance.col3 = queryresult.col3
classinstance.col4 = queryresult.col4
Which adds variables to the classinstance and assigns the values of the queryresult column with the same name as the variable.
I am hoping to make my code a little more flexible, and not need to identify the columns by name. To this end, I was wondering if there was some way to do a loop over all the columns, rather than handle each one individually. Something like this (This is psuedocode rather than actual code, since I'm not sure what it should actually look like):
for each var in vars(queryresult):
classinstance.(var.name) = var.value
Is this possible? What does it require? Is there some fundamental misunderstanding on my part?
I'm assuming there's only one row in the result for the following example (built with help from comments here). The key component here is zip(row.cursor_description, row) used to get column names from pyodbc.Row object.
# convert row to an object, assuming row variable contains query result
rowdict = { key[0]:value for (key, value) in zip(row.cursor_description, row) }
# loop through keys (equivalent to column names) and set class instance values
# assumes existing instance of class is variable classinstance
for column in rowdict.keys():
classinstance[column] = rowdict[column]
I am writing a function that will take a parameter and, among other things, make a dictionary. I would like the dictionary's name to be based off the name of the input file. Say ht input file is input.xml , i would like the name of the dictionary to be input. Ideally I would use something like this:
def function(input):
for x in y: list(get value)
input[:4][key] = [value]
I am wondering if you know a better way to do this but what i am using now is an extra name in the function:
def function(input, dictname):
for x in y: list(get value)
dictname[key] = [value]
right now I am simply adding a second name to my function but am wondering if there is a way to do this to require fewer inputs.
Edit
I am including a longer version of the function I am using so you guys can get the context. This uses a BioPython module to iterate through an XML file of hits. I am using [temp] to hold the hits for each query and then making a dictionary of for each set of query/hits. I would like this dictionary to be named the same as my input file.
from Bio.Blast import NCBIXML
def make_blast_dictionary(blastxml, maxhits, blastdict):
temp=[]
for record in NCBIXML.parse(open(blastxml):
for number, align in enumerate(record.alignments):
if number == int(maxhits): break
temp.append(str(align.title).split("|")[1])
blastdict[str(record.query_id)] = [temp]
The thing about named variables is that you can call them whatever you like. It's best to name them specific to the context you're using them with.
It would be a better move to simply return a dictionary from your method, instead.
The other respondents are legitimately concerned about why you would want to do this or whether you should do this. That being said, here is how you could do it:
import os.path
def function(filename):
d = {'red': 10, 'blue': 20}
name, ext = os.path.splitext(filename)
globals()[name] = d
function('input.xml')
print input
def make_name(input):
return = input.split('.')[0]
def function(input):
"""Note: this function is incomplete and assumes additional parameters are in your original script
"""
for x in y: list(get value)
dict_name[key] = [value]
return dict_name
def make_dict(input):
dict_name = make_name(input)
dict_name = {}
dict_name = function(input)
return dict_name
Is this what you need?