Stata keeping even years - stata

If I have data for every year of 1932 to 2012, how do I keep only the even number years from 1946 to 2012 in Stata? I've tried the following:
keep if year == 1946(2)2012
But it doesn't seem to help.

The error you receive with your code is: unknown function 1946(). Stata thinks 1946 is a function because it is followed by an opening parenthesis. It is expecting an expression and functions can be part of an expression. However, you are giving it a numlist (help numlist), and that is not allowed.
An example that works:
clear
set more off
*----- example data -----
set obs 81
egen year = seq(), from(1932) to(2012)
list
*----- what you want -----
keep if mod(year,2) == 0 & year >= 1946
list
Note I used a (legal) function, namely, the modulo function.

Related

How to rank without skipping values? [duplicate]

I have some data in Stata which look like the first two columns of:
group_id var_to_rank desired_rank
____________________________________
1 10 1
1 20 2
1 30 3
1 40 4
2 10 1
2 20 2
2 20 2
2 30 3
I'd like to create a rank of each observation within group (group_id) according to one variable (var_to_rank). Usually, for this purpose I used:
gen id = _n
However some of my observations (group_id = 2 in my small example) have the same values of ranking variable and this approach doesn't work.
I have also tried using:
egen rank
command with different options, but cannot make my rank variables make to look like desired_rank.
Could you point me to a solution to this problem?
The following works for me:
bysort group_id: egen desired_rank=rank(var_to_rank)
I'd say this question is posed the wrong way round for best understanding. The aim is to group observations, those with the lowest value all being assigned a grade 1, the next lowest being all assigned 2 and so forth. This isn't ranking in most senses that I have seen discussed, but Stata's egen, rank() does get you part of the way.
But the direct way, which was mentioned in the Statalist thread cited elewhere in this thread (start here) is simpler in spirit than any solution quoted:
bysort group_id (var_to_rank): gen desired_rank = sum(var_to_rank != var_to_rank[_n-1])
Once data are sorted on var_to_rank then when values differ from previous values at the start of each block of distinct values a value of 1 is the result of var_to_rank != var_to_rank[_n-1]; otherwise 0 is the result. Summing those 1s and 0s cumulatively gives the desired variable. The prefix command bysort does the sorting required and ensures that this is all done separately within the groups defined by group_id. No need for egen at all (a command that many people who only use Stata occasionally often find bizarre).
Declaration of interest: The Statalist thread cited shows that when asked a similar question I too did not think of this solution in one.
Stumbled upon such solution on the Statalist:
bysort group_id (var_to_rank) : gen rank = var_to_rank != var_to_rank[_n-1]
by group_id : replace rank = sum(rank)
Seems to sort out this issue.
#radek: you surely got it sorted out in the meantime ... but this would have been an easy (though not very elegant) solution:
bysort group_id: egen desired_rank_HELP =rank(var_to_rank), field
egen desired_rank =group(grup_id desired_rank_HELP)
drop desired_rank_HELP
Way too much work. Easy and elegant. Try this one.
gen desired_rank=int(var_to_rank/10)
try this command, it works for me so well: egen newid=group(oldid)

Generating a composite date variable

I want to generate a variable month that has the month and year together as 2013M01.
Below is a sample of my data:
clear
input expected_arrival_month year
1 2013
2 2014
3 2015
4 2016
5 2017
6 2018
end
I tried the following command:
generate month = .
replace month = 2013M01 if expected_arrival_month == 1 & year == 2013
However, I received the error:
2013M01 invalid name
r(198)
How can I get the desired output?
For essentially all Stata purposes a numeric monthly date variable is better than anything hand- or homemade (and certainly than dates held as string variables). You can get such variables to appear as you ask. You certainly do not need to calculate individual values directly. Although this code is for a minimal dataset it will apply to all values in numeric variables as you describe. See help datetime for invaluable (and unavoidable) information.
clear
set obs 1
generate year = 2013
generate arrival_month = 1
generate wanted = ym(year, arrival_month)
format wanted %tmCCYY!MNN
list
+---------------------------+
| year arriva~h wanted |
|---------------------------|
1. | 2013 1 2013M01 |
+---------------------------+
(As commented, you should provide example data directly and in a way that makes variable types clear. If one or both variables are really string, apply destring first or use monthly().)
The issue here is in dealing with string rather than numeric variables. Given that the variable you are generating is a string variable, the contents of the variable must be enclosed in quotation marks:
generate month = "2013M01" if expected_arrival_month == 1 & year == 2013
There would also be other more efficient ways to deal with this generation, for example using Stata's egen command (and concat), or datetime functions as indicated in another response.

Stata: How to modify some values in a string variable but keep original values?

I am working with a very large dataset (1 million obs.).
I have a string date that looks like this
key seq startdate (string)
AD07 1 August 2011
AD07 2 June 2011
AD07 3 February 2004
AD07 4 November 2004
AD07 5 2001
AD07 6 January 1998
AD5c23 1 January 2014
AD5c235 2 February 2014
AD5c235 3 2014
These are self-reported employment dates.
Some did not report the month at which they started.
But I would like to replace for AD07 the date “2001” to “January 2001”. Hence I cannot simply replace it because I would like to keep the original years but add the month in the string variable.
I started with:
levelsof start if start<="2016", local(levels)
which gives me all the years without the month from 1900 to 2016.
Now I would like to add "January" for the years without the month and keep original years.
How should I do that without using replace for every year? foreach loop?
You have a serious data quality problem if people are claiming to have started work in 1900 and every year since then! Even considering early employment starts and delayed retirement, that implies people older than the oldest established age.
Also, imputing "January" will impart bias as almost all job durations will be longer than they would have been. Real January starts will be correct, but no others: "June" or "July" or random months would make more obvious statistical sense.
That said, there is no loop needed here. You're asking for one line, say
replace startdate = "January " + startdate if length(trim(date)) == 4
or
replace startdate = "January " + startdate if real(startdate) < .
-- assuming a follow-up in converting to numeric dates. The logic there is that all year-only dates trim down to 4 characters, or (better) that feeding month names to real() will yield missings.
That said in turn, creating a new variable is better practice than over-writing one. Also, consider throwing away the month detail. Is it needed?
EDIT
You may have another problem if there are people with two or more jobs in the same year without month specifications. You don't want to impute all months in question as "January". You can check for such observations by
gen byte incomplete = real(startdate) < .
gen year = substr(trim(startdate), -4, 4)
bysort key year incomplete : gen byte multiplebad = incomplete & _N > 1

Difference between dropping years and "if Year > 2005"

I have a dataset of the top management teams of US banks from 2005 - 2015.
Now I want to generate a change-variable if a TMT composition changed between 2006 and 2009.
So first I used:
drop if Year > 2009
drop if Year < 2006
by id (id), sort: gen changed = (DirectorID[1] != DirectorID[_N])
and afterwards I used
by id (id), sort: gen changed = (DirectorID[1] != DirectorID[_N]) if Year < 2010 & Year > 2005
However there is a difference in output between two variables:
247 cases of "No change" and 853 cases of "Change" in the first and 116 cases of "No change" and the rest as "Changed" in the second variable
Could anyone clarify what the differences between these two commands are in Stata?
There are a couple reasons you may be seeing a different count of changes to the dataset. The data is most likely sorted differently for these two calls. The (id) parts have no effect here because you are already sorting by id. What you likely want to do is residually sort by year. So, bysort id (Year) - this way the dataset will be in the same order for each command you type. In the second command, the if clause is going to set the variable changed to missing for observations outside of the year range, but those observations are still being included in the calculation. You could create a new variable to flag the years of interest, and then add that new variable to the bysort call.
Lastly, you need to decide whether you only want to look at changes year-over-year (the value of the changed could vary by year within id), or have the value of changed reflect whether there were any changes in DirectorID over the entire time frame of interest (the value of changed would be constant within id).
Here's a toy example illustrating the difference. Essentially, when you drop the data, the last and the first observation could be the same, but in general you will have less data to compare the first and last observation since much of the data will be gone. When you use if, then the data is still there, even though the calculation is restricted to the middle observation by the if:
. clear
. input id year director_id
id year directo~d
1. 1 2016 10
2. 1 2017 20
3. 1 2018 30
4. end
.
. bys id (year): gen changed = (director_id[1] != director_id[_N]) if year < 2018 & year > 2016
(2 missing values generated)
. list, clean noobs
id year direct~d changed
1 2016 10 .
1 2017 20 1
1 2018 30 .
.
. drop if inlist(year, 2016,2018)
(2 observations deleted)
. bys id (year): gen changed2 = (director_id[1] != director_id[_N]) if year < 2018 & year > 2016
. list, clean noobs
id year direct~d changed changed2
1 2017 20 1 0
I added a sort by year since that seems in the spirit of your exercise.

Dropping observations in panel data

I have a panel data set over three years 87 90 93 for 50 different states. For my variable of interest, exec, I want to drop all entries for the state where exec == 0 in each of the years and only if it equals zero in each of the years.
I've been trying to write some sort of for loop but have been unsuccessful so far.
No loop is needed. No extra variable is needed.
bysort state (exec) : drop if exec[1] == 0 & exec[_N] == 0
will drop observations for a state if and only if all values of exec are 0.
Something like this will work assuming exec can't be negative:
webuse airacc
bysort airline (time): egen tot = total(inprog)
drop if tot==0
This will drop airlines where the sum of inprog across time for each state is zero, treating missings as zeros.
egen and egenmore will save you from getting loopy.